NT4/private/ole32/com/remote/service.hxx
2020-09-30 17:12:29 +02:00

679 lines
19 KiB
C++

//+-------------------------------------------------------------------
//
// File: service.hxx
//
// Contents: Rpc service class definition
//
// Classes: CRpcService - Rpc service object
//
// Functions:
//
// History: 23-Nov-92 Rickhi Created
// 31-Dec-93 ErikGav Chicago port
//
// Notes: there are two kinds of service objects, local and remote.
//
// only one local service object exists. it registers the
// IChannelService interface with Rpc and spawns a thread to
// listen for incomming requests.
//
// there is one remote service object for each processe that
// we are communicating with. they talk to the other processes
// via Rpc calls on IChannelService to open and close context
// handles to objects within a process.
//
// each service object has a chain of channels. the service
// that a channel is chained off indicates which process
// the channel talks to.
//
//--------------------------------------------------------------------
#ifndef __SERVICE__
#define __SERVICE__
// forward declarations for the classes defined herein
class CRpcService;
class CSrvList;
class CRpcChannelBuffer;
// global ptrs to the service object list & local service object
#ifndef _CHICAGO_
extern CSrvList sg_SrvList;
#endif
#include <olesem.hxx> // COleCommonMutexSem, COleStaticLock
#include <sem.hxx> // CMutexSem, CLock
#include <objerror.h> // Rpc errors
#include <dd.hxx> // CListEntry
#include <thread.hxx> // CThread
#include <iface.h> // PPOBJCTX
#include <endpnt.hxx> // CEndPoint, SEndPoint
#include <rpcbind.hxx> // CRpcBindHandle
#include <olerem.h>
#include <islocalp.hxx> // For telling if service is local
extern COleStaticMutexSem sg_SrvListLock;
// Prototypes.
SCODE StopListen( void );
// Service object state. The first three bytes are the string "svc".
typedef enum EServiceState
{
client_ss = 0x73766300,
server_ss,
disconnected_ss,
deleted_ss
} EServiceState;
// sleep timeout before rety when receiving a SERVER_TOO_BUSY error.
// time is in milliseconds.
#define SERVER_BUSY_SLEEP_MS 50
//+-------------------------------------------------------------------------
//
// Class: CRpcService (svc)
//
// Purpose: Rpc service object. This maintains the endpoint and Rpc
// binding handle to an Rpc service. Note that there is an
// Rpc service for the local process as well, though we do
// not bind to it.
//
// Notes: The two kinds of service objects are:
// Local (sg_pLocalSrv and in sg_SrvList).
// Created at startup; logically, sg_SrvList owns
// the ref count that keeps it alive; released at shutdown
// State:
// _CEp only available if listening
// _hRpc == NULL (never connected to a server)
// _pContext == NULL ( " " " " " )
// _eState == client_ss
//
// Remote (only in sg_SrvList)
// Created each time we contact a new process (which is
// identified by its string binding). When acting as a
// client, the channel keeps an addref'd pointer; that
// pointer is released when the channel is disconnected or
// destroyed. When acting as a server (possibly the same
// instance doing both), the existance of the context handle
// keeps a ref; i.e., when the context handle is freed
// (via the rundown), the service object is released.
// State:
// _CEp passed in at creation
// _hRpc set when connected to a server
// _pContext set when received ctx hdl from srv
// (it is this that logically holds the service object
// in the server process alive)
// _eState == client_ss
//
// Disconnected_ss is used to mark a Remote service object that
// has been disconnect (received a rundown from its client or
// was connected at the time of CoUnintialize); in this case,
// the state associated with the server, if any, is also
// cleared.
// State:
// _CEp meaningless, but present
// _hRpc == NULL
// _pContext == NULL
// _eState == disconnected_ss
//
// Server_ss is not used currently.
//
// History: 23-Nov-92 Rickhi Created
// 19-Jan-94 Alexmit Moved context handles here
// 20-Jan-94 Craigwi Tried to document better and add asserts
//
//--------------------------------------------------------------------------
class CRpcService : public CListEntry
{
friend CSrvList;
friend CRpcService *LocalService (void);
friend void SetLocalService ( CRpcService * );
friend BOOL IsInLocalProcess(CEndPoint *pcep);
public:
CRpcService(SEndPoint *pSEp, HRESULT &hr);
~CRpcService(void);
// used by compobj to start the Rpc server if not already done
SCODE StartListen(void);
// used by channel code to start/stop the Rpc server
SCODE Listen(BOOL fListenNow = FALSE); // do RpcServerListen
SCODE RegisterProtseq(WCHAR *pwszProtseq);
SCODE RemoteRegisterProtseq(WCHAR *pwszProtseq);
// IChannelServer interface used by channels
SCODE CheckContextHdl( HAPT server );
POBJCTX GetContextHdl( void );
SCODE SetContextHdl( POBJCTX );
SCODE GetChannelId( OID ObjectId, DWORD dwFlags, HAPT server,
DWORD *dwChannelId );
SCODE ReleaseChannel(CRpcChannelBuffer *pChannel,
BOOL fAsyncRelease);
SCODE TransferMarshalConnection(DWORD dwChannelID);
SCODE AddMarshalConnection(DWORD dwChannelID, HAPT hapt, REFOID roid);
SCODE RemoveMarshalConnection(DWORD dwChannelID);
SCODE QueryObjectInterface(DWORD dwChannelID, REFIID riid);
SCODE LockObjectConnection(DWORD dwChannelID, BOOL fLock,
BOOL fLastReleaseCloses);
handle_t GetRpcHdl(void);
BOOL IsConnected(void);
void Disconnect(void);
// used by marshalling/unmarshalling code
void GetDestCtx(DWORD *pdwDestCtx, void **);
BOOL IsEqualEp(SEndPoint *pEp);
SEndPoint *GetSEp(void);
SEndPoint *CopySEp(void);
ULONG GetSEpSize(void);
LPWSTR GetStringBinding(void);
BOOL GetActiveProtseq(WCHAR **ppwszProtseq);
void SetActiveProtseq(void);
BOOL DiffMachine(void);
ULONG AddRef(void);
ULONG Release(void);
BOOL IsServiceListen() { return _fListening; }
void SetServiceListen(BOOL fListen) {_fListening = fListen; }
#ifdef _CHICAGO_
BOOL NotifyServerOfSEp(void);
void SetSEp(SEndPoint *pSEp)
{
_CEp.SetNewSEp(pSEp);
}
#endif
#if DBG == 1
void AssertValid();
#else
void AssertValid() { }
#endif
private:
SCODE Bind(void); // bind to the appropriate endpoint
SCODE DoChannelOperation(DWORD dwChannelID, DWORD chop,
HAPT hapt, const IID *piid);
CEndPoint _CEp; // Rpc end point
CRpcBindHandle _hRpc; // Rpc binding handle
CMutexSem _mxs; // mutex semaphore
POBJCTX _pContext; // Context Handle
EServiceState _eState; // State of object
ULONG _ulRefCnt; // Reference count
BOOL _fThisProcess; // Ep is in this process
BOOL _fListenNow;
#ifdef _CHICAGO_
BOOL _fListening;
#else
static BOOL _fListening;
static CRpcService *sg_pLocalSrv;
#endif
};
//+-------------------------------------------------------------------
//
// Member: LocalService, public
//
// Synopsis: Get the local service object. For NT each process has a
// service object. For Chicago each thread has a service
// object.
//
// History: 3-Aug-94 AlexMit Created
//
//--------------------------------------------------------------------
inline CRpcService *LocalService()
{
#ifdef _CHICAGO_
return (CRpcService *) TLSGetService();
#else
return CRpcService::sg_pLocalSrv;
#endif
}
//+-------------------------------------------------------------------
//
// Member: SetLocalService, public
//
// Synopsis: Saves a service pointer in the service objects global
//
// History: 3-Aug-94 AlexMit Created
//
//--------------------------------------------------------------------
inline void SetLocalService( CRpcService *pService )
{
#ifdef _CHICAGO_
TLSSetService(pService);
#else
CRpcService::sg_pLocalSrv = pService;
#endif
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::StartListen, public
//
// Synopsis: starts the Rpc service listening if it is not
// doing so already.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline SCODE CRpcService::StartListen(void)
{
Win4Assert( this == LocalService() );
AssertValid();
if (!IsServiceListen())
{
// not already listening, start it listening now
return Listen();
}
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::GetRpcHdl, public
//
// Synopsis: returns the Rpc handle for the remote Rpc service. This
// is used when an Rpc call is made to the remote service.
// We dont bind until someone asks for the handle.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline handle_t CRpcService::GetRpcHdl(void)
{
AssertValid();
if (_hRpc.Handle() == NULL)
{
Bind(); // have not bound yet, do it now
}
return _hRpc.Handle();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::GetContextHdl, public
//
// Synopsis: returns the Rpc context for the remote Rpc service. This
// is used when an Rpc call is made to the remote service.
//
// History: 29-Nov-93 AlexMit Created
//
//--------------------------------------------------------------------
inline POBJCTX CRpcService::GetContextHdl(void)
{
AssertValid();
CLock lck(_mxs);
if (_eState == disconnected_ss)
return NULL;
return _pContext;
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::SetContextHdl, public
//
// Synopsis: Set the context handle if it has not yet been set.
//
// History: 2-Aug-94 AlexMit Created
//
//--------------------------------------------------------------------
inline SCODE CRpcService::SetContextHdl(POBJCTX pContext)
{
AssertValid();
CLock lck(_mxs);
if (_pContext == NULL)
{
_pContext = pContext;
return S_OK;
}
else
return E_FAIL;
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::IsEqualEp, public
//
// Synopsis: returns TRUE if the given EndPoint matches the one used
// by this service object.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline BOOL CRpcService::IsEqualEp(SEndPoint *pSEp)
{
Win4Assert(pSEp && "Invalid parameter");
AssertValid();
return _CEp.IsEqual(pSEp);
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::GetSEpSize, public
//
// Synopsis: returns the size of the EndPoint structure stored in
// this service object. This is used to calculate the
// size of buffer needed when marshalling an interface.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline ULONG CRpcService::GetSEpSize(void)
{
AssertValid();
if (!IsServiceListen() && this == LocalService())
{
// this is the local service object, and we need to start the
// server listening so we can marshal this interface
if (StartListen() != S_OK)
return 0;
}
return _CEp.GetSEpSize();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::GetSEp, public
//
// Synopsis: returns the EndPoint structure stored in this service
// object.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline SEndPoint *CRpcService::GetSEp(void)
{
AssertValid();
if (!IsServiceListen() && this == LocalService())
{
// this is the local service object, and we need to start the
// server listening so we can marshal this interface
StartListen();
}
return _CEp.GetSEp();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::CopySEp, public
//
// Synopsis: returns a copy of the EndPoint structure stored in
// this service object.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline SEndPoint * CRpcService::CopySEp(void)
{
AssertValid();
CLock lck(_mxs);
if (!IsServiceListen() && this == LocalService())
{
// this is the local service object, and we need to start the
// server listening so we can marshal this interface
if (StartListen() != S_OK)
{
return NULL;
}
}
return _CEp.CopySEp();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::DiffMachine
//
// Synopsis: asks the endpoint whether or not it refers to this machine
//
// History: 23-Nov-93 Rickhi Created
// 24-Nov-93 AlexMit Implemented
//
//--------------------------------------------------------------------
inline BOOL CRpcService::DiffMachine()
{
AssertValid();
return _CEp.DiffMachine();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::GetStringBinding
//
// Synopsis: returns the most favoured string binding for this
// service object
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline LPWSTR CRpcService::GetStringBinding(void)
{
AssertValid();
if (!IsServiceListen() && this == LocalService())
{
// this is the local service object, and we need to start the
// server listening so we can marshal this interface
if (StartListen() != S_OK)
return NULL;
}
return _CEp.GetStringBinding();
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::IsConnected
//
// Synopsis: quickly determines if this service is probably connected
// to its twin in the other process. The negative answer
// is definitive (i.e., we know when we are definitely not
// connected). This method is really only useful if the
// service object has ever acted as a server (i.e., gave
// out a context handle). This will be true in lots and lots
// of cases (e.g., ole embeddings).
//
// History: 08-Feb-94 CraigWi Created
//
//--------------------------------------------------------------------
inline BOOL CRpcService::IsConnected()
{
AssertValid();
// we can't check _hRpc or _pContext because they are not set
// in a service object which is servicing a remote process and which
// is not acting as a client of that process.
return _eState != disconnected_ss;
}
//+-------------------------------------------------------------------
//
// Member: CRpcService::Get/SetActiveProtseq, public
//
// Synopsis: returns the protocol sequence we are using to talk to
// a remote server. This is needed when we marshal an interface
// to pass back to the server to make sure we have registered
// that protocol sequence with Rpc.
//
// History: 23-Nov-93 Rickhi Created
//
//--------------------------------------------------------------------
inline BOOL CRpcService::GetActiveProtseq(WCHAR **ppwszProtseq)
{
AssertValid();
return _CEp.GetActiveProtseq(ppwszProtseq);
}
inline void CRpcService::SetActiveProtseq(void)
{
AssertValid();
_CEp.SetActiveProtseq();
}
//+-------------------------------------------------------------------------
//
// Class: CSrvListBase ()
//
// Purpose: Base class for Head list of Rpc service objects
//
// Interface: first -- get first item in the list.
// next -- get next item in the list.
//
// History: 23-Nov-92 Rickhi Created
//
// Notes: See dd.hxx for details of this macro.
//
//--------------------------------------------------------------------------
DERIVED_LIST_HEAD(CSrvListBase, CRpcService);
//+-------------------------------------------------------------------------
//
// Class: CSrvList ()
//
// Purpose: Head list of Rpc service objects
//
// Interface: AddToList -- add an entry to a list of remote handlers
//
// History: 23-Nov-92 Rickhi Created
//
// Notes: This class adds a few methods to its macro defined base
// class. It requires a destructor so that it can clean up any
// remaining entries in the base list BEFORE the destructor
// for the mutex is called.
//
//--------------------------------------------------------------------------
class CSrvList
{
public:
CSrvList(void) {}
~CSrvList();
CRpcService *FindSRVFromEP(SEndPoint *pSEp, BOOL fCreate);
CRpcService *FindSRVFromContext(POBJCTX hObjCtx, BOOL fRemove);
void RemoveFromList(CRpcService *pSrv);
void Cleanup(void);
private:
CSrvListBase _List;
};
//+-------------------------------------------------------------------
//
// Member: CSrvList::RemoveFromList
//
// Synopsis: removes an Rpc service object from the list of service
// objects. called by the service objects destructors to
// remove themselves from the list in a thread safe way.
//
// History: 23-Nov-93 Rickhi Created
//
// Notes: Thread Safe
//
//--------------------------------------------------------------------
inline void CSrvList::RemoveFromList(CRpcService *pSRVToRemove)
{
// validate input parms
Win4Assert(pSRVToRemove);
if (pSRVToRemove->connected())
{
COleStaticLock lck(sg_SrvListLock);
pSRVToRemove->delete_self();
}
}
//+-------------------------------------------------------------------
//
// Function: FindSRVFromEP
//
// Synopsis: Calls FindSRVFromEP on the service list for the current
// thread.
//
// History: 6 Sept 94 AlexMit Created
//
//--------------------------------------------------------------------
#ifndef _CHICAGO_
inline CRpcService *FindSRVFromEP(SEndPoint *pSEp, BOOL fCreate)
{
return sg_SrvList.FindSRVFromEP( pSEp, fCreate );
}
#else
inline CRpcService *FindSRVFromEP(SEndPoint *pSEp, BOOL fCreate)
{
CSrvList *pSrvList = (CSrvList *) TLSGetServiceList();
if (pSrvList != NULL)
return pSrvList->FindSRVFromEP( pSEp, fCreate );
else
return NULL;
}
#endif
//+-------------------------------------------------------------------
//
// Function: FindSRVFromContext
//
// Synopsis: Calls FindSRVFromContext on the service list for the current
// thread.
//
// History: 6 Sept 94 AlexMit Created
//
//--------------------------------------------------------------------
#ifndef _CHICAGO_
inline CRpcService *FindSRVFromContext(POBJCTX hObjCtx, BOOL fRemove)
{
return sg_SrvList.FindSRVFromContext( hObjCtx, fRemove );
}
#else
inline CRpcService *FindSRVFromContext(POBJCTX hObjCtx, BOOL fRemove)
{
CSrvList *pSrvList = (CSrvList *) TLSGetServiceList();
if (pSrvList != NULL)
return pSrvList->FindSRVFromContext( hObjCtx, fRemove );
else
return NULL;
}
#endif
inline BOOL IsThreadListening(void)
{
return LocalService()->IsServiceListen();
}
inline void SetThreadListening(BOOL fListen)
{
LocalService()->SetServiceListen(fListen);
}
#endif // __SERVICE__