1535 lines
35 KiB
C++
1535 lines
35 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1992 - 1999
|
||
|
||
Module Name:
|
||
|
||
lpcsvr.hxx
|
||
|
||
Abstract:
|
||
|
||
Class definition for the server side of RPC on LPC protocol
|
||
engine.
|
||
|
||
Author:
|
||
|
||
Steven Zeck (stevez) 12/17/91 (spcsvr.hxx)
|
||
|
||
Revision History:
|
||
|
||
16-Dec-1992 mikemon
|
||
|
||
Rewrote the majority of the code and added comments.
|
||
|
||
-- mazharm code fork from spcsvr.hxx
|
||
|
||
05/13/96 mazharm merged WMSG/LRPC into a common protocol
|
||
9/22/97 no more WMSG
|
||
|
||
Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
|
||
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
|
||
--*/
|
||
|
||
#ifndef __LPCSVR_HXX__
|
||
#define __LPCSVR_HXX__
|
||
|
||
class LRPC_SASSOCIATION;
|
||
class LRPC_CASSOCIATION;
|
||
class LRPC_ADDRESS;
|
||
class LRPC_SERVER ;
|
||
class LRPC_SCALL ;
|
||
class LRPC_SERVER ;
|
||
class LRPC_CASSOCIATION_DICT;
|
||
|
||
|
||
// the next four are protected by the LrpcMutex
|
||
extern LRPC_CASSOCIATION_DICT * LrpcAssociationDict;
|
||
|
||
// the number of associations in the LrpcAssociationDict
|
||
// dictionary that have their fAssociationLingered member set
|
||
extern long LrpcLingeredAssociations;
|
||
|
||
// the total number of LRPC associations destroyed in this process
|
||
// this is used to dynamically turn on garbage collection if
|
||
// necessary
|
||
extern ULONG LrpcDestroyedAssociations;
|
||
|
||
// each time the number of destroyed associations is divisible by
|
||
// NumberOfLrpcDestroyedAssociationsToSample, we check this timestamp
|
||
// and compare it to the current. If the difference is more than
|
||
// DestroyedLrpcAssociationBatchThreshold, we will turn on
|
||
// garbage collection automatically
|
||
extern ULARGE_INTEGER LastDestroyedAssociationsBatchTimestamp;
|
||
|
||
const ULONG NumberOfLrpcDestroyedAssociationsToSample = 128;
|
||
|
||
// in 100 nano-second intervals, this constant is 1 second
|
||
const DWORD DestroyedLrpcAssociationBatchThreshold = 1000 * 10 * 1000;
|
||
|
||
// 4 is an arbitrary number designed to ensure reasonably sized cache
|
||
// Feel free to change it if there is a perf reason for that
|
||
const long MaxLrpcLingeredAssociations = 4;
|
||
extern LRPC_SERVER *GlobalLrpcServer;
|
||
|
||
RPC_STATUS
|
||
InitializeLrpcServer(
|
||
) ;
|
||
|
||
extern RPC_STATUS
|
||
InitializeLrpcIfNecessary(
|
||
) ;
|
||
|
||
#define LrpcSetEndpoint(Endpoint) (\
|
||
GlobalLrpcServer->SetEndpoint(Endpoint))
|
||
#define LrpcGetEndpoint(Endpoint) (\
|
||
GlobalLrpcServer->GetEndpoint(Endpoint))
|
||
|
||
NEW_SDICT(LRPC_SASSOCIATION);
|
||
NEW_SDICT(LRPC_SCALL) ;
|
||
|
||
#define SERVER_KEY_MASK 0x8000
|
||
#define SERVERKEY(_x_) ((_x_) & 0x80000000)
|
||
|
||
#define CLEANUP goto cleanup
|
||
|
||
#define COPYMSG(LrpcCopy, LrpcMessage) \
|
||
LrpcCopy->LpcHeader.ClientId = LrpcMessage->LpcHeader.ClientId ; \
|
||
LrpcCopy->LpcHeader.CallbackId = LrpcMessage->LpcHeader.CallbackId ; \
|
||
LrpcCopy->LpcHeader.MessageId = LrpcMessage->LpcHeader.MessageId ; \
|
||
LrpcCopy->LpcHeader.u2.s2.DataInfoOffset = \
|
||
LrpcMessage->LpcHeader.u2.s2.DataInfoOffset
|
||
|
||
#define INITMSG(LrpcMessage, CId, Cbd, MId) \
|
||
(LrpcMessage)->LpcHeader.ClientId = ClientIdToMsgClientId(CId) ;\
|
||
(LrpcMessage)->LpcHeader.CallbackId = Cbd ;\
|
||
(LrpcMessage)->LpcHeader.MessageId = MId
|
||
|
||
#define AllocateMessage() ((LRPC_MESSAGE *) RpcAllocateBuffer(sizeof(LRPC_MESSAGE)))
|
||
#define FreeMessage(x) (RpcFreeBuffer((x)))
|
||
|
||
//
|
||
// The high bit of the sequence number
|
||
// is used to determine if it is a client or server
|
||
// key.
|
||
// CAUTION: Big endian implementations need to swap this
|
||
// around
|
||
//
|
||
typedef struct {
|
||
USHORT AssocKey;
|
||
USHORT SeqNumber;
|
||
} LPC_KEY;
|
||
|
||
|
||
class LRPC_SERVER
|
||
{
|
||
private:
|
||
LRPC_ADDRESS *Address ;
|
||
RPC_CHAR * Endpoint;
|
||
BOOL EndpointInitialized ;
|
||
MUTEX ServerMutex ;
|
||
|
||
public:
|
||
LRPC_SERVER(
|
||
IN OUT RPC_STATUS *Status
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
InitializeAsync (
|
||
) ;
|
||
|
||
void
|
||
GetEndpoint(
|
||
IN RPC_CHAR *Endpoint
|
||
)
|
||
{
|
||
RpcpStringCopy(Endpoint, this->Endpoint) ;
|
||
}
|
||
|
||
RPC_STATUS
|
||
SetEndpoint(
|
||
IN RPC_CHAR *Endpoint
|
||
)
|
||
{
|
||
if (EndpointInitialized == 0)
|
||
{
|
||
this->Endpoint = DuplicateString(Endpoint) ;
|
||
if (this->Endpoint == 0)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY ;
|
||
}
|
||
|
||
EndpointInitialized = 1 ;
|
||
}
|
||
|
||
return RPC_S_OK ;
|
||
}
|
||
|
||
void
|
||
AcquireMutex(
|
||
)
|
||
{
|
||
ServerMutex.Request() ;
|
||
}
|
||
|
||
void
|
||
ReleaseMutex(
|
||
)
|
||
{
|
||
ServerMutex.Clear() ;
|
||
}
|
||
|
||
void VerifyOwned(void)
|
||
{
|
||
ServerMutex.VerifyOwned();
|
||
}
|
||
|
||
BOOL
|
||
TryRequestMutex (
|
||
void
|
||
)
|
||
{
|
||
return ServerMutex.TryRequest();
|
||
}
|
||
} ;
|
||
|
||
inline void LrpcMutexRequest(void)
|
||
{
|
||
GlobalLrpcServer->AcquireMutex();
|
||
}
|
||
|
||
inline void LrpcMutexClear(void)
|
||
{
|
||
GlobalLrpcServer->ReleaseMutex();
|
||
}
|
||
|
||
inline void LrpcMutexVerifyOwned(void)
|
||
{
|
||
GlobalLrpcServer->VerifyOwned();
|
||
}
|
||
|
||
inline BOOL LrpcMutexTryRequest(void)
|
||
{
|
||
return GlobalLrpcServer->TryRequestMutex();
|
||
}
|
||
|
||
|
||
class LRPC_ADDRESS : public RPC_ADDRESS
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
Fields:
|
||
|
||
LpcAddressPort - Contains the connection port which this address will
|
||
use to wait for clients to connect.
|
||
|
||
CallThreadCount - Contains the number of call threads we have executing.
|
||
|
||
MinimumCallThreads - Contains the minimum number of call threads.
|
||
|
||
ServerListeningFlag - Contains a flag indicating whether or not the server
|
||
is listening for remote procedure calls. A non-zero value indicates
|
||
that it is listening.
|
||
|
||
ActiveCallCount - Contains the number of remote procedure calls active
|
||
on this address.
|
||
|
||
AssociationDictionary - Contains the dictionary of associations on this
|
||
address. We need this to map from an association key into the
|
||
correct association. This is necessary to prevent a race condition
|
||
between deleting an association and using it.
|
||
|
||
--*/
|
||
{
|
||
private:
|
||
|
||
HANDLE LpcAddressPort;
|
||
long CallThreadCount;
|
||
long MinimumCallThreads;
|
||
LRPC_SASSOCIATION_DICT AssociationDictionary;
|
||
int AssociationCount ;
|
||
USHORT SequenceNumber;
|
||
CellTag DebugCellTag;
|
||
DebugEndpointInfo *DebugCell;
|
||
|
||
// not protected - operated by interlocks. We push on the list,
|
||
// but we never pop, knowing addresses don't get deleted.
|
||
LRPC_ADDRESS *AddressChain;
|
||
|
||
// the next three are protected by the LrpcMutex
|
||
// If TickleMessage is non-zero, this means that the
|
||
// address has been prepared for tickling. Once it
|
||
// is initialized, fTickleMessageAvailable is used
|
||
// to tell whether the TickleMessage is currently posted
|
||
// or not. If it is already posted, no need to repost.
|
||
BOOL fTickleMessageAvailable;
|
||
LRPC_BIND_EXCHANGE *TickleMessage;
|
||
UNICODE_STRING ThisAddressLoopbackString;
|
||
|
||
// the number of threads on this address doing long wait
|
||
INTERLOCKED_INTEGER ThreadsDoingLongWait;
|
||
|
||
public:
|
||
unsigned int ServerListeningFlag ;
|
||
BOOL fServerThreadsStarted;
|
||
|
||
LRPC_ADDRESS (
|
||
OUT RPC_STATUS * Status
|
||
);
|
||
|
||
~LRPC_ADDRESS (
|
||
void
|
||
)
|
||
{
|
||
if (DebugCell)
|
||
{
|
||
FreeCell(DebugCell, &DebugCellTag);
|
||
DebugCell = NULL;
|
||
}
|
||
}
|
||
|
||
virtual RPC_STATUS
|
||
ServerStartingToListen (
|
||
IN unsigned int MinimumCallThreads,
|
||
IN unsigned int MaximumConcurrentCalls
|
||
);
|
||
|
||
virtual void
|
||
ServerStoppedListening (
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ServerSetupAddress (
|
||
IN RPC_CHAR * NetworkAddress,
|
||
IN RPC_CHAR * *Endpoint,
|
||
IN unsigned int PendingQueueSize,
|
||
IN void * SecurityDescriptor, OPTIONAL
|
||
IN unsigned long EndpointFlags,
|
||
IN unsigned long NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
LRPC_ADDRESS::CompleteListen (
|
||
);
|
||
|
||
inline void
|
||
DereferenceAssociation (
|
||
IN LRPC_SASSOCIATION * Association
|
||
);
|
||
|
||
friend BOOL
|
||
RecvLotsaCallsWrapper(
|
||
IN LRPC_ADDRESS * Address
|
||
);
|
||
|
||
RPC_STATUS
|
||
BeginLongCall(
|
||
void
|
||
);
|
||
|
||
BOOL
|
||
EndLongCall(
|
||
void
|
||
);
|
||
|
||
inline BOOL
|
||
PrepareForLoopbackTicklingIfNecessary (
|
||
void
|
||
)
|
||
{
|
||
LrpcMutexVerifyOwned();
|
||
|
||
if (TickleMessage)
|
||
return TRUE;
|
||
|
||
return PrepareForLoopbackTickling();
|
||
}
|
||
|
||
BOOL
|
||
LoopbackTickle (
|
||
void
|
||
);
|
||
|
||
inline BOOL
|
||
IsPreparedForLoopbackTickling (
|
||
void
|
||
)
|
||
{
|
||
return (TickleMessage != NULL);
|
||
}
|
||
|
||
inline LRPC_ADDRESS *
|
||
GetNextAddress (
|
||
void
|
||
)
|
||
{
|
||
return AddressChain;
|
||
}
|
||
|
||
inline int
|
||
GetNumberOfThreadsDoingShortWait (
|
||
void
|
||
)
|
||
{
|
||
return CallThreadCount - ThreadsDoingLongWait.GetInteger();
|
||
}
|
||
|
||
private:
|
||
|
||
RPC_STATUS
|
||
ActuallySetupAddress (
|
||
IN RPC_CHAR *Endpoint,
|
||
IN void * SecurityDescriptor
|
||
);
|
||
|
||
inline LRPC_SASSOCIATION *
|
||
ReferenceAssociation (
|
||
IN unsigned long AssociationKey
|
||
);
|
||
|
||
inline LRPC_CASSOCIATION *
|
||
ReferenceClientAssoc (
|
||
IN unsigned long AssociationKey
|
||
);
|
||
|
||
void
|
||
ReceiveLotsaCalls (
|
||
);
|
||
|
||
void
|
||
DealWithNewClient (
|
||
IN LRPC_MESSAGE * ConnectionRequest
|
||
);
|
||
|
||
void
|
||
DealWithConnectResponse (
|
||
IN LRPC_MESSAGE * ConnectResponse
|
||
) ;
|
||
|
||
void
|
||
RejectNewClient (
|
||
IN LRPC_MESSAGE * ConnectionRequest,
|
||
IN RPC_STATUS Status
|
||
);
|
||
|
||
BOOL
|
||
DealWithLRPCRequest (
|
||
IN LRPC_MESSAGE * LrpcMessage,
|
||
IN LRPC_MESSAGE * LrpcReplyMessage,
|
||
IN LRPC_SASSOCIATION *Association,
|
||
OUT LRPC_MESSAGE **LrpcResponse
|
||
) ;
|
||
|
||
BOOL fKeepThread(
|
||
)
|
||
{
|
||
// we keep at least two threads per address, to avoid creating the
|
||
// second thread each time a call arrives. Note that the second
|
||
// thread is free to timeout on the port and exit, the question
|
||
// is that it doesn't exit immediately after the call, as this will
|
||
// cause unnecessary creation/deletions of threads
|
||
return (((CallThreadCount - ActiveCallCount) <= 2)
|
||
|| (CallThreadCount <= MinimumCallThreads));
|
||
}
|
||
|
||
typedef enum
|
||
{
|
||
asctDestroyContextHandle = 0,
|
||
asctCleanupIdleSContext
|
||
} AssociationCallbackType;
|
||
|
||
void
|
||
EnumerateAndCallEachAssociation (
|
||
IN AssociationCallbackType asctType,
|
||
IN OUT void *Context OPTIONAL
|
||
);
|
||
|
||
virtual void
|
||
DestroyContextHandlesForInterface (
|
||
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
||
IN BOOL RundownContextHandles
|
||
);
|
||
|
||
virtual void
|
||
CleanupIdleSContexts (
|
||
void
|
||
);
|
||
|
||
BOOL
|
||
PrepareForLoopbackTickling (
|
||
void
|
||
);
|
||
|
||
void HandleInvalidAssociationReference (
|
||
IN LRPC_MESSAGE *RequestMessage,
|
||
IN OUT LRPC_MESSAGE **ReplyMessage,
|
||
IN ULONG AssociationKey
|
||
);
|
||
};
|
||
|
||
|
||
class LRPC_SBINDING
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
Each object of this class represents a binding to an interface by a
|
||
client.
|
||
|
||
Fields:
|
||
|
||
RpcInterface - Contains a pointer to the bound interface.
|
||
|
||
PresentationContext - Contains the key which the client will send when
|
||
it wants to use this binding.
|
||
|
||
--*/
|
||
{
|
||
friend class LRPC_SASSOCIATION;
|
||
friend class LRPC_SCALL;
|
||
friend class LRPC_ADDRESS;
|
||
|
||
private:
|
||
|
||
RPC_INTERFACE * RpcInterface;
|
||
int PresentationContext;
|
||
int SelectedTransferSyntaxIndex;
|
||
unsigned long SequenceNumber ;
|
||
|
||
public:
|
||
|
||
LRPC_SBINDING (
|
||
IN RPC_INTERFACE * RpcInterface,
|
||
IN int SelectedTransferSyntax
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We will construct a LRPC_SBINDING.
|
||
|
||
Arguments:
|
||
|
||
RpcInterface - Supplies the bound interface.
|
||
|
||
TransferSyntax - Supplies the transfer syntax which the client will use
|
||
over this binding.
|
||
|
||
--*/
|
||
{
|
||
this->RpcInterface = RpcInterface;
|
||
SequenceNumber = 0;
|
||
SelectedTransferSyntaxIndex = SelectedTransferSyntax;
|
||
}
|
||
|
||
RPC_STATUS
|
||
CheckSecurity (
|
||
SCALL * Context
|
||
);
|
||
|
||
inline unsigned short GetOnTheWirePresentationContext(void)
|
||
{
|
||
return (unsigned short)PresentationContext;
|
||
}
|
||
|
||
inline void SetPresentationContextFromPacket(unsigned short PresentContext)
|
||
{
|
||
PresentationContext = (int) PresentContext;
|
||
}
|
||
|
||
inline int GetPresentationContext (void)
|
||
{
|
||
return PresentationContext;
|
||
}
|
||
|
||
inline void SetPresentationContext (int PresentContext)
|
||
{
|
||
PresentationContext = PresentContext;
|
||
}
|
||
|
||
inline void GetSelectedTransferSyntaxAndDispatchTable(
|
||
OUT RPC_SYNTAX_IDENTIFIER **SelectedTransferSyntax,
|
||
OUT PRPC_DISPATCH_TABLE *SelectedDispatchTable)
|
||
{
|
||
RpcInterface->GetSelectedTransferSyntaxAndDispatchTable(SelectedTransferSyntaxIndex,
|
||
SelectedTransferSyntax, SelectedDispatchTable);
|
||
}
|
||
|
||
DWORD GetInterfaceFirstDWORD(void)
|
||
{
|
||
return RpcInterface->GetInterfaceFirstDWORD();;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
typedef void * LRPC_BUFFER;
|
||
|
||
NEW_SDICT(LRPC_SBINDING);
|
||
NEW_SDICT(LRPC_CLIENT_BUFFER);
|
||
NEW_SDICT2(LRPC_SCALL, PVOID);
|
||
NEW_NAMED_SDICT2(LRPC_SCALL_THREAD, LRPC_SCALL, HANDLE);
|
||
|
||
#define USER_NAME_LEN 256
|
||
#define DOMAIN_NAME_LEN 128
|
||
|
||
extern const SID AnonymousSid;
|
||
|
||
|
||
class LRPC_SCONTEXT
|
||
{
|
||
public:
|
||
HANDLE hToken;
|
||
LUID ClientLuid;
|
||
RPC_CHAR *ClientName;
|
||
int RefCount;
|
||
LRPC_SASSOCIATION *Association;
|
||
AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext;
|
||
|
||
LRPC_SCONTEXT (
|
||
IN HANDLE MyToken,
|
||
IN LUID *UserLuid,
|
||
IN LRPC_SASSOCIATION *MyAssociation,
|
||
IN BOOL fDefaultLogonId,
|
||
IN BOOL fAnonymousToken
|
||
);
|
||
|
||
~LRPC_SCONTEXT (
|
||
void
|
||
);
|
||
|
||
void AddReference();
|
||
void RemoveReference();
|
||
void Destroy();
|
||
|
||
RPC_STATUS
|
||
GetUserName (
|
||
IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL,
|
||
OUT RPC_CHAR **UserName,
|
||
IN HANDLE hUserToken OPTIONAL
|
||
);
|
||
|
||
static const unsigned int Deleted = 1;
|
||
static const unsigned int DefaultLogonId = 2;
|
||
static const unsigned int Anonymous = 4;
|
||
static const unsigned int ServerSideOnly = 8;
|
||
|
||
inline void SetDeletedFlag(void)
|
||
{
|
||
Flags.SetFlagUnsafe(Deleted);
|
||
}
|
||
inline void ClearDeletedFlag(void)
|
||
{
|
||
Flags.ClearFlagUnsafe(Deleted);
|
||
}
|
||
inline BOOL GetDeletedFlag(void)
|
||
{
|
||
return Flags.GetFlag(Deleted);
|
||
}
|
||
|
||
inline void SetDefaultLogonIdFlag(void)
|
||
{
|
||
Flags.SetFlagUnsafe(DefaultLogonId);
|
||
}
|
||
inline void ClearDefaultLogonIdFlag(void)
|
||
{
|
||
Flags.ClearFlagUnsafe(DefaultLogonId);
|
||
}
|
||
inline BOOL GetDefaultLogonIdFlag(void)
|
||
{
|
||
return Flags.GetFlag(DefaultLogonId);
|
||
}
|
||
|
||
inline void SetAnonymousFlag(void)
|
||
{
|
||
Flags.SetFlagUnsafe(Anonymous);
|
||
}
|
||
inline void ClearAnonymousFlag(void)
|
||
{
|
||
Flags.ClearFlagUnsafe(Anonymous);
|
||
}
|
||
inline BOOL GetAnonymousFlag(void)
|
||
{
|
||
return Flags.GetFlag(Anonymous);
|
||
}
|
||
|
||
inline void SetServerSideOnlyFlag(void)
|
||
{
|
||
Flags.SetFlagUnsafe(ServerSideOnly);
|
||
}
|
||
inline void ClearServerSideOnlyFlag(void)
|
||
{
|
||
Flags.ClearFlagUnsafe(ServerSideOnly);
|
||
}
|
||
inline BOOL GetServerSideOnlyFlag(void)
|
||
{
|
||
return Flags.GetFlag(ServerSideOnly);
|
||
}
|
||
|
||
static const ULONG CONTEXT_IDLE_TIMEOUT = 2 * 60 * 1000; // 2 minutes
|
||
|
||
inline void UpdateLastAccessTime (void)
|
||
{
|
||
LastAccessTime = NtGetTickCount();
|
||
}
|
||
|
||
inline BOOL IsIdle (void)
|
||
{
|
||
// make sure if the tick count wraps the calculation is still valid
|
||
return (NtGetTickCount() - LastAccessTime > CONTEXT_IDLE_TIMEOUT);
|
||
}
|
||
|
||
private:
|
||
static TOKEN_USER *
|
||
GetSID (
|
||
IN HANDLE hToken
|
||
);
|
||
|
||
static RPC_STATUS
|
||
LookupUser (
|
||
IN SID *pSid,
|
||
OUT RPC_CHAR **UserName
|
||
);
|
||
|
||
// changed either on creation, or within
|
||
// the Association mutex
|
||
CompositeFlags Flags;
|
||
|
||
// the last access time for server side only contexts.
|
||
// Undefined if the context is not server side only
|
||
// It is used to determine whether the context is idle
|
||
ULONG LastAccessTime;
|
||
};
|
||
|
||
NEW_SDICT(LRPC_SCONTEXT);
|
||
|
||
|
||
class LRPC_SASSOCIATION : public ASSOCIATION_HANDLE
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
|
||
Fields:
|
||
|
||
LpcServerPort - Contains the LPC server communication port.
|
||
|
||
Bindings - Contains the dictionary of bindings with the client. This
|
||
information is necessary to dispatch remote procedure calls to the
|
||
correct stub.
|
||
|
||
Address - Contains the address which this association is over.
|
||
|
||
AssociationReferenceCount - Contains a count of the number of objects
|
||
referencing this association. This will be the number of outstanding
|
||
remote procedure calls, and one for LPC (because of the context
|
||
pointer). We will protect this fielding using the global mutex.
|
||
|
||
Buffers - Contains the dictionary of buffers to be written into the
|
||
client's address space on demand.
|
||
|
||
AssociationKey - Contains the key for this association in the dictionary
|
||
of associations maintained by the address.
|
||
|
||
ClientThreadDict - This dictionary contains one entry per client thread. Each entry
|
||
contains a list of SCALLS representing calls made by that client thread. The
|
||
calls need to be causally ordered.
|
||
|
||
--*/
|
||
{
|
||
friend class LRPC_ADDRESS;
|
||
friend class LRPC_SCALL;
|
||
friend class LRPC_SCONTEXT;
|
||
friend void
|
||
SetFaultPacket (
|
||
IN LRPC_MESSAGE *LrpcMessage,
|
||
IN RPC_STATUS Status,
|
||
IN int Flags,
|
||
IN LRPC_SCALL *CurrentCall OPTIONAL
|
||
);
|
||
|
||
private:
|
||
|
||
long AssociationReferenceCount;
|
||
USHORT DictionaryKey;
|
||
USHORT SequenceNumber;
|
||
HANDLE LpcServerPort;
|
||
HANDLE LpcReplyPort ;
|
||
LRPC_ADDRESS * Address;
|
||
LRPC_SBINDING_DICT Bindings;
|
||
int Aborted ;
|
||
long Deleted ;
|
||
LRPC_SCALL *CachedSCall;
|
||
LONG CachedSCallAvailable;
|
||
BOOL fFirstCall;
|
||
LRPC_CLIENT_BUFFER_DICT Buffers ;
|
||
MUTEX AssociationMutex ;
|
||
QUEUE FreeSCallQueue ;
|
||
LRPC_SCALL_THREAD_DICT2 ClientThreadDict ;
|
||
LRPC_SCONTEXT_DICT SContextDict;
|
||
|
||
public:
|
||
|
||
LRPC_SCALL_DICT2 SCallDict ;
|
||
|
||
|
||
LRPC_SASSOCIATION (
|
||
IN LRPC_ADDRESS * Address,
|
||
IN RPC_STATUS *Status
|
||
);
|
||
|
||
~LRPC_SASSOCIATION (
|
||
);
|
||
|
||
RPC_STATUS
|
||
AddBinding (
|
||
IN OUT LRPC_BIND_EXCHANGE * BindExchange
|
||
);
|
||
|
||
void
|
||
DealWithBindMessage (
|
||
IN LRPC_MESSAGE * LrpcMessage
|
||
);
|
||
|
||
LRPC_MESSAGE *
|
||
DealWithCopyMessage (
|
||
IN LRPC_COPY_MESSAGE * LrpcMessage
|
||
) ;
|
||
|
||
NTSTATUS
|
||
ReplyMessage (
|
||
IN LRPC_MESSAGE * LrpcMessage
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
SaveToken (
|
||
IN LRPC_MESSAGE *LrpcMessage,
|
||
OUT HANDLE *pTokenHandle,
|
||
IN BOOL fRestoreToken = 0
|
||
) ;
|
||
|
||
LRPC_MESSAGE *
|
||
DealWithBindBackMessage (
|
||
IN LRPC_MESSAGE *BindBack
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
BindBack (
|
||
IN RPC_CHAR *Endpoint,
|
||
IN DWORD pAssocKey
|
||
) ;
|
||
|
||
LRPC_MESSAGE *
|
||
DealWithPartialRequest (
|
||
IN LRPC_MESSAGE **LrpcMessage
|
||
) ;
|
||
|
||
void
|
||
Delete(
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
AllocateSCall (
|
||
IN LRPC_MESSAGE *LrpcMessage,
|
||
IN LRPC_MESSAGE *LrpcReply,
|
||
IN unsigned int Flags,
|
||
IN LRPC_SCALL **SCall
|
||
) ;
|
||
|
||
void
|
||
FreeSCall (
|
||
LRPC_SCALL *SCall
|
||
) ;
|
||
|
||
int
|
||
MaybeQueueSCall (
|
||
IN LRPC_SCALL *SCall
|
||
) ;
|
||
|
||
LRPC_SCALL *
|
||
GetNextSCall (
|
||
IN LRPC_SCALL *SCall
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
GetClientName (
|
||
IN LRPC_SCALL *SCall,
|
||
IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL, // in bytes
|
||
OUT RPC_CHAR **ClientPrincipalName
|
||
);
|
||
|
||
void
|
||
AbortAssociation (
|
||
)
|
||
{
|
||
Aborted = 1 ;
|
||
}
|
||
|
||
LRPC_SCONTEXT *
|
||
FindSecurityContext (
|
||
ULONG SecurityContextId
|
||
)
|
||
{
|
||
LRPC_SCONTEXT *SContext;
|
||
|
||
AssociationMutex.Request();
|
||
SContext = SContextDict.Find(SecurityContextId);
|
||
if (SContext)
|
||
{
|
||
SContext->AddReference();
|
||
}
|
||
AssociationMutex.Clear();
|
||
|
||
return SContext;
|
||
}
|
||
|
||
int
|
||
IsAborted(
|
||
)
|
||
{
|
||
return Aborted ;
|
||
}
|
||
|
||
void
|
||
MaybeDereference (
|
||
)
|
||
{
|
||
if (Aborted)
|
||
{
|
||
Delete() ;
|
||
}
|
||
}
|
||
|
||
LRPC_ADDRESS *
|
||
InqAddress(
|
||
)
|
||
{
|
||
return Address ;
|
||
}
|
||
|
||
virtual RPC_STATUS CreateThread(void);
|
||
virtual void RundownNotificationCompleted(void);
|
||
|
||
void
|
||
CleanupIdleSContexts (
|
||
void
|
||
);
|
||
};
|
||
|
||
|
||
|
||
class LRPC_SCALL : public SCALL
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
Fields:
|
||
|
||
Association - Contains the association over which the remote procedure
|
||
call was received. We need this information to make callbacks and
|
||
to send the reply.
|
||
|
||
LrpcMessage - Contains the request message. We need this to send callbacks
|
||
as well as the reply.
|
||
|
||
SBinding - Contains the binding being used for this remote procedure call.
|
||
|
||
ObjectUuidFlag - Contains a flag indicting whether or not an object
|
||
uuid was specified for this remote procedure call. A non-zero
|
||
value indicates that an object uuid was specified.
|
||
|
||
ObjectUuid - Optionally contains the object uuid for this call, if one
|
||
was specified.
|
||
|
||
ClientId - Contains the thread identifier of the thread which made the
|
||
remote procedure call.
|
||
|
||
MessageId - Contains an identifier used by LPC to identify the current
|
||
remote procedure call.
|
||
|
||
PushedResponse - When the client needs to send a large response to the
|
||
server it must be transfered via a request. This holds the pushed
|
||
response until the request gets here.
|
||
|
||
--*/
|
||
{
|
||
friend class LRPC_SASSOCIATION;
|
||
friend class LRPC_ADDRESS;
|
||
friend void
|
||
SetFaultPacket (
|
||
IN LRPC_MESSAGE *LrpcMessage,
|
||
IN RPC_STATUS Status,
|
||
IN int Flags,
|
||
IN LRPC_SCALL *CurrentCall OPTIONAL
|
||
);
|
||
|
||
private:
|
||
CLIENT_AUTH_INFO AuthInfo;
|
||
LRPC_SASSOCIATION * Association;
|
||
LRPC_MESSAGE * LrpcRequestMessage;
|
||
LRPC_MESSAGE * LrpcReplyMessage;
|
||
LRPC_SBINDING * SBinding;
|
||
unsigned int ObjectUuidFlag;
|
||
ULONG CallId;
|
||
CLIENT_ID ClientId;
|
||
ULONG MessageId;
|
||
ULONG CallbackId;
|
||
void * PushedResponse;
|
||
ULONG CurrentBufferLength ;
|
||
int BufferComplete ;
|
||
LRPC_MESSAGE *LrpcAsyncReplyMessage;
|
||
unsigned int Flags ;
|
||
BOOL FirstSend ;
|
||
BOOL PipeSendCalled ;
|
||
int Deleted ;
|
||
RPC_UUID ObjectUuid;
|
||
|
||
DebugCallInfo *DebugCell;
|
||
|
||
// Async RPC
|
||
EVENT *ReceiveEvent ;
|
||
MUTEX *CallMutex ;
|
||
|
||
// the cell tag to the DebugCell above
|
||
CellTag DebugCellTag;
|
||
|
||
ULONG RcvBufferLength ;
|
||
BOOL ReceiveComplete ;
|
||
BOOL AsyncReply ;
|
||
LRPC_SCALL *NextSCall ;
|
||
LRPC_SCALL *LastSCall ;
|
||
ULONG NeededLength;
|
||
|
||
BOOL fSyncDispatch ;
|
||
BOOL Choked ;
|
||
long CancelPending;
|
||
|
||
RPC_MESSAGE RpcMessage;
|
||
RPC_RUNTIME_INFO RuntimeInfo;
|
||
QUEUE BufferQueue ;
|
||
|
||
RPC_CHAR *ClientPrincipalName;
|
||
public:
|
||
LRPC_SCONTEXT *SContext;
|
||
|
||
LRPC_SCALL (OUT RPC_STATUS *RpcStatus)
|
||
{
|
||
ObjectType = LRPC_SCALL_TYPE;
|
||
ReceiveEvent = 0;
|
||
CallMutex = 0;
|
||
LrpcAsyncReplyMessage = 0;
|
||
ClientPrincipalName = NULL;
|
||
*RpcStatus = RPC_S_OK;
|
||
|
||
if (IsServerSideDebugInfoEnabled())
|
||
{
|
||
DebugCell = (DebugCallInfo *)AllocateCell(&DebugCellTag);
|
||
if (DebugCell == NULL)
|
||
*RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
else
|
||
{
|
||
memset(DebugCell, 0, sizeof(DebugCallInfo));
|
||
DebugCell->FastInit = 0;
|
||
DebugCell->Type = dctCallInfo;
|
||
DebugCell->Status = (BYTE)csAllocated;
|
||
DebugCell->CallFlags = DBGCELL_CACHED_CALL | DBGCELL_LRPC_CALL;
|
||
DebugCell->LastUpdateTime = NtGetTickCount();
|
||
}
|
||
}
|
||
else
|
||
DebugCell = NULL;
|
||
}
|
||
|
||
~LRPC_SCALL (
|
||
)
|
||
{
|
||
if (ReceiveEvent)
|
||
{
|
||
if (CallId != (ULONG) -1)
|
||
{
|
||
Association->AssociationMutex.Request() ;
|
||
Association->SCallDict.Delete(ULongToPtr(CallId));
|
||
Association->AssociationMutex.Clear() ;
|
||
}
|
||
|
||
delete ReceiveEvent;
|
||
delete CallMutex ;
|
||
}
|
||
|
||
if (DebugCell)
|
||
{
|
||
FreeCell(DebugCell, &DebugCellTag);
|
||
}
|
||
|
||
if (LrpcAsyncReplyMessage)
|
||
{
|
||
FreeMessage(LrpcAsyncReplyMessage);
|
||
}
|
||
}
|
||
|
||
virtual RPC_STATUS
|
||
NegotiateTransferSyntax (
|
||
IN OUT PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
GetBuffer (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN UUID *ObjectUuid
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
SendReceive (
|
||
IN OUT PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
Send (
|
||
IN OUT PRPC_MESSAGE Messsage
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
Receive (
|
||
IN PRPC_MESSAGE Message,
|
||
IN unsigned int Size
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
AsyncSend (
|
||
IN OUT PRPC_MESSAGE Message
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
AsyncReceive (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN unsigned int Size
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
SetAsyncHandle (
|
||
IN PRPC_ASYNC_STATE pAsync
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
AbortAsyncCall (
|
||
IN PRPC_ASYNC_STATE pAsync,
|
||
IN unsigned long ExceptionCode
|
||
) ;
|
||
|
||
virtual void
|
||
FreeBuffer (
|
||
IN PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual void
|
||
FreePipeBuffer (
|
||
IN PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ReallocPipeBuffer (
|
||
IN PRPC_MESSAGE Message,
|
||
IN unsigned int NewSize
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
ImpersonateClient (
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
RevertToSelf (
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
GetAuthorizationContext (
|
||
IN BOOL ImpersonateOnReturn,
|
||
IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
|
||
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
||
IN LUID Identifier,
|
||
IN DWORD Flags,
|
||
IN PVOID DynamicGroupArgs OPTIONAL,
|
||
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
IsClientLocal (
|
||
OUT unsigned int * ClientLocalFlag
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ConvertToServerBinding (
|
||
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
|
||
);
|
||
|
||
virtual void
|
||
InquireObjectUuid (
|
||
OUT RPC_UUID * ObjectUuid
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ToStringBinding (
|
||
OUT RPC_CHAR ** StringBinding
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
GetAssociationContextCollection (
|
||
OUT ContextCollection **CtxCollection
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
InquireAuthClient (
|
||
OUT RPC_AUTHZ_HANDLE * Privileges,
|
||
OUT RPC_CHAR * * ServerPrincipalName, OPTIONAL
|
||
OUT unsigned long * AuthenticationLevel,
|
||
OUT unsigned long * AuthenticationService,
|
||
OUT unsigned long * AuthorizationService,
|
||
IN unsigned long Flags
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
InquireCallAttributes (
|
||
IN OUT void *RpcCallAttributes
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
InqTransportType(
|
||
OUT unsigned int __RPC_FAR * Type
|
||
)
|
||
{
|
||
*Type = TRANSPORT_TYPE_LPC ;
|
||
|
||
return (RPC_S_OK) ;
|
||
}
|
||
|
||
virtual BOOL
|
||
IsSyncCall (
|
||
)
|
||
{
|
||
return !pAsync ;
|
||
}
|
||
|
||
virtual unsigned
|
||
TestCancel(
|
||
)
|
||
{
|
||
return InterlockedExchange(&CancelPending, 0);
|
||
}
|
||
|
||
virtual void
|
||
FreeObject (
|
||
) ;
|
||
|
||
BOOL
|
||
IsClientAsync (
|
||
)
|
||
{
|
||
return ((Flags & LRPC_SYNC_CLIENT) == 0);
|
||
}
|
||
|
||
RPC_STATUS
|
||
ActivateCall (
|
||
IN LRPC_SASSOCIATION * Association,
|
||
IN LRPC_MESSAGE * LrpcMessage,
|
||
IN LRPC_MESSAGE * LrpcReplyMessage,
|
||
IN unsigned int Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description
|
||
|
||
Arguments:
|
||
|
||
arg1 - description
|
||
|
||
--*/
|
||
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
this->Association = Association;
|
||
this->LrpcRequestMessage = LrpcMessage;
|
||
this->LrpcReplyMessage = LrpcReplyMessage;
|
||
ObjectUuidFlag = 0;
|
||
PushedResponse = 0;
|
||
CurrentBufferLength = 0;
|
||
BufferComplete = 0;
|
||
this->Flags = Flags ;
|
||
FirstSend = 1;
|
||
PipeSendCalled = 0;
|
||
Deleted = 0;
|
||
SBinding = 0;
|
||
SetReferenceCount(2);
|
||
pAsync = 0;
|
||
NextSCall = 0;
|
||
LastSCall = 0;
|
||
CancelPending = 0;
|
||
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->Status = (BYTE)csActive;
|
||
if (Association->CachedSCall == this)
|
||
DebugCell->CallFlags = DBGCELL_CACHED_CALL | DBGCELL_LRPC_CALL;
|
||
else
|
||
DebugCell->CallFlags = DBGCELL_CACHED_CALL;
|
||
DebugCell->LastUpdateTime = NtGetTickCount();
|
||
}
|
||
|
||
// Async RPC stuff
|
||
|
||
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
||
RpcMessage.ReservedForRuntime = &RuntimeInfo;
|
||
RpcMessage.RpcFlags = 0;
|
||
|
||
if (LrpcMessage->Rpc.RpcHeader.SecurityContextId != -1)
|
||
{
|
||
SContext = Association->FindSecurityContext(
|
||
LrpcMessage->Rpc.RpcHeader.SecurityContextId);
|
||
if (SContext == NULL)
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SContext = NULL;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
inline void DeactivateCall (void)
|
||
{
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->Status = (BYTE)csAllocated;
|
||
DebugCell->LastUpdateTime = NtGetTickCount();
|
||
}
|
||
}
|
||
|
||
RPC_STATUS
|
||
ProcessResponse (
|
||
IN LRPC_MESSAGE **LrpcMessage
|
||
) ;
|
||
|
||
inline RPC_STATUS
|
||
LrpcMessageToRpcMessage (
|
||
IN LRPC_MESSAGE * LrpcMessage,
|
||
IN OUT PRPC_MESSAGE Message
|
||
) ;
|
||
|
||
void
|
||
DealWithRequestMessage (
|
||
);
|
||
|
||
void
|
||
HandleRequest (
|
||
) ;
|
||
|
||
LRPC_SASSOCIATION *
|
||
InqAssociation (
|
||
)
|
||
{
|
||
return Association;
|
||
}
|
||
|
||
LRPC_MESSAGE *
|
||
InitMsg (
|
||
)
|
||
{
|
||
INITMSG(LrpcReplyMessage,
|
||
ClientId,
|
||
CallbackId,
|
||
MessageId) ;
|
||
|
||
LrpcReplyMessage->LpcHeader.u1.s1.TotalLength =
|
||
LrpcReplyMessage->LpcHeader.u1.s1.DataLength+sizeof(PORT_MESSAGE);
|
||
|
||
return LrpcReplyMessage;
|
||
}
|
||
|
||
virtual RPC_STATUS
|
||
InqConnection (
|
||
OUT void **ConnId,
|
||
OUT BOOL *pfFirstCall
|
||
)
|
||
{
|
||
ASSERT(Association);
|
||
*ConnId = Association;
|
||
|
||
if (InterlockedIncrement((LONG *) &(Association->fFirstCall)) == 1)
|
||
{
|
||
*pfFirstCall = 1;
|
||
}
|
||
else
|
||
{
|
||
*pfFirstCall = 0;
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
inline HANDLE InqLocalClientPID (
|
||
void
|
||
)
|
||
{
|
||
return ClientId.UniqueProcess;
|
||
}
|
||
|
||
private:
|
||
RPC_STATUS
|
||
GetBufferDo(
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN unsigned long NewSize,
|
||
IN BOOL fDataValid
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
SetupCall (
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
GetCoalescedBuffer (
|
||
IN PRPC_MESSAGE Message,
|
||
IN BOOL BufferValid
|
||
) ;
|
||
|
||
RPC_STATUS
|
||
SendRequest (
|
||
IN OUT PRPC_MESSAGE Messsage,
|
||
OUT BOOL *Shutup
|
||
) ;
|
||
|
||
void
|
||
SendReply (
|
||
);
|
||
|
||
NTSTATUS
|
||
SendDGReply (
|
||
IN LRPC_MESSAGE *LrpcMessage
|
||
)
|
||
{
|
||
NTSTATUS NtStatus ;
|
||
|
||
LrpcMessage->LpcHeader.u2.ZeroInit = 0;
|
||
LrpcMessage->LpcHeader.CallbackId = 0;
|
||
LrpcMessage->LpcHeader.MessageId = 0;
|
||
LrpcMessage->LpcHeader.u1.s1.TotalLength =
|
||
LrpcMessage->LpcHeader.u1.s1.DataLength+sizeof(PORT_MESSAGE);
|
||
|
||
NtStatus = NtRequestPort(Association->LpcReplyPort,
|
||
(PORT_MESSAGE *) LrpcMessage);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
#if DBG
|
||
if ((NtStatus != STATUS_INVALID_CID)
|
||
&& (NtStatus != STATUS_REPLY_MESSAGE_MISMATCH)
|
||
&& (NtStatus != STATUS_PORT_DISCONNECTED))
|
||
{
|
||
PrintToDebugger("RPC : NtRequestPort : %lx, 0x%x, 0x%x\n",
|
||
NtStatus, this, Association->LpcReplyPort);
|
||
ASSERT(NtStatus != STATUS_INVALID_HANDLE);
|
||
}
|
||
#endif // DBG
|
||
Association->Delete();
|
||
}
|
||
|
||
|
||
return NtStatus ;
|
||
}
|
||
|
||
LRPC_SBINDING *
|
||
LookupBinding (
|
||
IN unsigned short PresentContextId
|
||
);
|
||
};
|
||
|
||
|
||
inline NTSTATUS
|
||
LRPC_SASSOCIATION::ReplyMessage(
|
||
IN LRPC_MESSAGE * LrpcMessage
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Send a reply to a request
|
||
|
||
Arguments:
|
||
|
||
LrpcMessage - Reply message
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Function succeeded
|
||
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus ;
|
||
|
||
LrpcMessage->LpcHeader.u1.s1.TotalLength =
|
||
LrpcMessage->LpcHeader.u1.s1.DataLength + sizeof(PORT_MESSAGE);
|
||
|
||
NtStatus = NtReplyPort(LpcServerPort,
|
||
(PORT_MESSAGE *) LrpcMessage) ;
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
#if DBG
|
||
PrintToDebugger("RPC : NtReplyPort : %lx, 0x%x, 0x%x\n",
|
||
NtStatus,
|
||
this,
|
||
LpcReplyPort);
|
||
ASSERT(NtStatus != STATUS_INVALID_HANDLE);
|
||
#endif
|
||
Delete();
|
||
}
|
||
|
||
return NtStatus ;
|
||
}
|
||
|
||
inline void
|
||
LRPC_SCONTEXT::AddReference()
|
||
{
|
||
Association->AssociationMutex.VerifyOwned();
|
||
ASSERT(RefCount);
|
||
|
||
RefCount++;
|
||
}
|
||
|
||
inline void
|
||
LRPC_SCONTEXT::RemoveReference()
|
||
{
|
||
LRPC_SASSOCIATION *MyAssoc = Association;
|
||
|
||
Association->AssociationMutex.Request();
|
||
RefCount--;
|
||
if (RefCount == 0)
|
||
{
|
||
delete this;
|
||
}
|
||
MyAssoc->AssociationMutex.Clear();
|
||
}
|
||
|
||
inline void
|
||
LRPC_SCONTEXT::Destroy()
|
||
{
|
||
Association->AssociationMutex.VerifyOwned();
|
||
if (GetDeletedFlag() == 0)
|
||
{
|
||
SetDeletedFlag();
|
||
RefCount--;
|
||
if (RefCount == 0)
|
||
{
|
||
delete this;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif //__LPCSVR_HXX__
|