Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2938 lines
68 KiB

/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
osfclnt.hxx
Abstract:
This file contains the client side classes for the OSF connection
oriented RPC protocol engine.
Author:
Michael Montague (mikemon) 17-Jul-1990
Revision History:
Mazhar Mohammed (mazharm) 11-08-1996 - Major re-haul to support async
- Added support for Async RPC, Pipes
- Changed class structure
Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
--*/
#ifndef __OSFCLNT_HXX__
#define __OSFCLNT_HXX__
enum OSF_CCALL_STATE
{
//
// Need to open the connection and bind, in order to
// handle the call
//
NeedOpenAndBind = 0,
//
// Need to send an alter context on the connection
// in order to handle this call
//
NeedAlterContext,
//
// We sent an alter-context, we are waiting for a reply
//
WaitingForAlterContext,
//
// The call is still sending the non pipe data
// we need to finish sending this before
// we can move on the the next call.
//
SendingFirstBuffer,
//
// The call is now sending pipe data
//
SendingMoreData,
//
// The the call is done sending data. It is now waiting for a reply.
// The reply may be either a response or a callback.
//
WaitingForReply,
//
// The call is receiving a callback from the server
//
InCallbackRequest,
//
// The call is in the process of sending a reply to a callback
//
InCallbackReply,
//
// We move into this state after receiving the first fragment
//
Receiving,
//
// Some failure occured. the call is now in an
// aborted state
//
Aborted,
//
// The call is complete
//
Complete
} ;
//
// Maximum retries in light of getting a shutdown
// or closed in doing a bind or shutdown
//
#define MAX_RETRIES 3
// 15 min timeout for bind
#define RPC_C_SERVER_BIND_TIMEOUT 15*60*1000
//
// These values specify the minimum amount of time in milliseconds to wait before
// deleting an idle connection. The second is the more aggressive. It will be used
// when we have more than 500 connections in an association
//
const ULONG AGGRESSIVE_TIMEOUT_THRESHOLD = 500;
const ULONG CLIENT_DISCONNECT_TIME1 = 10 * 1000;
const ULONG CLIENT_DISCONNECT_TIME2 = 5 * 1000;
#define InqTransCConnection(RpcTransportConnection) \
((OSF_CCONNECTION *) \
((char *) RpcTransportConnection - sizeof(OSF_CCONNECTION)))
#define TransConnection() ((RPC_TRANSPORT_CONNECTION) \
((char *) this+sizeof(OSF_CCONNECTION)))
#define TransResolverHint() ((void *) ((char *) this+sizeof(OSF_CASSOCIATION)))
class OSF_CASSOCIATION;
class OSF_CCONNECTION ;
class OSF_BINDING ;
class OSF_CCALL ;
extern MUTEX *AssocDictMutex;
class OSF_RECURSIVE_ENTRY
/*++
Class Description:
This class is used to describe the entries in the dictionary of
recursive calls maintained by each binding handle.
Fields:
Thread - Contains the thread owning this recursive call.
RpcInterfaceInformation - Contains information describing the
interface
CCall - Contains the call
--*/
{
friend class OSF_BINDING_HANDLE;
private:
THREAD_IDENTIFIER Thread;
PRPC_CLIENT_INTERFACE RpcInterfaceInformation;
OSF_CCALL * CCall;
public:
OSF_RECURSIVE_ENTRY (
IN THREAD_IDENTIFIER Thread,
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
IN OSF_CCALL * CCall
);
OSF_CCALL *
IsThisMyRecursiveCall (
IN THREAD_IDENTIFIER Thread,
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
);
};
inline
OSF_RECURSIVE_ENTRY::OSF_RECURSIVE_ENTRY (
IN THREAD_IDENTIFIER Thread,
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
IN OSF_CCALL * CCall
)
/*++
Routine Description:
All we do in this constructor is stash the arguments passed to us
away in the object.
Arguments:
Thread - Supplies the thread for which this is the recursive call.
RpcInterfaceInformation - Supplies information describing the
interface
CCall - Supplies the recursive call.
--*/
{
this->Thread = Thread;
this->RpcInterfaceInformation = RpcInterfaceInformation;
this->CCall = CCall;
}
inline OSF_CCALL *
OSF_RECURSIVE_ENTRY::IsThisMyRecursiveCall (
IN THREAD_IDENTIFIER Thread,
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
)
/*++
Routine Description:
This routine determines if this object contains the recursive call
for the specified thread and interface information.
Arguments:
Thread - Supplies the thread.
RpcInterfaceInformation - Supplies the interface information.
Return Value:
If this object contains the recursive call corresponding to the
specified thread and interface information, then the connection is
returned. Otherwise, zero will be returned.
--*/
{
return((((Thread == this->Thread)
&& (RpcInterfaceInformation == this->RpcInterfaceInformation))
? CCall : 0));
}
NEW_SDICT(OSF_RECURSIVE_ENTRY);
class RPC_TOKEN
{
public:
HANDLE hToken;
LUID ModifiedId;
int RefCount;
int Key;
RPC_TOKEN (HANDLE hToken, LUID *pModifiedId)
{
this->hToken = hToken;
RefCount = 1;
FastCopyLUIDAligned(&ModifiedId, pModifiedId);
}
~RPC_TOKEN ()
{
CloseHandle(hToken);
}
};
class OSF_BINDING_HANDLE : public BINDING_HANDLE
/*++
Class Description:
Client applications use instances (referenced via an RPC_BINDING_HANDLE)
of this class to make remote procedure calls.
Fields:
Association - Contains a pointer to the association used by this
binding handle. The association can allocate connection for
making remote procedure calls. Before the first remote procedure
call is made using this binding handle, the Association will
be zero. When the first remote procedure call is made, an
assocation will be found or created for use by this binding handle.
DceBinding - Before the first remote procedure call for this binding
handle, this will contain the DCE binding information necessary
to create or find an association to be used by this binding handle.
After we have an association, this field will be zero.
TransportInterface - This field is the same as DceBinding, except that
it points to a rpc client info data structure used for describing
a loadable transport.
RecursiveCalls - This is a dictionary of recursive calls indexed
by thread identifier and rpc interface information.
BindingMutex - The binding handle can be used by more than one thread
at a time. Hence, we need to serialize access to the object;
we use this mutex for that.
ReferenceCount - We count the number of active connections and the
application RPC_BINDING_HANDLE which point at this object. This
is so that we know when to free it.
--*/
{
friend class OSF_CCALL;
private:
OSF_CASSOCIATION * Association;
DCE_BINDING * DceBinding;
TRANS_INFO *TransInfo ;
OSF_RECURSIVE_ENTRY_DICT RecursiveCalls;
UINT ReferenceCount;
RPC_TOKEN *pToken;
public:
// This data member has very rich semantics. Named pipes of
// course are a special beast, and for them we do a bunch of
// special magic. If this is not a named pipe binding handle,
// NPType will be nptNotNamedPipe. However, if it is a named pipe
// it will be one of nptLocalStatic, nptRemoteStatic,
// nptLocalDynamic and nptRemoteDynamic. We do three things
// differently for named pipes:
// A. Determine when an existing connection can be used for a new
// binding handle. This is needed because while we know that
// all binding handles on the association are either static
// or dynamic on the named pipe transport security level (this
// is part of the association comparison logic), the different
// binding handles may have different identities hanging off
// them. Therefore you need to open new connections, unless
// the identity tracking is dynamic and the connection is
// exclusive
// B. Swap token on Open. This is needed because we may do the
// open from a worker thread which does not have the identity
// used for the binding handle. For static tracking, we need this
// even when opening from the client thread.
// C. Swap token on Write. This is needed when dynamic tracking
// is used to prevent impersontation from the server resulting in
// the process identity vs. the caller identity when the writes
// are done on a worker thread.
// Depending on the local/remote and static/dynamic settings, we
// have the following table of what we do when
// Identity
// Tracking Local Remote
// ---------------------------------------------------
// Static A, B A, B
// Dynamic B, C, maybe A A, B
NamedPipeType NPType;
BOOL TransAuthInitialized;
BOOL fDynamicEndpoint;
OSF_BINDING_HANDLE (
IN OUT RPC_STATUS * RpcStatus
);
~OSF_BINDING_HANDLE (
);
virtual RPC_STATUS
NegotiateTransferSyntax (
IN OUT PRPC_MESSAGE Message
);
virtual RPC_STATUS
GetBuffer (
IN OUT PRPC_MESSAGE Message,
IN UUID *ObjectUuid
);
virtual RPC_STATUS
BindingCopy (
OUT BINDING_HANDLE * * DestinationBinding,
IN UINT MaintainContext
);
virtual RPC_STATUS
BindingFree (
);
virtual RPC_STATUS
PrepareBindingHandle (
IN TRANS_INFO * TransportInterface,
IN DCE_BINDING * DceBinding
);
virtual RPC_STATUS
ToStringBinding (
OUT RPC_CHAR * * StringBinding
);
virtual RPC_STATUS
ResolveBinding (
IN RPC_CLIENT_INTERFACE * RpcClientInterface
);
virtual RPC_STATUS
BindingReset (
);
virtual RPC_STATUS
InquireTransportType(
OUT UINT *Type
)
{ *Type = TRANSPORT_TYPE_CN; return(RPC_S_OK); }
virtual ULONG
MapAuthenticationLevel (
IN ULONG AuthenticationLevel
);
virtual void
AddReference (
)
{
BindingMutex.Request();
ReferenceCount++;
BindingMutex.Clear();
}
RPC_STATUS
AllocateCCall (
OUT OSF_CCALL * * CCall,
IN PRPC_MESSAGE Message,
OUT BOOL *Retry
);
RPC_STATUS
AddRecursiveEntry (
IN OSF_CCALL * CCall,
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
);
void
RemoveRecursiveCall (
IN OSF_CCALL * CCall
);
OSF_CASSOCIATION *
TheAssociation (
) {return(Association);}
OSF_CASSOCIATION *
FindOrCreateAssociation (
IN DCE_BINDING * DceBinding,
IN TRANS_INFO * TransInfo,
IN RPC_CLIENT_INTERFACE *InterfaceInfo
);
RPC_STATUS
AcquireCredentialsForTransport (
);
BOOL
SwapToken (
HANDLE *OldToken
);
void Unbind ();
virtual RPC_STATUS
SetTransportOption( unsigned long option,
ULONG_PTR optionValue );
virtual RPC_STATUS
InqTransportOption( unsigned long option,
ULONG_PTR * pOptionValue );
};
const unsigned int BindingListPresent = 1;
class OSF_CCONNECTION ;
enum CANCEL_STATE {
CANCEL_NOTREGISTERED = 0,
CANCEL_INFINITE,
CANCEL_NOTINFINITE
};
class OSF_CCALL : public CCALL
/*++
Class Description:
This class encapsulates an RPC call.
Fields:
PresentationContext - This field is only valid when there is a remote
procedure call in progress on this connection; it contains the
presentation context for the call.
DispatchTableCallback - This field is only valid when there is a remote
procedure call in progress on this connection; it contains the
dispatch table to use for callbacks.
Association - Contains a pointer to the association which owns this
connection.
TokenLength - Contains the maximum size of a token for the security
package being used by this connection; we need to keep track of
this for the third leg authentication case.
--*/
{
//
// This class will only access the AssociationKey member.
//
friend class OSF_CASSOCIATION;
friend class OSF_CCONNECTION;
friend class OSF_BINDING_HANDLE;
friend class OSF_CCALL_AVRF;
public:
OSF_CCALL_STATE CurrentState ;
private:
OSF_CCONNECTION *Connection ;
OSF_BINDING_HANDLE *BindingHandle;
int CallbackLevel;
// don't access the struct members directly - only through
// the access functions - this will ensure that the
// contents of the struct is properly checked. Async first
// calls on new connection have both elements valid if there
// are no preferences. Since this is the only case where
// this condition is true, we can use it as a flag.
// If AvailableBindingsList is set, the elements in it carry a refcount
// and SelectedBinding doesn't. If AvailableBindingsList is not set, then
// SelectedBinding carries a refcount.
struct
{
// NULL if no binding is selected
OSF_BINDING *SelectedBinding;
// this is the list of differning only by transfer syntax
// bindings this call can use. It can have one or more
// elements.
// This may be NULL if the call doesn't need a list
OSF_BINDING *AvailableBindingsList;
} Bindings;
void *CurrentBuffer ;
BOOL fDataLengthNegotiated;
int CurrentOffset ;
ULONG CurrentBufferLength ;
ULONG CallId;
UINT RcvBufferLength ;
BOOL FirstSend ;
PRPC_DISPATCH_TABLE DispatchTableCallback;
UINT MaximumFragmentLength;
// starts from 0, and set to non-zero if security is used after
// negotiating the bind
UINT MaxSecuritySize ;
UINT MaxDataLength;
int ProcNum ;
unsigned char *ReservedForSecurity ;
UINT SecBufferLength;
// When the call is created, set to 0, because we don't know whether
// there is object UUID or not. During GetBuffer we will know, and then
// we will set it properly. Starting from 0 allows the bind and GetBuffer
// threads (if different) to check and to synchronize the updating of the
// max fragment size, since it depends both on the object UUID and
// the security negotiation
UINT HeaderSize;
UINT AdditionalSpaceForSecurity;
ULONG SavedHeaderSize;
void * SavedHeader;
void * LastBuffer ;
EVENT SyncEvent ;
UINT ActualBufferLength;
UINT NeededLength;
void *CallSendContext;
INTERLOCKED_INTEGER fAdvanceCallCount;
BOOL fPeerChoked;
static const unsigned int IsPipeCallFlag = 0x01;
static const unsigned int MaxSecuritySizeUpdated = 0x02;
static const unsigned int IsAsyncPipeCall = 0x04;
static const unsigned int FreeLastBuffer = 0x08;
CompositeFlags Flags; // One of the above flags may be set.
public:
BOOL fLastSendComplete;
MUTEX CallMutex ;
int RecursiveCallsKey;
// the size of the non-pipe data. This is what goes out
// as AllocHint on the wire.
ULONG AllocHint;
//
// Indicates the call stack. Whenever a request message is sent or
// received, the stack is incremented. Likewise, whenever a response
// message is sent or received, the stack is decremented.
//
int CallStack;
BOOL fCallCancelled;
CANCEL_STATE CancelState;
private:
QUEUE BufferQueue ;
BOOL InReply;
BOOL fChoked;
OSF_CCALL (
RPC_STATUS * pStatus
);
public:
virtual~OSF_CCALL (
);
virtual RPC_STATUS
NegotiateTransferSyntax (
IN OUT PRPC_MESSAGE Message
);
virtual RPC_STATUS
GetBuffer (
IN OUT PRPC_MESSAGE Message,
IN UUID *ObjectUuid = 0
);
RPC_STATUS
GetBufferWithoutCleanup (
IN OUT PRPC_MESSAGE Message,
IN UUID *ObjectUuid
);
virtual RPC_STATUS
SendReceive (
IN OUT PRPC_MESSAGE Message
);
RPC_STATUS
SendReceiveHelper (
IN OUT PRPC_MESSAGE Message,
OUT BOOL *fRetry
);
virtual RPC_STATUS
Send (
IN PRPC_MESSAGE Message
);
virtual RPC_STATUS
Receive (
IN PRPC_MESSAGE Message,
IN UINT Size
);
virtual void
FreeBuffer (
IN PRPC_MESSAGE Message
);
virtual void
FreePipeBuffer (
IN PRPC_MESSAGE Message
);
virtual RPC_STATUS
ReallocPipeBuffer (
IN PRPC_MESSAGE Message,
IN UINT NewSize
);
virtual RPC_STATUS
AsyncSend (
IN OUT PRPC_MESSAGE Message
);
virtual RPC_STATUS
AsyncReceive (
IN OUT PRPC_MESSAGE Message,
IN UINT Size
);
virtual RPC_STATUS
SetAsyncHandle (
IN PRPC_ASYNC_STATE pAsync
) ;
virtual void
ProcessSendComplete (
IN RPC_STATUS EventStatus,
IN BUFFER Buffer
);
virtual RPC_STATUS
CancelAsyncCall (
IN BOOL fAbort
);
virtual void
FreeObject (
);
RPC_STATUS
SendHelper (
IN PRPC_MESSAGE Message,
OUT BOOL *fFirstSend
);
RPC_STATUS
SendData (
IN BUFFER Buffer
);
RPC_STATUS
SendMoreData (
IN BUFFER Buffer
);
RPC_STATUS
ActuallyAllocateBuffer (
OUT void * * Buffer,
IN UINT BufferLength
);
void
ActuallyFreeBuffer (
IN void * Buffer
);
//
// Actually perform the buffer allocation.
//
RPC_STATUS
GetBufferDo (
IN UINT culRequiredLength,
OUT void * * ppBuffer,
IN int fDataValid = 0,
IN int DataLength = 0
);
void
FreeBufferDo (
IN void *Buffer
);
RPC_STATUS
ActivateCall (
IN OSF_BINDING_HANDLE *BindingHandle,
IN OSF_BINDING *Binding,
IN OSF_BINDING *AvailableBindingsList,
IN ULONG CallIdToUse,
IN OSF_CCALL_STATE InitialCallState,
IN PRPC_DISPATCH_TABLE DispatchTable,
IN OSF_CCONNECTION *CConnection
);
void
FreeCCall (
IN RPC_STATUS Status
);
RPC_STATUS
SendCancelPDU(
);
RPC_STATUS
SendOrphanPDU (
);
RPC_STATUS
BindToServer (
BOOL fAsyncBind
);
RPC_STATUS
Cancel(
void * ThreadHandle
);
RPC_STATUS
InqWireIdForSnego (
OUT unsigned char *WireId
);
RPC_STATUS
BindingHandleToAsyncHandle (
OUT void **AsyncHandle
);
RPC_STATUS
InqMarshalledTargetInfo (
OUT unsigned long *MarshalledTargetInfoLength,
OUT unsigned char **MarshalledTargetinfo
);
// if fMultipleBindingsAvailable is set, the return value is a head of a linked
// list. If fMultipleBindingsAvailable is FALSE, only the element in the return
// value is meaningful
inline OSF_BINDING *
GetListOfAvaialbleBindings (
OUT BOOL *fMultipleBindingsAvailable
)
{
if (Bindings.AvailableBindingsList)
{
*fMultipleBindingsAvailable = TRUE;
return Bindings.AvailableBindingsList;
}
else
{
*fMultipleBindingsAvailable = FALSE;
return Bindings.SelectedBinding;
}
}
RPC_STATUS
BindCompleteNotify (
IN p_result_t *OsfResult,
IN int IndexOfPresentationContextAccepted,
OUT OSF_BINDING **BindingNegotiated
);
inline void EnterCallback(void)
{
CallbackLevel ++;
}
inline void ExitCallback(void)
{
CallbackLevel --;
}
inline BOOL IsCallInCallback(void)
{
return CallbackLevel > 0;
}
inline void
SetIsPipeCallFlag (
void
)
{
Flags.SetFlagInterlocked(IsPipeCallFlag);
}
inline BOOL
GetIsPipeCallFlag (
void
)
{
return Flags.GetFlag(IsPipeCallFlag);
}
// currently not used
inline void
ClearIsPipeCallFlag (
void
)
{
Flags.ClearFlagUnsafe(IsPipeCallFlag);
}
inline void
SetMaxSecuritySizeUpdatedFlag (
void
)
{
Flags.SetFlagInterlocked(MaxSecuritySizeUpdated);
}
inline BOOL
GetMaxSecuritySizeUpdatedFlag (
void
)
{
return Flags.GetFlag(MaxSecuritySizeUpdated);
}
// currently not used
inline void
ClearMaxSecuritySizeUpdatedFlag (
void
)
{
Flags.ClearFlagUnsafe(MaxSecuritySizeUpdated);
}
inline void
SetIsAsyncPipeCallFlag (
void
)
{
Flags.SetFlagInterlocked(IsAsyncPipeCall);
}
inline BOOL
GetIsAsyncPipeCallFlag (
void
)
{
return Flags.GetFlag(IsAsyncPipeCall);
}
inline void
SetFreeLastBufferFlag (
void
)
{
Flags.SetFlagInterlocked(FreeLastBuffer);
}
inline BOOL
GetFreeLastBufferFlag (
void
)
{
return Flags.GetFlag(FreeLastBuffer);
}
// Returns TRUE if the call object is for an async pipe call that
// is doing pulls and for which the notification is not armed.
// The user will do another pull for the call.
inline BOOL
IsAsyncPipeCallBeforePull (
void
)
{
return (GetIsAsyncPipeCallFlag() // This is an async pipe call
&& CurrentState == Receiving // it is in the pull stage
&& NeededLength == 0); // and the notification is not armed.
}
private:
void
SendFault (
IN RPC_STATUS Status,
IN int DidNotExecute
);
#define MAX_ALLOC_Hint 16*1024
RPC_STATUS
EatAuthInfoFromPacket (
IN rpcconn_request * Request,
IN OUT UINT * RequestLength
);
BOOL
ProcessReceivedPDU (
IN void *Buffer,
IN int BufferLength
);
RPC_STATUS
GetCoalescedBuffer (
IN PRPC_MESSAGE Message,
IN BOOL BufferValid
);
RPC_STATUS
SendAlterContextPDU (
);
RPC_STATUS
GetCoalescedBuffer(
IN PRPC_MESSAGE Message);
RPC_STATUS
FastSendReceive (
IN OUT PRPC_MESSAGE Message,
OUT BOOL *fRetry
);
RPC_STATUS
SendNextFragment (
IN unsigned char PacketType = rpc_request,
IN BOOL fFirstSend = TRUE,
OUT void **ReceiveBuffer = 0,
OUT UINT *ReceivedLength = 0
);
RPC_STATUS
ActuallyProcessPDU (
IN rpcconn_common *Packet,
IN UINT PacketLength,
IN OUT PRPC_MESSAGE Message,
IN BOOL fAsync = 0,
OUT BOOL *pfSubmitReceive = NULL
);
RPC_STATUS
ProcessResponse (
IN rpcconn_response *Packet,
IN PRPC_MESSAGE Message,
OUT BOOL *pfSubmitReceive
);
RPC_STATUS
ProcessRequestOrResponse (
IN rpcconn_request *Request,
IN UINT PacketLength,
IN BOOL fRequest,
IN PRPC_MESSAGE Message
);
RPC_STATUS
DealWithCallback (
IN rpcconn_request *Request,
IN PRPC_MESSAGE Message
);
RPC_STATUS
ReceiveReply (
IN rpcconn_request *Request,
IN PRPC_MESSAGE Message
);
void
CallFailed (
IN RPC_STATUS Status
) ;
int
QueueBuffer (
IN void *Buffer,
IN int BufferLength);
BOOL
IssueNotification (
IN RPC_ASYNC_EVENT Event = RpcCallComplete
);
RPC_STATUS ReserveSpaceForSecurityIfNecessary (void);
void UpdateObjectUUIDInfo (IN UUID *ObjectUuid);
void UpdateMaxFragLength (const IN ULONG AuthnLevel);
RPC_STATUS AutoRetryCall(IN OUT RPC_MESSAGE *Message, IN BOOL fSendReceivePath,
IN OSF_BINDING_HANDLE *LocalBindingHandle, IN RPC_STATUS CurrentStatus,
IN RPC_ASYNC_STATE *AsyncState OPTIONAL);
void CleanupOldCallOnAutoRetry(IN PVOID Buffer, IN BOOL fSendReceivePath,
IN RPC_STATUS CurrentStatus)
{
FreeBufferDo(Buffer);
if (fSendReceivePath)
FreeCCall(CurrentStatus);
else
{
//
// Remove the call reference, CCALL--
//
RemoveReference();
}
}
OSF_BINDING *GetSelectedBinding(void)
{
ASSERT(Bindings.SelectedBinding != NULL);
return Bindings.SelectedBinding;
}
OSF_BINDING *GetBindingList(void)
{
ASSERT(Bindings.AvailableBindingsList != NULL);
return Bindings.AvailableBindingsList;
}
void *
ActualBuffer (
IN void *Buffer
);
RPC_STATUS
CallCancelled (
OUT PDWORD Timeout
);
RPC_STATUS
RegisterCallForCancels (
);
void
UnregisterCallForCancels (
);
void * operator new (
size_t allocBlock,
unsigned int xtraBytes
);
RPC_STATUS
UpdateBufferSize (
IN OUT void **Buffer,
IN int CurrentBufferLength
);
inline BOOL
fOkToAdvanceCall()
{
return (fAdvanceCallCount.Increment() == 2);
}
virtual RPC_STATUS
InqSecurityContext (
OUT void **SecurityContextHandle
);
static RPC_STATUS
NegotiateTransferSyntaxAndGetBuffer (
IN OUT PRPC_MESSAGE Message,
IN RPC_SYNTAX_IDENTIFIER *OldTransferSyntax,
IN UUID *ObjectUuid
);
inline ULONG
GetBindingHandleTimeout (
IN OSF_BINDING_HANDLE *BindingToUse
)
{
RPC_STATUS RpcStatus;
ULONG_PTR OptionValue;
RpcStatus = BindingToUse->OSF_BINDING_HANDLE::InqTransportOption(
RPC_C_OPT_CALL_TIMEOUT,
&OptionValue);
ASSERT(RpcStatus == RPC_S_OK);
if (OptionValue == 0)
return INFINITE;
else
return (ULONG) OptionValue;
}
inline RPC_STATUS
GetStatusForTimeout (
IN OSF_BINDING_HANDLE *BindingHandleToUse,
IN RPC_STATUS Status,
BOOL fBindingHandleTimeoutUsed
)
{
if (Status == RPC_P_TIMEOUT)
{
if (fBindingHandleTimeoutUsed)
{
Status = RPC_S_CALL_CANCELLED;
RpcpErrorAddRecord(EEInfoGCRuntime,
Status,
EEInfoDLGetStatusForTimeout10,
RPC_P_TIMEOUT,
GetBindingHandleTimeout(BindingHandle));
}
else
{
Status = RPC_S_CALL_FAILED_DNE;
RpcpErrorAddRecord(EEInfoGCRuntime,
Status,
EEInfoDLGetStatusForTimeout20,
(ULONG)RPC_P_TIMEOUT,
(ULONG)RPC_C_SERVER_BIND_TIMEOUT);
}
}
return Status;
}
inline ULONG
GetEffectiveTimeoutForBind (
IN OSF_BINDING_HANDLE *BindingToUse,
OUT BOOL *fBindingHandleTimeoutUsed
)
{
ULONG Timeout;
Timeout = GetBindingHandleTimeout(BindingToUse);
if (Timeout > RPC_C_SERVER_BIND_TIMEOUT)
{
Timeout = RPC_C_SERVER_BIND_TIMEOUT;
*fBindingHandleTimeoutUsed = FALSE;
}
else
{
*fBindingHandleTimeoutUsed = TRUE;
}
return Timeout;
}
static const unsigned int VTHeaderSize = sizeof(rpc_sec_verification_trailer) + MAX_RPC_SEC_VT_ALIGN;
int SizeVerificationTrailer (
void
);
void AddVerificationTrailer (
IN RPC_MESSAGE *RpcMessage
);
rpc_sec_verification_trailer_command *AddVerificationTrailerHeader (
IN RPC_MESSAGE *RpcMessage
);
};
inline void *
OSF_CCALL::operator new (
size_t allocBlock,
unsigned int xtraBytes
)
{
I_RPC_HANDLE pvTemp = (I_RPC_HANDLE) new char[allocBlock + xtraBytes];
return(pvTemp);
}
inline void
OSF_CCALL::FreeObject (
)
{
if (AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
{
AsyncStatus = RPC_S_CALL_FAILED;
}
FreeCCall(AsyncStatus);
}
inline RPC_STATUS
OSF_CCALL::RegisterCallForCancels (
)
{
RPC_STATUS Status;
if (pAsync == 0)
{
Status = RegisterForCancels(this);
if (Status != RPC_S_OK)
{
return Status;
}
if (ThreadGetRpcCancelTimeout() == RPC_C_CANCEL_INFINITE_TIMEOUT)
{
CancelState = CANCEL_INFINITE;
}
else
{
CancelState = CANCEL_NOTINFINITE;
}
}
return RPC_S_OK;
}
inline void
OSF_CCALL::UnregisterCallForCancels (
)
{
if (pAsync == 0)
{
EVAL_AND_ASSERT(RPC_S_OK == UnregisterForCancels());
}
}
inline void *
OSF_CCALL::ActualBuffer (
IN void *Buffer
)
{
ASSERT (HeaderSize != 0);
if (UuidSpecified)
{
Buffer = (char *) Buffer - sizeof(rpcconn_request) - sizeof(UUID);
}
else
{
Buffer = (char *) Buffer - sizeof(rpcconn_request);
}
return Buffer;
}
inline int
OSF_CCALL::QueueBuffer (
IN void *Buffer,
IN int BufferLength
)
{
RcvBufferLength += BufferLength;
return BufferQueue.PutOnQueue(Buffer, BufferLength);
}
NEW_SDICT2(OSF_CCALL, PVOID);
class OSF_CCALL_AVRF : public OSF_CCALL
/*++
Class Description:
This class overwrites an OSF_CCALL for use with RPC verifier.
Methods will perform some checks.
--*/
{
public:
OSF_CCALL_AVRF(RPC_STATUS __RPC_FAR * pStatus) : OSF_CCALL(pStatus) {}
RPC_STATUS
GetBuffer (
IN OUT PRPC_MESSAGE Message,
IN UUID *ObjectUuid
);
};
#define SYNC_CONN_FREE 0
#define SYNC_CONN_BUSY -1
#define ASYNC_CONN_BUSY -2
#define ASYNC_CONN_FREE -3
enum CONNECTION_STATES
{
ConnUninitialized,
ConnAborted,
ConnOpen
};
const unsigned int FreshFromCache = 4;
const unsigned int TransInitialized = 8;
const unsigned int NoAssociationShutdown = 16;
enum FAILURE_COUNT_STATE
{
FailureCountUnknown,
FailureCountNotExceeded,
FailureCountExceeded
};
typedef enum tagConnectionSupportHeaderSign
{
cshsDontKnow, // = 0
cshsUnconfirmedNo, // = 1
cshsYes, // = 2
cshsConfirmedNo // = 3
} ConnectionSupportHeaderSign;
const unsigned int ConnectionSupportHeaderSignMask = 3;
class OSF_CCONNECTION : public REFERENCED_OBJECT
/*++
Class Description:
This class encapsulates a transport connection. The transport
connection may be used by one or more RPC calls. Each RPC
call is encapsulated by an CALL object. This object may
be exclusively used by a call. Each connection is owned by
exacly one thread (ie: all calls on a connection have been
initiated by a single thread).
Fields:
Association: Pointer to the association object
ConnectionKey: Key to our entry in the dictionary of connections in
the association.
ThreadId: Thread Id of the thread owning this call.
DceSecurityInfo - Contains information necessary for DCE security to
work properly. This includes the association uuid (a different
value for each connection), and sequence numbers (both directions).
ThirdLegAuthNeeded - Contains a flag indicating whether or not third
leg authentication is needed; a non-zero value indicates that it
is needed.
ClientSecurityContext - Optionally contains the security context being
used for this connection.
AdditionalSpaceForSecurity - Contains the amount of space to save
for security in each buffer we allocate.
LastTimeUsed - Contains the time in seconds when this connection was
last used.
CurrentCall - The call on which we are currently **sending** data
ClientInfo - Contains the pointers to the loadable transport routines
for the transport type of this connection.
fConnectionAborted - If this field is non-zero it indicates that the
connection has been aborted, meaning that any attempts to send
or receive data on the connection will fail.
--*/
{
friend class OSF_CASSOCIATION;
friend class OSF_CCALL;
friend class OSF_BINDING_HANDLE;
friend class OSF_CCALL_AVRF;
private:
OSF_CASSOCIATION * Association;
OSF_CCALL *CurrentCall ;
int ConnectionKey;
CONNECTION_STATES State;
unsigned char WireAuthId;
unsigned short MaxFrag;
ULONG ThreadId ;
BOOL CachedCCallAvailable ;
ULONG MaxSavedHeaderSize;
OSF_CCALL *CachedCCall ;
ULONG SavedHeaderSize;
unsigned int ComTimeout ;
void * SavedHeader;
BOOL AdditionalLegNeeded;
ULONG LastTimeUsed;
UINT TokenLength;
UINT AdditionalSpaceForSecurity;
BOOL fIdle ;
BOOL fExclusive ;
BOOL fConnectionAborted;
// ConnectionSupportHeaderSign transitions are as follows
//
// cshsDontKnow
// |
// +------------------------+----------------------+
// | |
// cshsYes cshsUnconfirmedNo
// |
// cshsConfirmedNo
//
// We start with cshsDontKnow. If first bind returns that the server supports signing,
// we go to cshsYes. If we don't get this, we don't know for sure yet (it may be a
// downgrade attack), so we move to cshsUnconfirmedNo. The first call that succeeds
// will make that a cshsConfirmedNo. We know new server will blow away all calls that
// indicate client supports signing but isn't doing it so the first successful call
// with verification trailer indicates negotiation is completed.
// All transitions will be called from a single thread only, except cshsUnconfirmedNo ->
// cshsConfirmedNo. For the last transition, we must use interlocks as it potentially
// races with ClearFreshFromCacheFlag.
CompositeFlags Flags;
BITSET Bindings;
QUEUE CallQueue ;
MUTEX ConnMutex ;
OSF_CCALL_DICT2 ActiveCalls ;
SECURITY_CONTEXT ClientSecurityContext;
RPC_CONNECTION_TRANSPORT * ClientInfo;
union
{
void *ConnSendContext ;
OSF_CCONNECTION *NextConnection; // used to link connections in some case
} u;
DCE_SECURITY_INFO DceSecurityInfo;
void *BufferToFree;
BOOL ConnectionReady;
BOOL fSeparateConnection;
public:
OSF_CCONNECTION (
IN OSF_CASSOCIATION *Association,
IN RPC_CONNECTION_TRANSPORT * RpcClientInfo,
IN unsigned int Timeout,
IN CLIENT_AUTH_INFO * myAuthInfo,
IN BOOL fExclusive,
IN BOOL fSeparateConnection,
OUT RPC_STATUS * pStatus
);
virtual ~OSF_CCONNECTION (
);
virtual void
ProcessSendComplete (
IN RPC_STATUS EventStatus,
IN BUFFER Buffer
);
RPC_STATUS
TransInitialize (
IN RPC_CHAR *NetworkAddress,
IN RPC_CHAR *NetworkOptions
)
{
if (ClientInfo->Initialize)
{
return ClientInfo->Initialize(TransConnection(),
NetworkAddress,
NetworkOptions,
(fExclusive == 0));
}
return (RPC_S_OK);
}
void
TransInitComplete (
)
{
if (ClientInfo->InitComplete)
{
ClientInfo->InitComplete(TransConnection());
}
}
RPC_STATUS
TransOpen (
IN OSF_BINDING_HANDLE * BindingHandle,
IN RPC_CHAR * RpcProtocolSequence,
IN RPC_CHAR * NetworkAddress,
IN RPC_CHAR * Endpoint,
IN RPC_CHAR * NetworkOptions,
IN void *ResolverHint,
IN BOOL fHintInitialized,
IN ULONG Timeout
) ;
RPC_STATUS
TransReceive (
OUT void * * Buffer,
OUT unsigned int * BufferLength,
IN ULONG Timeout
);
RPC_STATUS
TransSend (
IN OSF_BINDING_HANDLE * BindingHandle, OPTIONAL
IN void * Buffer,
IN unsigned int BufferLength,
IN BOOL fDisableShutdownCheck,
IN BOOL fDisableCancelCheck,
IN ULONG Timeout
);
#ifdef WIN96
RPC_STATUS
TransClose (
);
#endif
RPC_STATUS
TransSendReceive (
IN OSF_BINDING_HANDLE * BindingHandle, OPTIONAL
IN void * SendBuffer,
IN unsigned int SendBufferLength,
OUT void * * ReceiveBuffer,
OUT unsigned int * ReceiveBufferLength,
IN ULONG Timeout
);
RPC_STATUS
TransAsyncSend (
IN OSF_BINDING_HANDLE * BindingHandle, OPTIONAL
IN void * SendBuffer,
IN unsigned int SendBufferLength,
IN void *SendContext
) ;
RPC_STATUS
TransAsyncReceive (
) ;
RPC_STATUS
TransPostEvent (
IN PVOID Context
) ;
void
TransAbortConnection (
);
void
TransClose (
);
unsigned int
TransMaximumSend (
);
unsigned int
GuessPacketLength (
);
void * operator new (
size_t allocBlock,
unsigned int xtraBytes
);
RPC_STATUS
TransGetBuffer (
OUT void * * Buffer,
IN UINT BufferLength
);
void
TransFreeBuffer (
IN void * Buffer
);
RPC_STATUS
TransReallocBuffer (
IN OUT void * * Buffer,
IN UINT OldSize,
IN UINT NewSize
);
RPC_STATUS
AllocateCCall (
OUT OSF_CCALL **CCall
);
RPC_STATUS
AddCall (
IN OSF_CCALL *CCall
);
void
FreeCCall (
IN OSF_CCALL *CCall,
IN RPC_STATUS Status,
IN ULONG ComTimeout
);
RPC_STATUS
OpenConnectionAndBind (
IN OSF_BINDING_HANDLE *BindingHandle,
IN ULONG Timeout,
IN BOOL fAlwaysNegotiateNDR20,
OUT FAILURE_COUNT_STATE *fFailureCountExceeded OPTIONAL
);
RPC_STATUS
ActuallyDoBinding (
IN OSF_CCALL *CCall,
IN ULONG MyAssocGroupId,
IN BOOL fNewConnection,
IN ULONG Timeout,
OUT OSF_BINDING **BindingNegotiated,
OUT BOOL *fPossibleAssociationReset,
OUT FAILURE_COUNT_STATE *fFailureCountExceeded OPTIONAL
);
RPC_STATUS
SendBindPacket (
IN OSF_BINDING_HANDLE * BindingHandle, OPTIONAL
IN BOOL fInitialPass,
IN OSF_CCALL *Call,
IN ULONG AssocGroup,
IN unsigned char PacketType,
IN ULONG Timeout,
IN BOOL fAsync = 1,
OUT rpcconn_common * * Buffer = 0,
OUT UINT * BufferLength = 0,
IN rpcconn_common * InputPacket = 0,
IN unsigned int InputPacketLength = 0
);
RPC_STATUS
MaybeDo3rdLegAuth (
IN void * Buffer,
IN UINT BufferLength
);
//
// Set the value of the max frag for the connection.
//
void
SetMaxFrag (
IN unsigned short max_xmit_frag,
IN unsigned short max_recv_frag
);
UINT
InqMaximumFragmentLength (
);
inline int
AddPContext (
IN int PresentContext
);
inline void
DeletePContext (
IN int PresentContext
);
int
SupportedPContext (
IN int *PresentationContexts,
IN int NumberOfPresentationContexts,
OUT int *PresentationContextSupported
);
RPC_STATUS
SupportedAuthInfo (
IN CLIENT_AUTH_INFO * ClientAuthInfo,
IN NamedPipeType NPType,
IN BOOL IsExclusiveConnection,
OUT BOOL *Supported
);
RPC_STATUS
SendFragment (
IN rpcconn_common *pFragment,
IN OSF_CCALL *CCall,
IN UINT LastFragmentFlag,
IN UINT HeaderSize,
IN UINT MaxSecuritySize,
IN UINT DataLength,
IN UINT MaximumFragmentLength,
IN unsigned char *ReservedForSecurity,
IN BOOL fAsync,
IN void *SendContext,
IN ULONG Timeout,
OUT void **ReceiveBuffer,
OUT UINT *ReceiveBufferLength
);
void
ProcessReceiveComplete (
IN RPC_STATUS EventStatus,
IN BUFFER Buffer,
IN UINT BufferLength
);
ULONG
InquireSendSequenceNumber (
);
ULONG
InquireReceiveSequenceNumber (
);
RPC_CHAR *InqEndpoint(void);
RPC_CHAR *InqNetworkAddress(void);
void
IncSendSequenceNumber (
);
inline void
IncReceiveSequenceNumber (
);
void
NotifyCallDeleted (
);
void
SetLastTimeUsedToNow (
);
ULONG
InquireLastTimeUsed (
);
ULONG
GetAssocGroupId (
);
void
ConnectionAborted (
IN RPC_STATUS Status,
IN BOOL fShutdownAssoc = 1
);
void
AdvanceToNextCall (
);
RPC_STATUS
AddActiveCall (
IN ULONG CallId,
IN OSF_CCALL *CCall
);
RPC_STATUS
DealWithAlterContextResp (
IN OSF_CCALL *CCall,
IN rpcconn_common *Packet,
IN int PacketLength,
IN OUT BOOL *AlterContextToNDR20IfNDR64Negotiated
);
void
MakeConnectionIdle (
);
void
MakeConnectionActive (
);
BOOL
IsIdle (
);
void
DeleteConnection (
);
BOOL IsExclusive (void)
{
return fExclusive;
}
RPC_STATUS
ValidateHeader(
rpcconn_common * Buffer,
unsigned long BufferLength
);
RPC_STATUS
FinishSecurityContextSetup (
IN OSF_CCALL *Call,
IN unsigned long AssocGroup,
OUT rpcconn_common * * Buffer,
OUT unsigned int * BufferLength,
IN ULONG Timeout
);
RPC_STATUS
CallCancelled (
OUT PDWORD Timeout
);
void
WaitForSend(
);
BOOL
MatchModifiedId (
LUID *pModifiedId
)
{
if (ClientSecurityContext.DefaultLogonId)
{
return FALSE;
}
return (FastCompareLUIDAligned(pModifiedId, &ClientSecurityContext.ModifiedId));
}
void
MaybeAdvanceToNextCall(
OSF_CCALL *Call
)
{
if (fExclusive == 0
&& CurrentCall == Call)
{
AdvanceToNextCall();
}
}
inline void SetFreshFromCacheFlag(void)
{
Flags.SetFlagUnsafe(FreshFromCache);
}
inline void ClearFreshFromCacheFlag(void)
{
Flags.ClearFlagInterlocked(FreshFromCache);
}
inline BOOL GetFreshFromCacheFlag(void)
{
return Flags.GetFlag(FreshFromCache);
}
inline void SetTransInitializedFlag(void)
{
Flags.SetFlagUnsafe(TransInitialized);
}
inline void ClearTransInitializedFlag(void)
{
Flags.ClearFlagInterlocked(TransInitialized);
}
inline BOOL GetTransInitializedFlag(void)
{
return Flags.GetFlag(TransInitialized);
}
inline ConnectionSupportHeaderSign
GetConnectionSupportHeaderSign (
void
)
{
return (ConnectionSupportHeaderSign)Flags.GetFlag(ConnectionSupportHeaderSignMask);
}
inline void
SetConnectionSupportHeaderSignUnsafe (
ConnectionSupportHeaderSign NewConnectionSupportHeaderSign
)
{
Flags.SetFlagUnsafe(NewConnectionSupportHeaderSign);
}
inline void
SetConnectionSupportHeaderSignInterlocked (
ConnectionSupportHeaderSign NewConnectionSupportHeaderSign
)
{
Flags.SetFlagInterlocked(NewConnectionSupportHeaderSign);
}
inline void
InitConnectionSupportHeaderSign (
void
)
{
Flags.SetFlagUnsafe(cshsDontKnow);
}
inline void
SuccessfulResponseReceived (
void
)
{
if (GetConnectionSupportHeaderSign() == cshsUnconfirmedNo)
{
SetConnectionSupportHeaderSignInterlocked (cshsConfirmedNo);
}
}
static void
OsfDeleteIdleConnections (
void
);
RPC_STATUS
TurnOnOffKeepAlives (
IN BOOL TurnOn,
IN ULONG Timeout
);
inline BOOL
IsVerificationTrailerNecessary (
void
)
{
return ((ClientSecurityContext.AuthenticationLevel >= RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
&& (InqNetworkAddress() != NULL)
&& (*(InqNetworkAddress()) != 0)
);
}
inline BOOL
IsSChannel (
void
)
{
return (ClientSecurityContext.AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL);
}
private:
inline void
InitializeWireAuthId (
IN CLIENT_AUTH_INFO * ClientAuthInfo
)
{
if (ClientAuthInfo)
WireAuthId = (unsigned char) ClientAuthInfo->AuthenticationService;
else
WireAuthId = RPC_C_AUTHN_NONE;
}
};
inline void *
OSF_CCONNECTION::operator new (
size_t allocBlock,
unsigned int xtraBytes
)
{
I_RPC_HANDLE pvTemp = (I_RPC_HANDLE) new char[allocBlock + xtraBytes];
return(pvTemp);
}
#pragma optimize ("t", on)
inline void
OSF_CCONNECTION::MakeConnectionIdle (
)
{
LogEvent(SU_CCONN, EV_STOP, this, 0, 0, 1);
fIdle = 1;
}
inline void
OSF_CCONNECTION::MakeConnectionActive (
)
{
LogEvent(SU_CCONN, EV_START, this, 0, 0, 1);
fIdle = 0;
}
inline BOOL
OSF_CCONNECTION::IsIdle (
)
{
return fIdle;
}
inline void
OSF_CCONNECTION::NotifyCallDeleted (
)
{
}
inline void
OSF_CCONNECTION::IncSendSequenceNumber (
)
{
DceSecurityInfo.ReceiveSequenceNumber += 1;
}
inline void
OSF_CCONNECTION::IncReceiveSequenceNumber (
)
{
DceSecurityInfo.ReceiveSequenceNumber += 1;
}
inline ULONG
OSF_CCONNECTION::InquireSendSequenceNumber (
)
{
return DceSecurityInfo.SendSequenceNumber ;
}
inline ULONG
OSF_CCONNECTION::InquireReceiveSequenceNumber (
)
{
return DceSecurityInfo.ReceiveSequenceNumber ;
}
inline UINT
OSF_CCONNECTION::InqMaximumFragmentLength (
)
/*++
Return Value:
The maximum fragment length negotiated for this connection will be
returned.
--*/
{
return(MaxFrag);
}
#pragma optimize("", on)
inline void
OSF_CCONNECTION::SetLastTimeUsedToNow (
)
/*++
Routine Description:
We the the last time that this connection was used to now.
--*/
{
LastTimeUsed = NtGetTickCount();
}
inline ULONG
OSF_CCONNECTION::InquireLastTimeUsed (
)
/*++
Return Value:
The last time this connection was used will be returned.
--*/
{
return(LastTimeUsed);
}
inline RPC_STATUS
OSF_CCALL::InqSecurityContext (
OUT void **SecurityContextHandle
)
{
*SecurityContextHandle = Connection->ClientSecurityContext.InqSecurityContext();
return RPC_S_OK;
}
inline RPC_STATUS
OSF_CCALL::InqWireIdForSnego (
OUT unsigned char *WireId
)
{
if ((Connection->ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
|| (Connection->ClientSecurityContext.AuthenticationService == RPC_C_AUTHN_NONE))
return RPC_S_INVALID_BINDING;
return Connection->ClientSecurityContext.GetWireIdForSnego(WireId);
}
inline RPC_STATUS
OSF_CCALL::BindingHandleToAsyncHandle (
OUT void **AsyncHandle
)
{
if (pAsync == 0)
return RPC_S_INVALID_BINDING;
*AsyncHandle = pAsync;
return RPC_S_OK;
}
inline RPC_STATUS
OSF_CCALL::InqMarshalledTargetInfo (
OUT unsigned long *MarshalledTargetInfoLength,
OUT unsigned char **MarshalledTargetInfo
)
{
if ((Connection->ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
|| (Connection->ClientSecurityContext.AuthenticationService == RPC_C_AUTHN_NONE))
return RPC_S_INVALID_BINDING;
return Connection->ClientSecurityContext.InqMarshalledTargetInfo(MarshalledTargetInfoLength,MarshalledTargetInfo);
}
class OSF_BINDING : public MTSyntaxBinding
{
public:
OSF_BINDING (
IN RPC_SYNTAX_IDENTIFIER *InterfaceId,
IN TRANSFER_SYNTAX_STUB_INFO *TransferSyntaxInfo,
IN int CapabilitiesBitmap
) : MTSyntaxBinding(InterfaceId, TransferSyntaxInfo, CapabilitiesBitmap),
RefCount (1)
{
}
inline void SetNextBinding(OSF_BINDING *Next)
{
MTSyntaxBinding::SetNextBinding(Next);
}
inline OSF_BINDING *GetNextBinding(void)
{
return (OSF_BINDING *)(MTSyntaxBinding::GetNextBinding());
}
inline int CompareWithTransferSyntax (IN const p_syntax_id_t *TransferSyntax)
{
return CompareWithTransferSyntax ((RPC_SYNTAX_IDENTIFIER *)TransferSyntax);
}
inline int CompareWithTransferSyntax (IN const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
{
return MTSyntaxBinding::CompareWithTransferSyntax ((RPC_SYNTAX_IDENTIFIER *)TransferSyntax);
}
// N.B. IsCapabilityBitmapReset is used as flag for the lifetime reference.
// Whenever we take away the lifetime reference, we reset the capabilities bitmap
// and we subsequently use IsCapabilityBitmapReset to test whether the lifetime
// reference has been taken away. This allows us to not add another member to
// OSF_BINDING and save a data member per object.
void AddReference (
void
)
{
int Count;
// make sure we don't just make up refcounts
// out of thin air
ASSERT(RefCount.GetInteger() > 0);
// make sure the number of refcounts stays reasonable
ASSERT(RefCount.GetInteger() < 10000);
Count = RefCount.Increment();
LogEvent(SU_REFOBJ, EV_INC, this, IntToPtr(0x33), Count, 1, 1);
}
void RemoveReference (
void
)
{
int Count;
LogEvent(SU_REFOBJ, EV_DEC, this, IntToPtr(0x33), RefCount.GetInteger(), 1, 1);
Count = RefCount.Decrement();
ASSERT(Count >= 0);
if (0 == Count)
{
// we just mark the binding as invalid. It will be picked and destroyed
// next time we iterate the binding list.
ResetCapabilityBitmap();
}
}
BOOL IsRefCountZero (
void
)
{
return (RefCount.GetInteger() == 0);
}
inline void
SetPContextVerifiedFlag (
void
)
{
Flags.SetFlagUnsafe(PContextVerified);
}
inline BOOL
GetPContextVerifiedFlag (
void
)
{
return Flags.GetFlag(PContextVerified);
}
inline void
ClearPContextVerifiedFlag (
void
)
{
Flags.ClearFlagUnsafe(PContextVerified);
}
private:
INTERLOCKED_INTEGER RefCount;
const static unsigned int PContextVerified = 1;
// can be PContextVerified. As long as it is the only flag, it may be operated
// unsafely since it only goes from clear to set. If we add new flags, we must
// switch to interlocks since this is accessed from multiple threads.
CompositeFlags Flags;
};
NEW_SDICT(OSF_BINDING);
NEW_SDICT(OSF_CCONNECTION);
enum MPX_TYPES
{
mpx_unknown,
mpx_yes,
mpx_no
};
NEW_SDICT(RPC_TOKEN);
class OSF_CASSOCIATION : public REFERENCED_OBJECT
/*++
Class Description:
Fields:
MaintainContext - Contains a flag indicating whether or not this
association needs to keep at least one connection open with
the server if at all possible. A non-zero value indicates that
at least one connection should be kept open.
CallIdCounter - Contains an interlocked integer used to allocate
unique call identifiers.
BindHandleCount - Counts the number of OSF_BINDING_HANDLEs using
this association. This particular variable is operated
with interlocks. However, adding a refcount if you don't have
one (as in FindOrCreateAssociation - through the global data
structure) requires holding AssocDictMutex.
--*/
{
friend class OSF_CCONNECTION;
friend class OSF_CCALL;
friend class OSF_BINDING_HANDLE;
friend class OSF_CCALL_AVRF;
private:
DCE_BINDING * DceBinding;
INTERLOCKED_INTEGER BindHandleCount;
ULONG AssocGroupId;
OSF_BINDING_DICT Bindings;
OSF_CCONNECTION_DICT ActiveConnections;
TRANS_INFO *TransInfo ;
unsigned char * SecondaryEndpoint;
int Key;
UINT OpenConnectionCount;
UINT ConnectionsDoingBindCount;
BOOL fPossibleServerReset;
UINT MaintainContext;
ULONG CallIdCounter;
MUTEX AssociationMutex;
BOOL AssociationValid;
// in some cases we will decide that the association is dead,
// and we will mark it as such so that other calls can
// quickly fail instead of banging against a dead server.
// The error with which the association was shutdown is
// stored here. Callers that implement quick failure detection
// can read it off here. This is valid only if
// AssociationValid == FALSE.
RPC_STATUS AssociationShutdownError;
BOOL DontLinger;
BOOL ResolverHintInitialized;
// protected by the AssociationMutex
BOOL fIdleConnectionCleanupNeeded;
int FailureCount;
MPX_TYPES fMultiplex;
unsigned long SavedDrep;
RPC_TOKEN_DICT TokenDict;
union
{
struct
{
// TRUE if this is an association without binding handle
// references to it (i.e. it is lingered), FALSE
// otherwise. Protected by the AssocDictMutex
BOOL fAssociationLingered;
// The timestamp for garbage collecting this item. Defined
// only if fAssociationLingered == TRUE. Protected by the
// AssocDictMutex
DWORD Timestamp;
} Linger;
// this arm of the union is used only during destruction - never use
// it outside
OSF_CASSOCIATION *NextAssociation;
};
// if non-zero, it means that the resolved endpoint to the server was
// mutually authenticated using the endpoint mapper. Zero otherwise.
// Protected by the AssocDictMutex.
BOOL LocalMASet;
public:
OSF_CASSOCIATION (
IN DCE_BINDING * DceBinding,
IN TRANS_INFO *TransInfo,
IN OUT RPC_STATUS * RpcStatus
);
~OSF_CASSOCIATION (
);
public:
#if 0
void
CleanupAuthenticatedConnections(
IN CLIENT_AUTH_INFO *ClientAuthInfo
);
#endif
void
UnBind ( // Decrement the BindingCount, and clean up the
// association if it reaches zero.
);
RPC_STATUS
FindOrCreateOsfBinding (
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
IN RPC_MESSAGE *Message,
OUT int *NumberOfBindings,
IN OUT OSF_BINDING *BindingsForThisInterface[]
);
BOOL
DoesBindingForInterfaceExist (
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
);
RPC_STATUS
AllocateCCall (
IN OSF_BINDING_HANDLE *BindingHandle,
IN PRPC_MESSAGE Message,
IN CLIENT_AUTH_INFO * ClientAuthInfo,
OUT OSF_CCALL ** CCall,
OUT BOOL *fBindingHandleReferenceRemoved
);
private:
RPC_STATUS
ProcessBindAckOrNak (
IN rpcconn_common *Buffer,
IN UINT BufferLength,
IN OSF_CCONNECTION *CConnection,
IN OSF_CCALL *CCall,
OUT ULONG *NewGroupId,
OUT OSF_BINDING **BindingNegotiated,
OUT FAILURE_COUNT_STATE *fFailureCountExceeded OPTIONAL
);
RPC_STATUS
LookForExistingConnection (
IN OSF_BINDING_HANDLE *BindingHandle,
IN BOOL fExclusive,
IN CLIENT_AUTH_INFO *ClientAuthInfo,
IN int *PresentContext,
IN int NumberOfPresentationContexts,
OUT OSF_CCONNECTION **NewConnection,
OUT int *PresentationContextSupported,
OUT OSF_CCALL_STATE *InitialCallState,
IN BOOL fNonCausal
);
inline void
ClearIdleConnectionCleanupFlag (
void
)
{
AssociationMutex.VerifyOwned();
if (fIdleConnectionCleanupNeeded)
{
fIdleConnectionCleanupNeeded = FALSE;
if (InterlockedDecrement(&PeriodicGarbageCollectItems) == 0)
{
#if defined (RPC_GC_AUDIT)
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) PeriodicGarbageCollectItems dropped to 0 (a)\n",
GetCurrentProcessId(), GetCurrentProcessId());
#endif
}
}
}
public:
int
CompareWithDceBinding (
IN DCE_BINDING * DceBinding,
OUT BOOL *fOnlyEndpointDifferent
);
//
// Note, whoever calls this routine must have already
// requested the AssociationDictMutex.
//
void
IncrementCount (
void
)
{
LogEvent(SU_CASSOC, EV_INC, this, (PVOID)2, BindHandleCount.GetInteger(), 1, 0);
BindHandleCount.Increment();
}
void
ShutdownRequested (
IN RPC_STATUS AssociationShutdownError OPTIONAL,
IN OSF_CCONNECTION *ExemptConnection OPTIONAL
);
inline OSF_BINDING *
FindBinding (
IN int PresentContext
)
{
return(Bindings.Find(PresentContext));
}
void FreeAllBindings (
void
);
void DestroyBinding (
IN OSF_BINDING *Binding
);
virtual RPC_STATUS
ToStringBinding (
OUT RPC_CHAR * * StringBinding,
IN RPC_UUID * ObjectUuid
);
OSF_CCONNECTION *
FindIdleConnection (
void
);
void
MaintainingContext (
);
DCE_BINDING *
DuplicateDceBinding (
);
BOOL
IsValid (
);
BOOL
ConnectionAborted (
IN OSF_CCONNECTION *Connection
);
void
NotifyConnectionOpen (
);
void
NotifyConnectionClosed (
);
void NotifyConnectionBindInProgress (
void
);
void NotifyConnectionBindCompleted (
void
);
void * operator new (
size_t allocBlock,
unsigned int xtraBytes
);
int
CompareResolverHint (
void *Hint
);
void *
InqResolverHint (
);
void
SetResolverHint (
void *Hint
);
void
FreeResolverHint (
void *Hint
);
inline BOOL
IsResolverHintSynchronizationNeeded (
void
);
inline void
ResetAssociation (
)
{
AssociationMutex.VerifyOwned();
AssocGroupId = 0;
LocalMASet = FALSE;
if (ResolverHintInitialized)
{
ResolverHintInitialized = FALSE;
FreeResolverHint(InqResolverHint());
}
}
BOOL
IsAssociationReset ( void )
{
return (AssocGroupId == 0);
}
RPC_STATUS
FindOrCreateToken (
IN HANDLE hToken,
IN LUID *pLuid,
OUT RPC_TOKEN **ppToken,
OUT BOOL *pfTokenFound
);
void
ReferenceToken(
IN RPC_TOKEN *pToken
);
void
DereferenceToken(
IN RPC_TOKEN *pToken
);
void
CleanupConnectionList(
IN RPC_TOKEN *pToken
);
static void
OsfDeleteLingeringAssociations (
void
);
inline BOOL
GetDontLingerState (
void
)
{
return DontLinger;
}
inline void
SetDontLingerState (
IN BOOL DontLinger
)
{
ASSERT(DontLinger == TRUE);
this->DontLinger = DontLinger;
}
};
inline int
OSF_CASSOCIATION::CompareResolverHint (
void *Hint
)
{
RPC_CONNECTION_TRANSPORT *ClientInfo =
(RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
if (ClientInfo->CompareResolverHint)
{
return ClientInfo->CompareResolverHint(TransResolverHint(), Hint);
}
else
{
return RpcpMemoryCompare(TransResolverHint(), Hint, ClientInfo->ResolverHintSize);
}
}
inline void *
OSF_CASSOCIATION::InqResolverHint (
)
{
return TransResolverHint();
}
inline void
OSF_CASSOCIATION::SetResolverHint (
void *Hint
)
{
RPC_CONNECTION_TRANSPORT *ClientInfo =
(RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
if (ClientInfo->CopyResolverHint)
{
if (TransResolverHint() != Hint)
{
ClientInfo->CopyResolverHint(TransResolverHint(),
Hint,
TRUE // SourceWillBeAbandoned
);
}
}
else
{
RpcpMemoryCopy(TransResolverHint(), Hint, ClientInfo->ResolverHintSize);
}
}
inline void
OSF_CASSOCIATION::FreeResolverHint (
void *Hint
)
{
RPC_CONNECTION_TRANSPORT *ClientInfo =
(RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
if (ClientInfo->FreeResolverHint)
{
ClientInfo->FreeResolverHint(Hint);
}
}
BOOL
OSF_CASSOCIATION::IsResolverHintSynchronizationNeeded (
void
)
{
RPC_CONNECTION_TRANSPORT *ClientInfo =
(RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
return (ClientInfo->FreeResolverHint != NULL);
}
inline void *
OSF_CASSOCIATION::operator new (
size_t allocBlock,
unsigned int xtraBytes
)
{
I_RPC_HANDLE pvTemp = (I_RPC_HANDLE) new char[allocBlock + xtraBytes];
return(pvTemp);
}
inline BOOL
OSF_CASSOCIATION::IsValid (
)
{
return AssociationValid ;
}
inline void
OSF_CASSOCIATION::MaintainingContext (
)
/*++
Routine Description:
This routine is used to indicate that a binding handle using this
association is maintaining context with the server. This means
that at least one connection for this association must always be
open.
--*/
{
MaintainContext = 1;
}
inline DCE_BINDING *
OSF_CASSOCIATION::DuplicateDceBinding (
)
{
return(DceBinding->DuplicateDceBinding());
}
inline ULONG
OSF_CCONNECTION::GetAssocGroupId (
)
{
return Association->AssocGroupId ;
}
inline void
OSF_CCONNECTION::WaitForSend (
)
{
while (ConnectionReady == 0)
{
//
// We need a listening thread
// so the send can complete
//
Association->TransInfo->CreateThread();
Sleep(10);
}
ASSERT(ConnectionReady == 1);
ConnectionReady = 0;
}
inline void
OSF_CCONNECTION::DeleteConnection (
)
{
if (fExclusive == 0)
{
TransAbortConnection();
}
Delete();
}
inline RPC_CHAR *OSF_CCONNECTION::InqEndpoint(void)
{
return Association->DceBinding->InqEndpoint();
}
inline RPC_CHAR *OSF_CCONNECTION::InqNetworkAddress(void)
{
return Association->DceBinding->InqNetworkAddress();
}
inline int
OSF_CCONNECTION::AddPContext (
IN int PresentContext
)
{
Association->AssociationMutex.VerifyOwned();
return(Bindings.Insert(PresentContext));
}
inline void
OSF_CCONNECTION::DeletePContext (
IN int PresentContext
)
{
Association->AssociationMutex.VerifyOwned();
Bindings.Delete(PresentContext);
}
inline int
OSF_CCONNECTION::SupportedPContext (
IN int *PresentationContexts,
IN int NumberOfPresentationContexts,
OUT int *PresentationContextSupported
)
/*++
Return Value:
Non-zero will be returned if this connection supports the supplied
presentation context; otherwise, zero will be returned.
--*/
{
int i;
int Result = 0;
Association->AssociationMutex.VerifyOwned();
ASSERT(NumberOfPresentationContexts);
for (i = 0; i < NumberOfPresentationContexts; i ++)
{
Result = Bindings.MemberP(PresentationContexts[i]);
if (Result)
{
*PresentationContextSupported = i;
break;
}
}
return Result;
}
inline void
OSF_BINDING_HANDLE::Unbind ()
{
BOOL fMutexTaken;
// try to take the two mutexes, but if fail on the second, release
// the first as well and retry, because there is a potential
// deadlock condition for which this is a workaround
while (TRUE)
{
AssocDictMutex->Request();
fMutexTaken = Association->AssociationMutex.TryRequest();
if (fMutexTaken)
break;
else
{
AssocDictMutex->Clear();
Sleep(10);
}
}
if (pToken)
{
Association->DereferenceToken(pToken);
pToken = 0;
}
// unbind will clear the association dict mutex
// and the association mutex.
// If the association is not lingered, it may be freed.
// We can't touch Association after this point.
Association->UnBind();
Association = 0;
}
RPC_STATUS
LoadableTransportClientInfo (
IN RPC_CHAR * DllName,
IN RPC_CHAR * RpcProtocolSequence,
OUT TRANS_INFO * *ClientTransInfo
);
TRANS_INFO *
GetLoadedClientTransportInfoFromId (
IN unsigned short TransportId
);
void ReleaseBindingListWithException (
IN OSF_BINDING *ExemptBinding, OPTIONAL
IN OSF_BINDING *BindingList
);
inline void ReleaseBindingList (
IN OSF_BINDING *BindingList
)
/*++
Routine Description:
Removes a refcount on all bindings in the list.
Arguments:
BindingList - the list of bindings.
Return Value:
--*/
{
return ReleaseBindingListWithException(NULL, // ExemptBinding
BindingList
);
}
RPC_STATUS SetAuthInformation (
IN RPC_BINDING_HANDLE BindingHandle,
IN CLIENT_AUTH_INFO *AuthInfo
);
// --------------------------------------------------------------------
#endif // __OSFCLNT_HXX__