/*++ b Copyright (C) Microsoft Corporation, 1993 - 1999 Module Name: dgclnt.hxx Abstract: This file contains the definitions used by the datagram client. Revision History: NT 3.5 was the first version shipped, supporting IPX and UDP. (connieh) NT 3.51 added secure calls over NTLM and DEC Kerberos. (jroberts) NT 4.0 added sliding window, larger packet sizes, cancels. (jroberts) NT 5.0 added asynchronous calls and SSL/PCT security. (jroberts) --*/ #ifndef __DGCLNT_HXX__ #define __DGCLNT_HXX__ class DG_CCALL; typedef DG_CCALL * PDG_CCALL; class DG_CCONNECTION; typedef DG_CCONNECTION * PDG_CCONNECTION; class DG_CASSOCIATION; typedef DG_CASSOCIATION * PDG_CASSOCIATION; class DG_BINDING_HANDLE; typedef DG_BINDING_HANDLE * PDG_BINDING_HANDLE; class INTERFACE_AND_OBJECT_LIST { public: inline INTERFACE_AND_OBJECT_LIST( ) { Head = 0; Cache1Available = TRUE; Cache2Available = TRUE; } ~INTERFACE_AND_OBJECT_LIST( ); BOOL Insert( void * Interface, RPC_UUID * Object ); BOOL Find( void * Interface, RPC_UUID * Object ); BOOL Delete( void * Interface, RPC_UUID * Object ); private: #define MAX_ELEMENTS 10 struct INTERFACE_AND_OBJECT { INTERFACE_AND_OBJECT * Next; void * Interface; RPC_UUID Object; inline void Update( void * a_Interface, RPC_UUID * a_Object ) { Interface = a_Interface; Object = *a_Object; } }; INTERFACE_AND_OBJECT * Head; unsigned Cache1Available : 1; unsigned Cache2Available : 1; INTERFACE_AND_OBJECT Cache1; INTERFACE_AND_OBJECT Cache2; }; class DG_CCONNECTION : public DG_COMMON_CONNECTION { public: long TimeStamp; DG_CCONNECTION * Next; boolean CallbackCompleted; boolean fServerSupportsAsync; boolean fSecurePacketReceived; boolean ServerResponded; boolean fBusy; boolean InConnectionTable; signed char AckPending; boolean AckOrphaned; boolean PossiblyRunDown; boolean fAutoReconnect; boolean fError; DWORD ThreadId; PDG_BINDING_HANDLE BindingHandle; int AssociationKey; PDG_CASSOCIATION Association; PDG_CCALL CurrentCall; //-------------------------------------------------------------------- DG_CCALL * AllocateCall(); inline void AddCallToCache( PDG_CCALL Call ); RPC_STATUS BeginCall( IN PDG_CCALL Call ); void EndCall( IN PDG_CCALL Call ); long DecrementRefCount(); long DecrementRefCountAndKeepMutex(); void IncrementRefCount( void ); inline int IsSupportedAuthInfo( IN const CLIENT_AUTH_INFO * ClientAuthInfo ); RPC_STATUS DealWithAuthCallback( IN void * InToken, IN long InTokenLengh, OUT void * OutToken, OUT long MaxOutTokenLength, OUT long * OutTokenLength ); RPC_STATUS DealWithAuthMore( IN long Index, OUT void * OutToken, OUT long MaxOutTokenLength, OUT long * OutTokenLength ); DG_CCONNECTION( IN PDG_CASSOCIATION a_Association, IN const CLIENT_AUTH_INFO * AuthInfo, IN OUT RPC_STATUS * pStatus ); ~DG_CCONNECTION(); void PostDelayedAck(); void SendDelayedAck(); void CancelDelayedAck( BOOL Flush = FALSE ); inline void UpdateAssociation(); RPC_STATUS UpdateServerAddress( IN DG_PACKET * Packet, IN DG_TRANSPORT_ADDRESS Address ); void EnableOverlappedCalls(); unsigned long GetSequenceNumber() { return LowestActiveSequence; } unsigned long GetLowestActiveSequence() { return LowestActiveSequence; } RPC_STATUS WillNextCallBeQueued(); RPC_STATUS MaybeTransmitNextCall(); DG_CCALL * FindIdleCalls( long CurrentTime ); void DispatchPacket( PDG_PACKET Packet, void * Address ); inline unsigned long CurrentSequenceNumber(); virtual RPC_STATUS SealAndSendPacket( IN DG_ENDPOINT * SourceEndpoint, IN DG_TRANSPORT_ADDRESS RemoteAddress, IN UNALIGNED NCA_PACKET_HEADER * Header, IN unsigned long BufferOffset ); RPC_STATUS VerifyPacket( IN DG_PACKET * Packet ); static inline DG_CCONNECTION * FromHashNode( IN UUID_HASH_TABLE_NODE * Node ) { return CONTAINING_RECORD( Node, DG_CCONNECTION, ActivityNode ); } inline void * operator new( IN size_t ObjectLength, IN const RPC_DATAGRAM_TRANSPORT * Transport ); void WaitForNoReferences() { while (ReferenceCount) { Sleep(10); } fBusy = FALSE; } RPC_STATUS TransferCallsToNewConnection( PDG_CCALL FirstCall, PDG_CCONNECTION NewConnection ); const CLIENT_AUTH_INFO * InqAuthInfo() { return &AuthInfo; } BOOL MutexTryRequest() { BOOL result = Mutex.TryRequest(); if (result) { LogEvent( SU_MUTEX, EV_INC, this, 0, 0, TRUE, 1); } return result; } void MutexRequest() { Mutex.Request(); LogEvent( SU_MUTEX, EV_INC, this, 0, 0, TRUE, 1); #ifdef CHECK_MUTEX_INVERSION ThreadSelf()->ConnectionMutexHeld = this; #endif } void MutexClear() { LogEvent( SU_MUTEX, EV_DEC, this, 0, 0, TRUE, 1); Mutex.Clear(); #ifdef CHECK_MUTEX_INVERSION ThreadSelf()->ConnectionMutexHeld = 0; #endif } private: CLIENT_AUTH_INFO AuthInfo; DELAYED_ACTION_NODE DelayedAckTimer; unsigned SecurityContextId; long LastScavengeTime; unsigned CachedCallCount; PDG_CCALL CachedCalls; PDG_CCALL ActiveCallHead; PDG_CCALL ActiveCallTail; //-------------------------------------------------------------------- RPC_STATUS InitializeSecurityContext(); unsigned char * SecurityBuffer; long SecurityBufferLength; public: long LastCallbackTime; }; NEW_SDICT(DG_CCONNECTION); inline void * DG_CCONNECTION::operator new( IN size_t ObjectLength, IN const RPC_DATAGRAM_TRANSPORT * Transport ) { return new char[ObjectLength + Transport->AddressSize]; } inline void DG_CCONNECTION::IncrementRefCount() { Mutex.VerifyOwned(); ++ReferenceCount; LogEvent(SU_CCONN, EV_INC, this, 0, ReferenceCount, TRUE); } class DG_CCALL : public CCALL, public DG_PACKET_ENGINE { friend RPC_STATUS DG_CCONNECTION::WillNextCallBeQueued(); public: // // The call's Next pointer is NOT_ACTIVE until the call is added // to a connection's active call list. // #define DG_CCALL_NOT_ACTIVE ((DG_CCALL *) (~0)) long TimeStamp; DG_CCALL * Next; DG_CCALL * Previous; boolean LastSendTimedOut; boolean CancelPending; boolean CancelComplete; boolean AutoReconnectOk; //----------------------------------------------- DG_CCALL( IN PDG_CCONNECTION Connection, OUT RPC_STATUS * pStatus ); virtual ~DG_CCALL(); RPC_STATUS DispatchPacket( PDG_PACKET Packet ); inline void IncrementRefCount(); long DecrementRefCount(); long DecrementRefCountAndKeepMutex(); //------------------------------------------------ // // implementations of CCALL virtual functions // virtual RPC_STATUS NegotiateTransferSyntax ( IN OUT PRPC_MESSAGE Message ) { // datagrams don't support multiple syntax // negotiation. They always return the transfer // syntax the stub prefers return RPC_S_OK; } virtual RPC_STATUS GetBuffer ( IN OUT PRPC_MESSAGE Message, IN UUID *ObjectUuid = 0 ); virtual RPC_STATUS SendReceive ( IN OUT PRPC_MESSAGE Message ); virtual RPC_STATUS Send( PRPC_MESSAGE Message ); virtual RPC_STATUS Receive( PRPC_MESSAGE Message, unsigned MinimumSize ); virtual RPC_STATUS AsyncSend( PRPC_MESSAGE Message ); virtual RPC_STATUS AsyncReceive( PRPC_MESSAGE Message, unsigned MinimumSize ); 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 BOOL IssueNotification ( IN RPC_ASYNC_EVENT Event ) ; virtual void FreeAPCInfo ( IN RPC_APC_INFO *pAPCInfo ) ; RPC_STATUS CancelAsyncCall ( IN BOOL fAbort ); void SendAck(); virtual RPC_STATUS Cancel( void * ThreadHandle ); virtual unsigned TestCancel(); void ExecuteDelayedSend(); RPC_STATUS SendSomeFragments(); inline RPC_STATUS GetInitialBuffer( IN OUT RPC_MESSAGE * Message, IN UUID *MyObjectUuid ); inline void SwitchConnection( PDG_CCONNECTION NewConnection ); BOOL IsBroadcast() { if (BasePacketFlags & RPC_NCA_FLAGS_BROADCAST) { return TRUE; } return FALSE; } RPC_STATUS ProcessFaultOrRejectData( PDG_PACKET Packet ); BOOL InProgress() { if (AsyncStatus == RPC_S_ASYNC_CALL_PENDING) { return TRUE; } return FALSE; } private: enum DG_CLIENT_STATE { CallInit = 0x900, CallQuiescent, CallSend, CallSendReceive, CallReceive, CallCancellingSend, CallComplete }; DG_CLIENT_STATE State; DG_CLIENT_STATE PreviousState; PRPC_CLIENT_INTERFACE InterfacePointer; PDG_CCONNECTION Connection; DELAYED_ACTION_NODE TransmitTimer; // unused unsigned WorkingCount; unsigned UnansweredRequestCount; long ReceiveTimeout; unsigned long PipeReceiveSize; long TimeoutLimit; long LastReceiveTime; long CancelTime; boolean StaticArgsSent; boolean AllArgsSent; boolean _unused; boolean ForceAck; long DelayedSendPending; // Extended Error Info stuff // used in async calls only to hold // information b/n call failure and // RpcAsyncCompleteCall ExtendedErrorInfo *EEInfo; //-------------------------------------------------------------------- RPC_STATUS BeforeSendReceive( PRPC_MESSAGE Message ); RPC_STATUS AfterSendReceive( PRPC_MESSAGE Message, RPC_STATUS Status ); RPC_STATUS MaybeSendReceive( IN OUT PRPC_MESSAGE Message ); void BuildNcaPacketHeader( OUT PNCA_PACKET_HEADER pNcaPacketHeader, IN OUT PRPC_MESSAGE Message ); RPC_STATUS AttemptAutoReconnect(); BOOL CheckForCancelTimeout(); void PostDelayedSend(); void CancelDelayedSend(); void SendDelayedAck(); RPC_STATUS SendFragment( PRPC_MESSAGE pMessage, PNCA_PACKET_HEADER pBaseHeader ); RPC_STATUS SendQuit(); RPC_STATUS SendPing(); RPC_STATUS ReceiveSinglePacket(); //----------------------------------------------- RPC_STATUS DealWithNocall( PDG_PACKET pPacket ); RPC_STATUS DealWithFault( PDG_PACKET pPacket ); RPC_STATUS DealWithReject( PDG_PACKET pPacket ); RPC_STATUS DealWithWorking( PDG_PACKET pPacket ); RPC_STATUS DealWithResponse( PDG_PACKET pPacket ); RPC_STATUS DealWithFack( PDG_PACKET pPacket ); RPC_STATUS DealWithQuack( PDG_PACKET pPacket ); RPC_STATUS DealWithTimeout(); RPC_STATUS DealWithRequest( IN PDG_PACKET Packet, IN DG_TRANSPORT_ADDRESS RemoteAddress ); void IncreaseReceiveTimeout(); RPC_STATUS MapErrorCode( RPC_STATUS Status ); RPC_STATUS GetEndpoint( DWORD EndpointFlags ); void SetState( IN DG_CLIENT_STATE NewState ) { if (NewState != State) { LogEvent(SU_CCALL, EV_STATE, this, 0, NewState); } PreviousState = State; State = NewState; } }; class DG_CASSOCIATION : public GENERIC_OBJECT { friend class DG_ASSOCIATION_TABLE; public: RPC_DATAGRAM_TRANSPORT * TransportInterface; unsigned long ServerBootTime; unsigned long ServerDataRep; unsigned CurrentPduSize; unsigned RemoteWindowSize; boolean fServerSupportsAsync; boolean fLoneBindingHandle; enum { BROADCAST = 0x100, UNRESOLVEDEP = 0x200 }; //---------------------------------------------------------- DG_CASSOCIATION( IN RPC_DATAGRAM_TRANSPORT * a_Transport, IN LONG a_AssociationFlag, IN DCE_BINDING * a_DceBinding, IN BOOL a_Unique, IN OUT RPC_STATUS * pStatus ); ~DG_CASSOCIATION(); RPC_STATUS SendPacket( IN DG_ENDPOINT Endpoint, IN PNCA_PACKET_HEADER Header, IN unsigned SecurityTrailerLength = 0 ); virtual RPC_STATUS ToStringBinding ( OUT RPC_CHAR * * StringBinding, IN RPC_UUID * ObjectUuid ); void IncrementRefCount(); void DecrementRefCount(); int CompareWithBinding( IN PDG_BINDING_HANDLE pBinding ); BOOL ComparePartialBinding( IN PDG_BINDING_HANDLE pBinding, void * Interface ); BOOL AddInterface( void * InterfaceInformation, RPC_UUID * ObjectUuid ); BOOL RemoveInterface( void * InterfaceInformation, RPC_UUID * ObjectUuid ); RPC_STATUS AllocateCall( IN PDG_BINDING_HANDLE BindingHandle, IN const CLIENT_AUTH_INFO * AuthInfo, OUT PDG_CCALL * ppCall, IN BOOL fAsync ); void ReleaseCall( IN PDG_CCALL Call ); PDG_CCONNECTION AllocateConnection( IN PDG_BINDING_HANDLE BindingHandle, IN const CLIENT_AUTH_INFO * AuthInfo, IN DWORD ThreadId, IN BOOL fAsync, OUT RPC_STATUS * pStatus ); void ReleaseConnection( IN PDG_CCONNECTION Call ); void DeleteIdleConnections( long CurrentTime ); RPC_STATUS UpdateAssociationWithAddress( PDG_PACKET Packet, void * Address ); BOOL SendKeepAlive(); DCE_BINDING * DuplicateDceBinding (); void SetErrorFlag () { fErrorFlag = TRUE; } void ClearErrorFlag() { fErrorFlag = FALSE; } BOOL ErrorFlag () { return fErrorFlag; } DG_TRANSPORT_ADDRESS InqServerAddress () { return ServerAddress; } void CopyServerAddress( IN DG_TRANSPORT_ADDRESS Destination ); inline void * operator new( IN size_t ObjectLength, IN const RPC_DATAGRAM_TRANSPORT * Transport ); BOOL IsAckPending(); void FlushAcks(); void IncrementBindingRefCount( unsigned ContextHandleRef ); void DecrementBindingRefCount( unsigned ContextHandleRef ); void VerifyNotLocked() { Mutex.VerifyNotOwned(); } BOOL LockOwnedByMe() { return Mutex.OwnedByMe(); } private: void MutexRequest() { #ifdef CHECK_MUTEX_INVERSION if (!Mutex.OwnedByMe() ) { DG_CCONNECTION * conn = (DG_CCONNECTION *) ThreadSelf()->ConnectionMutexHeld; ASSERT( 0 == conn || conn->ThreadId == GetCurrentThreadId() ); } #endif Mutex.Request(); } void MutexClear() { Mutex.Clear(); } INTERLOCKED_INTEGER ReferenceCount; MUTEX Mutex; LONG AssociationFlag; boolean fErrorFlag; DCE_BINDING * pDceBinding; long LastScavengeTime; DG_TRANSPORT_ADDRESS ServerAddress; DG_CCONNECTION_DICT ActiveConnections; DG_CCONNECTION_DICT InactiveConnections; INTERFACE_AND_OBJECT_LIST InterfaceAndObjectDict; RPC_CHAR * ResolvedEndpoint; long BindingHandleReferences; long InternalTableIndex; DG_BINDING_HANDLE * KeepAliveHandle; public: long LastReceiveTime; }; inline DCE_BINDING * DG_CASSOCIATION::DuplicateDceBinding ( ) { CLAIM_MUTEX lock( Mutex ); ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) ); return(pDceBinding->DuplicateDceBinding()); } inline void DG_CASSOCIATION::IncrementRefCount( void ) { ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) ); long Count = ReferenceCount.Increment(); LogEvent(SU_CASSOC, EV_INC, this, 0, Count); } inline void * DG_CASSOCIATION::operator new( IN size_t ObjectLength, IN const RPC_DATAGRAM_TRANSPORT * Transport ) { return new char[ObjectLength + 2 * Transport->AddressSize]; } class DG_ASSOCIATION_TABLE { public: BOOL fCasUuidReady; UUID CasUuid; //-------------------------------------------------------------------- typedef LONG HINT; DG_ASSOCIATION_TABLE( RPC_STATUS * pStatus ); ~DG_ASSOCIATION_TABLE() { if (Associations != InitialAssociations) delete Associations; } HINT MakeHint( DCE_BINDING * pDceBinding ); RPC_STATUS Add( DG_CASSOCIATION * Association ); DG_CASSOCIATION * Find( DG_BINDING_HANDLE * Binding, RPC_CLIENT_INTERFACE * Interface, BOOL fContextHandle, BOOL fPartial, BOOL fReconnect ); void Delete( DG_CASSOCIATION * Association ); BOOL DeleteIdleEntries( long CurrentTime ); BOOL SendContextHandleKeepalives(); void IncrementContextHandleCount( DG_CASSOCIATION * Association ); void DecrementContextHandleCount( DG_CASSOCIATION * Association ); long GetContextHandleCount( DG_CASSOCIATION * Association ); void UpdateTimeStamp( DG_CASSOCIATION * Association ); void LockExclusive() { Mutex.LockExclusive(); } void UnlockExclusive() { Mutex.UnlockExclusive(); } private: struct NODE { DG_CASSOCIATION * Association; HINT Hint; BOOL fBusy; long ContextHandleCount; long TimeStamp; }; enum { INITIAL_ARRAY_LENGTH = 4, MINIMUM_IDLE_ENTRIES = 10 }; CSharedLock Mutex; NODE * Associations; LONG AssociationsLength; NODE InitialAssociations[ INITIAL_ARRAY_LENGTH ]; long PreviousFreedCount; }; extern DG_ASSOCIATION_TABLE * ActiveAssociations; inline void DG_CASSOCIATION::IncrementBindingRefCount( unsigned ContextHandleRef ) { ASSERT( ContextHandleRef <= 1 ); // ASSERT( ContextHandleReferences < 100 ); // ASSERT( BindingHandleReferences < 100 ); ++BindingHandleReferences; if (ContextHandleRef) { ActiveAssociations->IncrementContextHandleCount(this); } IncrementRefCount(); } inline void DG_CASSOCIATION::DecrementBindingRefCount( unsigned ContextHandleRef ) { ASSERT( ContextHandleRef <= 1 ); ASSERT( BindingHandleReferences > 0 ); if (ContextHandleRef) { ActiveAssociations->DecrementContextHandleCount(this); } // ASSERT( ContextHandleReferences >= 0 ); if (0 == --BindingHandleReferences) { FlushAcks(); } DecrementRefCount(); } class DG_BINDING_HANDLE : public BINDING_HANDLE /*++ Class Description: This class represents a handle pointing at a particular server/endpoint. Fields: pDceBinding - Until a DG_CASSOCIATION is found (or created) for this binding handle, pDceBinding will point at the appropriate DCE_BINDING. Mutex - Protects this binding handle. ReferenceCount - Number of DG_CCALLs currently associated with this binding handle. DecrementReferenceCount - Decrements the reference count to this binding handle. If the reference count hits 0, the binding handle is deleted. DisassociateFromServer - If this is a BH that we couldnt successfully use, tear down the association --*/ { public: DCE_BINDING * pDceBinding; DWORD EndpointFlags; DG_BINDING_HANDLE( IN OUT RPC_STATUS * RpcStatus ); // // This is not a general-purpose constructor. // The context handle keep-alive code uses it. // DG_BINDING_HANDLE( IN PDG_CASSOCIATION Association, IN DCE_BINDING * DceBinding, IN OUT RPC_STATUS * RpcStatus ); ~DG_BINDING_HANDLE(); virtual RPC_STATUS NegotiateTransferSyntax ( IN OUT PRPC_MESSAGE Message ) { // datagrams don't support multiple syntax // negotiation. They always return the transfer // syntax the stub prefers return RPC_S_OK; } RPC_STATUS GetBuffer ( IN OUT PRPC_MESSAGE Message, IN UUID *ObjectUuid ); RPC_STATUS BindingCopy ( OUT BINDING_HANDLE * * DestinationBinding, IN unsigned int MaintainContext ); RPC_STATUS BindingFree (); PDG_CCONNECTION GetReplacementConnection( PDG_CCONNECTION OldConnection, PRPC_CLIENT_INTERFACE Interface ); RPC_STATUS PrepareBindingHandle ( IN TRANS_INFO * TransportInterface, IN DCE_BINDING * DceBinding ); RPC_STATUS ToStringBinding ( OUT RPC_CHAR * * StringBinding ); RPC_STATUS ResolveBinding ( IN RPC_CLIENT_INTERFACE * RpcClientInterface ); RPC_STATUS BindingReset (); virtual RPC_STATUS InquireTransportType( OUT unsigned int * Type ) { *Type = TRANSPORT_TYPE_DG; return(RPC_S_OK); } inline void IncrementRefCount() { long Count = ReferenceCount.Increment(); LogEvent(SU_HANDLE, EV_INC, this, 0, Count); } void DecrementRefCount(); void FreeCall( DG_CCALL * Call ); void DisassociateFromServer(); unsigned long MapAuthenticationLevel ( IN unsigned long AuthenticationLevel ); BOOL SetTransportAuthentication( IN unsigned long ulAuthenticationLevel, IN unsigned long ulAuthenticationService, OUT RPC_STATUS *pStatus ); inline BOOL IsDynamic() { return fDynamicEndpoint; } RPC_STATUS SetTransportOption( IN unsigned long option, IN ULONG_PTR optionValue ); RPC_STATUS InqTransportOption( IN unsigned long option, OUT ULONG_PTR * pOptionValue ); void MutexRequest() { #ifdef CHECK_MUTEX_INVERSION if (!BindingMutex.OwnedByMe() ) { DG_CCONNECTION * conn = (DG_CCONNECTION *) ThreadSelf()->ConnectionMutexHeld; ASSERT( 0 == conn || conn->ThreadId == GetCurrentThreadId() ); if (Association) { if (Association->LockOwnedByMe() == FALSE) { Association->VerifyNotLocked(); } } } #endif BindingMutex.Request(); } void MutexClear() { BindingMutex.Clear(); } private: TRANS_INFO * TransportObject; RPC_DATAGRAM_TRANSPORT *TransportInterface; DG_CASSOCIATION * Association; INTERLOCKED_INTEGER ReferenceCount; boolean fDynamicEndpoint; unsigned fContextHandle; RPC_STATUS FindOrCreateAssociation( IN const PRPC_CLIENT_INTERFACE Interface, IN BOOL fReconnect, IN BOOL fBroadcast ); }; inline DG_BINDING_HANDLE::DG_BINDING_HANDLE( IN OUT RPC_STATUS * pStatus ) : BINDING_HANDLE (pStatus), Association (0), ReferenceCount(1), pDceBinding (0), fContextHandle(0), EndpointFlags (0) /*++ Routine Description: The constructor for DG_BINDING_HANDLE. This object represents a binding to a server. Most of the important members are set in DG_BINDING_HANDLE::PrepareBindingHandle. --*/ { ObjectType = DG_BINDING_HANDLE_TYPE; LogEvent(SU_HANDLE, EV_CREATE, this); } inline DG_BINDING_HANDLE::DG_BINDING_HANDLE( IN PDG_CASSOCIATION a_Association, IN DCE_BINDING * a_DceBinding, IN OUT RPC_STATUS * a_pStatus ) : BINDING_HANDLE(a_pStatus), Association (a_Association), ReferenceCount(1), pDceBinding (a_DceBinding), fContextHandle(0), EndpointFlags (0) /*++ Routine Description: The constructor for DG_BINDING_HANDLE. This is a quick and dirty constructor; in particular it does not clone the DCE_BINDING. --*/ { ObjectType = DG_BINDING_HANDLE_TYPE; LogEvent(SU_HANDLE, EV_CREATE, this, 0, *a_pStatus); if (0 != *a_pStatus) { Association = 0; } } inline DG_BINDING_HANDLE::~DG_BINDING_HANDLE() /*++ Routine Description: Destructor for the DG_BINDING_HANDLE. Let the association know we aren't using it anymore; this may cause it to be deleted. Arguments: Return Value: --*/ { LogEvent(SU_HANDLE, EV_DELETE, this); if (Association != 0) { Association->DecrementBindingRefCount(fContextHandle); } delete pDceBinding; } inline void DG_BINDING_HANDLE::DecrementRefCount() { long Count = ReferenceCount.Decrement(); LogEvent(SU_HANDLE, EV_DEC, this, 0, Count, TRUE); if (Count == 0) { delete this; } } class DG_CLIENT_CALLBACK : public MESSAGE_OBJECT { public: DG_PACKET * Request; DG_CCONNECTION * Connection; DG_ENDPOINT * LocalEndpoint; DG_TRANSPORT_ADDRESS RemoteAddress; //-------------------------------------------------------------------- inline DG_CLIENT_CALLBACK() { ObjectType = DG_CALLBACK_TYPE; Request = 0; } inline ~DG_CLIENT_CALLBACK() { if (Request) { Request->Free(FALSE); } } virtual RPC_STATUS NegotiateTransferSyntax ( IN OUT PRPC_MESSAGE Message ) { // datagrams don't support multiple syntax // negotiation. They always return the transfer // syntax the stub prefers return RPC_S_OK; } virtual RPC_STATUS GetBuffer( IN OUT PRPC_MESSAGE Message, IN UUID *ObjectUuid ); virtual void FreeBuffer( IN OUT PRPC_MESSAGE Message ); // not really implemented virtual RPC_STATUS SendReceive ( IN OUT PRPC_MESSAGE Message ); virtual RPC_STATUS Send( PRPC_MESSAGE Message ); virtual RPC_STATUS AsyncSend( PRPC_MESSAGE Message ); virtual RPC_STATUS Receive( PRPC_MESSAGE Message, unsigned MinimumSize ); virtual RPC_STATUS SetAsyncHandle ( IN RPC_ASYNC_STATE * hAsync ); virtual BOOL IsSyncCall () { return FALSE; } inline void SendPacket( NCA_PACKET_HEADER * Header ) { unsigned Frag = (Header->PacketType << 16) | Header->GetFragmentNumber(); LogEvent( SU_CCONN, EV_PKT_OUT, Connection, 0, Frag); LocalEndpoint->TransportInterface->Send( &LocalEndpoint->TransportEndpoint, RemoteAddress, 0, 0, Header, sizeof(NCA_PACKET_HEADER) + Header->GetPacketBodyLen(), 0, 0 ); } }; typedef DG_CLIENT_CALLBACK * PDG_CLIENT_CALLBACK; class CLIENT_ACTIVITY_TABLE : private UUID_HASH_TABLE { public: inline CLIENT_ACTIVITY_TABLE( RPC_STATUS * pStatus ) : UUID_HASH_TABLE(pStatus) { } inline ~CLIENT_ACTIVITY_TABLE( ) { } PDG_CCONNECTION Lookup( RPC_UUID * Uuid ); inline RPC_STATUS Add( PDG_CCONNECTION Connection ); inline RPC_STATUS Remove( PDG_CCONNECTION Connection ); }; RPC_STATUS CLIENT_ACTIVITY_TABLE::Add( PDG_CCONNECTION Connection ) { ASSERT( !Connection->InConnectionTable ); Connection->InConnectionTable = TRUE; unsigned Hash = MakeHash(&Connection->ActivityNode.Uuid); RequestHashMutex(Hash); UUID_HASH_TABLE::Add(&Connection->ActivityNode); ReleaseHashMutex(Hash); return RPC_S_OK; } RPC_STATUS CLIENT_ACTIVITY_TABLE::Remove( PDG_CCONNECTION Connection ) { if( !Connection->InConnectionTable ) { return RPC_S_OK; } Connection->InConnectionTable = FALSE; unsigned Hash = MakeHash(&Connection->ActivityNode.Uuid); RequestHashMutex(Hash); UUID_HASH_TABLE::Remove(&Connection->ActivityNode); ReleaseHashMutex(Hash); return RPC_S_OK; } class ENDPOINT_MANAGER { public: ENDPOINT_MANAGER( IN OUT RPC_STATUS * pStatus ); DG_ENDPOINT * RequestEndpoint( IN RPC_DATAGRAM_TRANSPORT * TransportInterface, IN BOOL Async, IN DWORD Flags ); void ReleaseEndpoint( IN DG_ENDPOINT * Endpoint ); BOOL DeleteIdleEndpoints( long CurrentTime ); private: #define DG_TRANSPORT_COUNT 2 MUTEX Mutex; DWORD LastScavengeTime; DG_ENDPOINT_STATS Stats; DG_ENDPOINT * AsyncEndpoints[DG_TRANSPORT_COUNT]; DG_ENDPOINT * Endpoints; }; //------------------------------------------------------------------------ inline void DG_CCONNECTION::AddCallToCache( PDG_CCALL Call ) { Mutex.VerifyOwned(); Call->Next = CachedCalls; CachedCalls = Call; LogEvent(SU_CCALL, EV_STOP, Call, this, Call->GetSequenceNumber() ); #ifdef DEBUGRPC PDG_CCALL Node = ActiveCallHead; while (Node) { ASSERT( Node != Call ); Node = Node->Next; } #endif } void DG_CCONNECTION::UpdateAssociation( ) { Association->CurrentPduSize = CurrentPduSize; Association->RemoteWindowSize = RemoteWindowSize; } unsigned long DG_CCONNECTION::CurrentSequenceNumber() { return CurrentCall->GetSequenceNumber(); } inline void DG_CCALL::IncrementRefCount() { ++ReferenceCount; LogEvent(SU_CCALL, EV_INC, this, 0, ReferenceCount); } inline void DG_CCALL::SwitchConnection( PDG_CCONNECTION NewConnection ) { Connection = NewConnection; ReadConnectionInfo(NewConnection, 0); ActivityHint = 0xffff; pSavedPacket->Header.ServerBootTime = NewConnection->Association->ServerBootTime; pSavedPacket->Header.ActivityHint = ActivityHint; } RPC_STATUS StandardPacketChecks( PDG_PACKET Packet ); #endif // if __DGCLNT_HXX__