1494 lines
31 KiB
C++
1494 lines
31 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1992 - 1999
|
||
|
||
Module Name:
|
||
|
||
dgsvr.hxx
|
||
|
||
Abstract:
|
||
|
||
This is the server protocol definitions for a datagram rpc.
|
||
|
||
Author:
|
||
|
||
Dave Steckler (davidst) 15-Dec-1992
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#ifndef __DGSVR_HXX__
|
||
#define __DGSVR_HXX__
|
||
|
||
#define MIN_THREADS_WHILE_ACTIVE 3
|
||
|
||
|
||
// Information on the source endpoint. To be used in
|
||
// forwarding a packet to a dynamic endpoint from the epmapper.
|
||
|
||
// disable "zero-length array" warning
|
||
#pragma warning(disable:4200)
|
||
|
||
struct FROM_ENDPOINT_INFO
|
||
{
|
||
unsigned long FromEndpointLen;
|
||
DREP FromDataRepresentation;
|
||
char FromEndpoint[0];
|
||
};
|
||
|
||
#pragma warning(default:4200)
|
||
|
||
//----------------------------------------------------------------------
|
||
|
||
class DG_SCALL;
|
||
typedef DG_SCALL * PDG_SCALL;
|
||
|
||
class DG_SCONNECTION;
|
||
typedef DG_SCONNECTION * PDG_SCONNECTION;
|
||
|
||
|
||
class DG_ADDRESS : public RPC_ADDRESS
|
||
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
This class represents an endpoint.
|
||
|
||
--*/
|
||
|
||
{
|
||
public:
|
||
|
||
#define MIN_FREE_CALLS 2
|
||
|
||
//--------------------------------------------------------------------
|
||
|
||
inline void *
|
||
operator new(
|
||
IN size_t ObjectLength,
|
||
IN TRANS_INFO * Transport
|
||
);
|
||
|
||
DG_ADDRESS(
|
||
TRANS_INFO * LoadableTransport,
|
||
RPC_STATUS * pStatus
|
||
);
|
||
|
||
virtual
|
||
~DG_ADDRESS ();
|
||
|
||
void
|
||
WaitForCalls(
|
||
);
|
||
|
||
virtual void
|
||
EncourageCallCleanup(
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ServerSetupAddress (
|
||
IN RPC_CHAR PAPI *NetworkAddress,
|
||
IN RPC_CHAR PAPI * PAPI *Endpoint,
|
||
IN unsigned int PendingQueueSize,
|
||
IN void PAPI * SecurityDescriptor, OPTIONAL
|
||
IN unsigned long EndpointFlags,
|
||
IN unsigned long NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
|
||
) ;
|
||
|
||
#ifndef NO_PLUG_AND_PLAY
|
||
virtual void PnpNotify();
|
||
#endif
|
||
|
||
virtual RPC_STATUS
|
||
ServerStartingToListen (
|
||
IN unsigned int MinimumCallThreads,
|
||
IN unsigned int MaximumConcurrentCalls
|
||
);
|
||
|
||
virtual void
|
||
ServerStoppedListening (
|
||
);
|
||
|
||
virtual long
|
||
InqNumberOfActiveCalls (
|
||
);
|
||
|
||
RPC_STATUS
|
||
CheckThreadPool(
|
||
);
|
||
|
||
inline void
|
||
DispatchPacket(
|
||
DG_PACKET * Packet,
|
||
IN DatagramTransportPair *AddressPair
|
||
);
|
||
|
||
inline PDG_PACKET AllocatePacket();
|
||
|
||
inline void
|
||
FreePacket(
|
||
IN PDG_PACKET pPacket
|
||
);
|
||
|
||
inline PDG_SCALL AllocateCall();
|
||
|
||
inline void
|
||
FreeCall(
|
||
PDG_SCALL pCall
|
||
);
|
||
|
||
DG_SCONNECTION * AllocateConnection();
|
||
|
||
void
|
||
FreeConnection(
|
||
DG_SCONNECTION * Connection
|
||
);
|
||
|
||
RPC_STATUS CompleteListen ();
|
||
|
||
inline RPC_STATUS
|
||
SendPacketBack(
|
||
NCA_PACKET_HEADER * Header,
|
||
unsigned DataAfterHeader,
|
||
DG_TRANSPORT_ADDRESS RemoteAddress
|
||
)
|
||
{
|
||
Header->PacketFlags &= ~DG_PF_FORWARDED;
|
||
Header->PacketFlags2 &= ~DG_PF2_FORWARDED_2;
|
||
|
||
ASSERT( Header->PacketType <= 10 );
|
||
|
||
unsigned Frag = (Header->PacketType << 16) | Header->GetFragmentNumber();
|
||
LogEvent(SU_ADDRESS, EV_PKT_OUT, this, 0, Frag);
|
||
|
||
return Endpoint.TransportInterface->Send(
|
||
Endpoint.TransportEndpoint,
|
||
RemoteAddress,
|
||
0,
|
||
0,
|
||
Header,
|
||
sizeof(NCA_PACKET_HEADER) + DataAfterHeader,
|
||
0,
|
||
0
|
||
);
|
||
}
|
||
|
||
inline void
|
||
SendRejectPacket(
|
||
DG_PACKET * Packet,
|
||
DWORD ErrorCode,
|
||
DG_TRANSPORT_ADDRESS RemoteAddress
|
||
)
|
||
{
|
||
InitErrorPacket(Packet, DG_REJECT, ErrorCode);
|
||
SendPacketBack (&Packet->Header, Packet->GetPacketBodyLen(), RemoteAddress);
|
||
}
|
||
|
||
RPC_STATUS
|
||
LaunchReceiveThread(
|
||
);
|
||
|
||
static void
|
||
ScavengerProc(
|
||
void * address
|
||
);
|
||
|
||
inline void
|
||
DecrementActiveCallCount(
|
||
)
|
||
{
|
||
ASSERT(ActiveCallCount < 0xffff0000UL);
|
||
|
||
InterlockedDecrement((LONG *) &ActiveCallCount);
|
||
|
||
Endpoint.NumberOfCalls = ActiveCallCount;
|
||
}
|
||
|
||
inline void
|
||
IncrementActiveCallCount(
|
||
)
|
||
{
|
||
ASSERT( ActiveCallCount < 0x100000 );
|
||
|
||
InterlockedIncrement((LONG *) &ActiveCallCount);
|
||
|
||
Endpoint.NumberOfCalls = ActiveCallCount;
|
||
}
|
||
|
||
void
|
||
BeginAutoListenCall (
|
||
) ;
|
||
|
||
void
|
||
EndAutoListenCall (
|
||
) ;
|
||
|
||
static inline DG_ADDRESS *
|
||
FromEndpoint(
|
||
IN DG_TRANSPORT_ENDPOINT Endpoint
|
||
)
|
||
{
|
||
return CONTAINING_RECORD( Endpoint, DG_ADDRESS, Endpoint.TransportEndpoint );
|
||
}
|
||
|
||
//--------------------------------------------------------------------
|
||
|
||
private:
|
||
|
||
LONG TotalThreadsThisEndpoint;
|
||
LONG ThreadsReceivingThisEndpoint;
|
||
unsigned MinimumCallThreads;
|
||
unsigned MaximumConcurrentCalls;
|
||
|
||
DELAYED_ACTION_NODE ScavengerTimer;
|
||
|
||
unsigned ActiveCallCount;
|
||
|
||
UUID_HASH_TABLE_NODE * CachedConnections;
|
||
|
||
INTERLOCKED_INTEGER AutoListenCallCount;
|
||
|
||
public:
|
||
// this needs to be the last member because the transport endpoint
|
||
// follows it.
|
||
//
|
||
DG_ENDPOINT Endpoint;
|
||
|
||
//--------------------------------------------------------------------
|
||
|
||
unsigned ScavengePackets();
|
||
unsigned ScavengeCalls();
|
||
|
||
private:
|
||
|
||
BOOL
|
||
CaptureClientAddress(
|
||
IN PDG_PACKET Packet,
|
||
OUT DG_TRANSPORT_ADDRESS RemoteAddress
|
||
);
|
||
|
||
RPC_STATUS
|
||
ForwardPacket(
|
||
IN PDG_PACKET Packet,
|
||
IN DG_TRANSPORT_ADDRESS RemoteAddress,
|
||
IN char * ServerEndpointString
|
||
);
|
||
|
||
BOOL
|
||
ForwardPacketIfNecessary(
|
||
IN PDG_PACKET pReceivedPacket,
|
||
IN void * pFromEndpoint
|
||
);
|
||
|
||
unsigned short
|
||
ConvertSerialNum(
|
||
IN PDG_PACKET pPacket
|
||
);
|
||
|
||
static inline void
|
||
RemoveIdleConnections(
|
||
DG_ADDRESS * Address
|
||
);
|
||
|
||
};
|
||
|
||
typedef DG_ADDRESS PAPI * PDG_ADDRESS;
|
||
|
||
inline void *
|
||
DG_ADDRESS::operator new(
|
||
IN size_t ObjectLength,
|
||
IN TRANS_INFO * Transport
|
||
)
|
||
{
|
||
RPC_DATAGRAM_TRANSPORT * TransportInterface = (RPC_DATAGRAM_TRANSPORT *) (Transport->InqTransInfo());
|
||
return new char[ObjectLength + TransportInterface->ServerEndpointSize];
|
||
}
|
||
|
||
|
||
|
||
PDG_PACKET
|
||
DG_ADDRESS::AllocatePacket(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates a packet and associates it with a particular transport address.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
a packet, or zero if out of memory
|
||
|
||
--*/
|
||
|
||
{
|
||
return DG_PACKET::AllocatePacket(Endpoint.Stats.PreferredPduSize);
|
||
}
|
||
|
||
|
||
void
|
||
DG_ADDRESS::FreePacket(
|
||
IN PDG_PACKET pPacket
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Frees a packet. If there are less than MAX_FREE_PACKETS on the
|
||
pre-allocated list, then just add it to the list, otherwise delete it.
|
||
|
||
Arguments:
|
||
|
||
pPacket - Packet to delete.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
--*/
|
||
|
||
{
|
||
pPacket->Free();
|
||
}
|
||
|
||
class ASSOC_GROUP_TABLE;
|
||
|
||
//
|
||
// casting unsigned to/from void * is OK in this case.
|
||
//
|
||
#pragma warning(push)
|
||
#pragma warning(disable:4312)
|
||
NEW_SDICT2(SECURITY_CONTEXT, unsigned);
|
||
|
||
#pragma warning(pop)
|
||
|
||
|
||
class ASSOCIATION_GROUP : public ASSOCIATION_HANDLE
|
||
//
|
||
// This class represents an association group as defined by OSF. This means
|
||
// a set of associations sharing an address space.
|
||
//
|
||
{
|
||
friend class ASSOC_GROUP_TABLE;
|
||
|
||
public:
|
||
|
||
inline
|
||
ASSOCIATION_GROUP(
|
||
RPC_UUID * pUuid,
|
||
unsigned short InitialPduSize,
|
||
RPC_STATUS * pStatus
|
||
)
|
||
: Mutex(pStatus),
|
||
ASSOCIATION_HANDLE(),
|
||
Node(pUuid),
|
||
CurrentPduSize(InitialPduSize),
|
||
ReferenceCount(1),
|
||
RemoteWindowSize(1)
|
||
{
|
||
ObjectType = DG_SASSOCIATION_TYPE;
|
||
}
|
||
|
||
~ASSOCIATION_GROUP(
|
||
)
|
||
{
|
||
}
|
||
|
||
inline static ASSOCIATION_GROUP *
|
||
ContainingRecord(
|
||
UUID_HASH_TABLE_NODE * Node
|
||
)
|
||
{
|
||
return CONTAINING_RECORD (Node, ASSOCIATION_GROUP, Node);
|
||
}
|
||
void
|
||
RequestMutex(
|
||
)
|
||
{
|
||
Mutex.Request();
|
||
}
|
||
|
||
void
|
||
ClearMutex(
|
||
)
|
||
{
|
||
Mutex.Clear();
|
||
}
|
||
|
||
void
|
||
IncrementRefCount(
|
||
)
|
||
{
|
||
long Count = ReferenceCount.Increment();
|
||
LogEvent(SU_ASSOC, EV_INC, this, 0, Count);
|
||
}
|
||
|
||
long
|
||
DecrementRefCount(
|
||
)
|
||
{
|
||
long Count = ReferenceCount.Decrement();
|
||
LogEvent(SU_ASSOC, EV_DEC, this, 0, Count);
|
||
|
||
return Count;
|
||
}
|
||
private:
|
||
|
||
INTERLOCKED_INTEGER ReferenceCount;
|
||
MUTEX Mutex;
|
||
//
|
||
// This lets the object be added to the master ASSOC_GROUP_TABLE.
|
||
//
|
||
UUID_HASH_TABLE_NODE Node;
|
||
|
||
unsigned short CurrentPduSize;
|
||
unsigned short RemoteWindowSize;
|
||
|
||
};
|
||
|
||
|
||
//
|
||
// Scurity callback results.
|
||
//
|
||
// CBI_VALID is true if the callback has occurred.
|
||
// CBI_ALLOWED is true if the callback allowed the user to make the call.
|
||
// CBI_CONTEXT_MASK is bitmask for the context (key sequence number).
|
||
//
|
||
// The remaining bits contain the interface sequence number;
|
||
// (x >> CBI_SEQUENCE_SHIFT) extracts it.
|
||
//
|
||
#define CBI_VALID (0x00000800U)
|
||
#define CBI_ALLOWED (0x00000400U)
|
||
#define CBI_CONTEXT_MASK (0x000000ffU)
|
||
|
||
#define CBI_SEQUENCE_SHIFT 12
|
||
#define CBI_SEQUENCE_MASK (~((1 << CBI_SEQUENCE_SHIFT) - 1))
|
||
|
||
class SECURITY_CALLBACK_INFO_DICT2 : public SIMPLE_DICT2
|
||
{
|
||
public:
|
||
|
||
inline
|
||
SECURITY_CALLBACK_INFO_DICT2 ( // Constructor.
|
||
)
|
||
{
|
||
}
|
||
|
||
inline
|
||
~SECURITY_CALLBACK_INFO_DICT2 ( // Destructor.
|
||
)
|
||
{
|
||
}
|
||
|
||
inline int
|
||
Update (
|
||
RPC_INTERFACE * Key,
|
||
unsigned Item
|
||
)
|
||
{
|
||
Remove(Key);
|
||
return SIMPLE_DICT2::Insert(Key, UlongToPtr(Item));
|
||
}
|
||
|
||
inline unsigned
|
||
Remove (
|
||
RPC_INTERFACE * Key
|
||
)
|
||
{
|
||
return PtrToUlong(SIMPLE_DICT2::Delete(Key));
|
||
}
|
||
|
||
inline unsigned
|
||
Find (
|
||
RPC_INTERFACE * Key
|
||
)
|
||
{
|
||
return PtrToUlong(SIMPLE_DICT2::Find(Key));
|
||
}
|
||
};
|
||
|
||
|
||
class DG_SCALL_TABLE
|
||
{
|
||
public:
|
||
|
||
inline DG_SCALL_TABLE();
|
||
|
||
inline ~DG_SCALL_TABLE();
|
||
|
||
BOOL
|
||
Add(
|
||
PDG_SCALL Call,
|
||
unsigned long Sequence
|
||
);
|
||
|
||
void
|
||
Remove(
|
||
PDG_SCALL Call
|
||
);
|
||
|
||
PDG_SCALL
|
||
Find(
|
||
unsigned long Sequence
|
||
);
|
||
|
||
PDG_SCALL
|
||
Predecessor(
|
||
unsigned long Sequence
|
||
);
|
||
|
||
PDG_SCALL
|
||
Successor(
|
||
PDG_SCALL Call
|
||
);
|
||
|
||
inline void
|
||
RemoveIdleCalls(
|
||
BOOL Aggressive,
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
private:
|
||
|
||
PDG_SCALL ActiveCallHead;
|
||
PDG_SCALL ActiveCallTail;
|
||
|
||
};
|
||
|
||
inline
|
||
DG_SCALL_TABLE::DG_SCALL_TABLE()
|
||
{
|
||
ActiveCallHead = 0;
|
||
ActiveCallTail = 0;
|
||
}
|
||
|
||
inline
|
||
DG_SCALL_TABLE::~DG_SCALL_TABLE()
|
||
{
|
||
ASSERT( ActiveCallHead == 0 );
|
||
ASSERT( ActiveCallTail == 0 );
|
||
}
|
||
|
||
|
||
class DG_SCONNECTION : public DG_COMMON_CONNECTION
|
||
{
|
||
public:
|
||
|
||
DG_SCONNECTION *Next;
|
||
|
||
CLIENT_AUTH_INFO AuthInfo;
|
||
|
||
unsigned ActivityHint;
|
||
|
||
ASSOCIATION_GROUP * pAssocGroup;
|
||
|
||
PDG_ADDRESS pAddress;
|
||
RPC_INTERFACE * LastInterface;
|
||
|
||
DG_SCALL * CurrentCall;
|
||
BOOL fFirstCall;
|
||
|
||
enum CALLBACK_STATE
|
||
{
|
||
NoCallbackAttempted = 0x99,
|
||
SetupInProgress,
|
||
MsConvWayAuthInProgress,
|
||
ConvWayAuthInProgress,
|
||
MsConvWay2InProgress,
|
||
ConvWay2InProgress,
|
||
ConvWayInProgress,
|
||
ConvWayAuthMoreInProgress,
|
||
CallbackSucceeded,
|
||
CallbackFailed
|
||
};
|
||
|
||
//--------------------------------------------------------------------
|
||
// The message mutex is only used by ncadg_mq.
|
||
MUTEX3 *pMessageMutex;
|
||
|
||
//--------------------------------------------------------------------
|
||
|
||
DG_SCONNECTION(
|
||
DG_ADDRESS * a_Address,
|
||
RPC_STATUS * pStatus
|
||
);
|
||
|
||
~DG_SCONNECTION();
|
||
|
||
virtual RPC_STATUS
|
||
SealAndSendPacket(
|
||
IN DG_ENDPOINT * SourceEndpoint,
|
||
IN DG_TRANSPORT_ADDRESS RemoteAddress,
|
||
IN UNALIGNED NCA_PACKET_HEADER * Header,
|
||
IN unsigned long DataOffset
|
||
);
|
||
|
||
void
|
||
Activate(
|
||
PNCA_PACKET_HEADER pHeader,
|
||
unsigned short NewHash
|
||
);
|
||
|
||
void Deactivate();
|
||
|
||
PDG_SCALL AllocateCall();
|
||
|
||
void
|
||
FreeCall(
|
||
PDG_SCALL Call
|
||
);
|
||
|
||
void CheckForExpiredCalls();
|
||
|
||
inline BOOL HasExpired();
|
||
|
||
inline void
|
||
DispatchPacket(
|
||
DG_PACKET * Packet,
|
||
DatagramTransportPair *AddressPair
|
||
);
|
||
|
||
RPC_STATUS
|
||
MakeApplicationSecurityCallback(
|
||
RPC_INTERFACE * Interface,
|
||
PDG_SCALL Call
|
||
);
|
||
|
||
inline void
|
||
AddCallToCache(
|
||
DG_SCALL * Call
|
||
);
|
||
|
||
inline LONG
|
||
IncrementRefCount(
|
||
)
|
||
{
|
||
ASSERT(ReferenceCount < 1000);
|
||
return InterlockedIncrement(&ReferenceCount);
|
||
}
|
||
|
||
inline LONG
|
||
DecrementRefCount(
|
||
)
|
||
{
|
||
ASSERT(ReferenceCount > 0);
|
||
return InterlockedDecrement(&ReferenceCount);
|
||
}
|
||
|
||
inline static DG_SCONNECTION *
|
||
FromHashNode(
|
||
UUID_HASH_TABLE_NODE * Node
|
||
)
|
||
{
|
||
return CONTAINING_RECORD (Node, DG_SCONNECTION, ActivityNode);
|
||
}
|
||
|
||
inline LONG GetTimeStamp()
|
||
{
|
||
return TimeStamp;
|
||
}
|
||
|
||
inline BOOL DidCallbackFail()
|
||
{
|
||
if (Callback.State == CallbackFailed)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
VerifyNonRequestPacket(
|
||
DG_PACKET * Packet
|
||
);
|
||
|
||
RPC_STATUS
|
||
VerifyRequestPacket(
|
||
DG_PACKET * Packet
|
||
);
|
||
|
||
RPC_STATUS
|
||
FindOrCreateSecurityContext(
|
||
IN DG_PACKET * pPacket,
|
||
IN DG_TRANSPORT_ADDRESS RemoteAddress,
|
||
OUT unsigned long * pClientSequenceNumber
|
||
);
|
||
|
||
inline SECURITY_CONTEXT *
|
||
FindMatchingSecurityContext(
|
||
DG_PACKET * Packet
|
||
);
|
||
|
||
inline DG_SCALL *
|
||
RemoveIdleCalls(
|
||
DG_SCALL * List,
|
||
BOOL Aggressive,
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
RPC_STATUS
|
||
GetAssociationGroup(
|
||
DG_TRANSPORT_ADDRESS RemoteAddress
|
||
);
|
||
|
||
inline void
|
||
SubmitCallbackIfNecessary(
|
||
PDG_SCALL Call,
|
||
PDG_PACKET Packet,
|
||
DG_TRANSPORT_ADDRESS RemoteAddress
|
||
);
|
||
|
||
void ConvCallCompleted();
|
||
|
||
inline void MessageMutexInitialize( RPC_STATUS *pStatus )
|
||
{
|
||
pMessageMutex = new MUTEX3(pStatus);
|
||
|
||
if (!pMessageMutex)
|
||
{
|
||
*pStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else if (*pStatus != RPC_S_OK)
|
||
{
|
||
delete pMessageMutex;
|
||
pMessageMutex = 0;
|
||
}
|
||
}
|
||
|
||
private:
|
||
|
||
DG_SCALL * CachedCalls;
|
||
|
||
DG_SCALL_TABLE ActiveCalls;
|
||
|
||
SECURITY_CONTEXT_DICT2 SecurityContextDict;
|
||
|
||
unsigned MaxKeySeq;
|
||
|
||
SECURITY_CALLBACK_INFO_DICT2 InterfaceCallbackResults;
|
||
|
||
struct
|
||
{
|
||
CALLBACK_STATE State;
|
||
|
||
RPC_BINDING_HANDLE Binding;
|
||
RPC_ASYNC_STATE AsyncState;
|
||
|
||
DG_SCALL * Call;
|
||
SECURITY_CREDENTIALS * Credentials;
|
||
SECURITY_CONTEXT * SecurityContext;
|
||
BOOL ThirdLegNeeded;
|
||
DWORD DataRep;
|
||
DWORD KeySequence;
|
||
|
||
RPC_UUID CasUuid;
|
||
unsigned long ClientSequence;
|
||
unsigned char * TokenBuffer;
|
||
long TokenLength;
|
||
unsigned char * ResponseBuffer;
|
||
long ResponseLength;
|
||
long MaxData;
|
||
unsigned long DataIndex;
|
||
unsigned long Status;
|
||
}
|
||
Callback;
|
||
|
||
boolean BlockIdleCallRemoval;
|
||
|
||
//--------------------------------------------------------------------
|
||
|
||
void CallDispatchLoop();
|
||
|
||
RPC_STATUS
|
||
FinishConvCallback(
|
||
RPC_STATUS Status
|
||
);
|
||
|
||
BOOL
|
||
HandleMaybeCall(
|
||
PDG_PACKET Packet,
|
||
DatagramTransportPair *AddressPair
|
||
);
|
||
|
||
PDG_SCALL
|
||
HandleNewCall(
|
||
PDG_PACKET Packet,
|
||
DatagramTransportPair *AddressPair
|
||
);
|
||
|
||
RPC_STATUS
|
||
CreateCallbackBindingAndReleaseMutex(
|
||
DG_TRANSPORT_ADDRESS RemoteAddress
|
||
);
|
||
|
||
static void RPC_ENTRY
|
||
ConvNotificationRoutine (
|
||
RPC_ASYNC_STATE * pAsync,
|
||
void * Reserved,
|
||
RPC_ASYNC_EVENT Event
|
||
);
|
||
};
|
||
|
||
|
||
inline SECURITY_CONTEXT *
|
||
DG_SCONNECTION::FindMatchingSecurityContext(
|
||
DG_PACKET * Packet
|
||
)
|
||
{
|
||
DG_SECURITY_TRAILER * Verifier = (DG_SECURITY_TRAILER *)
|
||
(Packet->Header.Data + Packet->GetPacketBodyLen());
|
||
|
||
return SecurityContextDict.Find(Verifier->key_vers_num);
|
||
}
|
||
|
||
class DG_SCALL : public SCALL, public DG_PACKET_ENGINE
|
||
/*++
|
||
|
||
Class Description:
|
||
|
||
This class represents a call in progress on the server.
|
||
|
||
Fields:
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
{
|
||
#ifdef MONITOR_SERVER_PACKET_COUNT
|
||
long OutstandingPacketCount;
|
||
#endif
|
||
|
||
public:
|
||
|
||
long TimeStamp;
|
||
DG_SCALL * Next;
|
||
DG_SCALL * Previous;
|
||
|
||
//------------------------------------------------
|
||
|
||
|
||
inline void *
|
||
operator new(
|
||
IN size_t ObjectLength,
|
||
IN RPC_DATAGRAM_TRANSPORT * TransportInterface
|
||
);
|
||
|
||
DG_SCALL(
|
||
DG_ADDRESS * Address,
|
||
RPC_STATUS * pStatus
|
||
);
|
||
|
||
virtual ~DG_SCALL();
|
||
|
||
//------------------------------------------------
|
||
|
||
virtual RPC_STATUS
|
||
NegotiateTransferSyntax (
|
||
IN OUT PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
GetBuffer (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN UUID *ObjectUuid
|
||
);
|
||
|
||
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
|
||
SendReceive (
|
||
IN OUT PRPC_MESSAGE Message
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ToStringBinding (
|
||
OUT RPC_CHAR PAPI * PAPI * StringBinding
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ImpersonateClient (
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
RevertToSelf (
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
GetAssociationContextCollection (
|
||
OUT ContextCollection **CtxCollection
|
||
);
|
||
|
||
virtual void
|
||
InquireObjectUuid (
|
||
OUT RPC_UUID PAPI * ObjectUuid
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
InquireAuthClient (
|
||
OUT RPC_AUTHZ_HANDLE PAPI * Privileges,
|
||
OUT RPC_CHAR PAPI * PAPI * ServerPrincipalName, OPTIONAL
|
||
OUT unsigned long PAPI * AuthenticationLevel,
|
||
OUT unsigned long PAPI * AuthenticationService,
|
||
OUT unsigned long PAPI * AuthorizationService,
|
||
IN unsigned long Flags
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
ConvertToServerBinding (
|
||
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
InqTransportType(
|
||
OUT unsigned int __RPC_FAR * Type
|
||
) ;
|
||
|
||
virtual RPC_STATUS
|
||
Cancel(
|
||
void * ThreadHandle
|
||
);
|
||
|
||
virtual unsigned TestCancel();
|
||
|
||
virtual RPC_STATUS
|
||
Receive(
|
||
PRPC_MESSAGE Message,
|
||
unsigned Size
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
Send(
|
||
PRPC_MESSAGE Message
|
||
);
|
||
|
||
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
|
||
IsClientLocal(
|
||
IN OUT unsigned * pClientIsLocal
|
||
)
|
||
{
|
||
return RPC_S_CANNOT_SUPPORT;
|
||
}
|
||
|
||
RPC_STATUS
|
||
InqLocalConnAddress (
|
||
IN OUT void *Buffer,
|
||
IN OUT unsigned long *BufferSize,
|
||
OUT unsigned long *AddressFormat
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
AbortAsyncCall (
|
||
IN PRPC_ASYNC_STATE pAsync,
|
||
IN unsigned long ExceptionCode
|
||
);
|
||
|
||
virtual RPC_STATUS
|
||
SetAsyncHandle (
|
||
IN RPC_ASYNC_STATE * pAsync
|
||
);
|
||
|
||
virtual BOOL
|
||
IsSyncCall ()
|
||
{
|
||
return !pAsync;
|
||
}
|
||
|
||
//------------------------------------------------
|
||
|
||
inline void
|
||
DispatchPacket(
|
||
DG_PACKET * Packet,
|
||
IN DG_TRANSPORT_ADDRESS RemoteAddress
|
||
);
|
||
|
||
void DealWithRequest ( PDG_PACKET pPacket );
|
||
void DealWithResponse ( PDG_PACKET pPacket );
|
||
void DealWithPing ( PDG_PACKET pPacket );
|
||
void DealWithFack ( PDG_PACKET pPacket );
|
||
void DealWithAck ( PDG_PACKET pPacket );
|
||
void DealWithQuit ( PDG_PACKET pPacket );
|
||
|
||
//------------------------------------------------
|
||
|
||
inline void
|
||
NewCall(
|
||
DG_PACKET * pPacket,
|
||
DatagramTransportPair *AddressPAir
|
||
);
|
||
|
||
inline void
|
||
BindToConnection(
|
||
PDG_SCONNECTION a_Connection
|
||
);
|
||
|
||
BOOL
|
||
DG_SCALL::FinishSendOrReceive(
|
||
BOOL Abort
|
||
);
|
||
|
||
inline BOOL ReadyToDispatch();
|
||
|
||
void ProcessRpcCall();
|
||
|
||
inline BOOL
|
||
HasExpired(
|
||
BOOL Aggressive,
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
BOOL Cleanup();
|
||
|
||
inline BOOL IsSynchronous();
|
||
|
||
void
|
||
FreeAPCInfo (
|
||
IN RPC_APC_INFO *pAPCInfo
|
||
);
|
||
|
||
inline void IncrementRefCount();
|
||
inline void DecrementRefCount();
|
||
|
||
inline void
|
||
ConvCallbackFailed(
|
||
DWORD Status
|
||
)
|
||
{
|
||
pSavedPacket->Header.SequenceNumber = SequenceNumber;
|
||
|
||
InitErrorPacket(pSavedPacket, DG_REJECT, Status);
|
||
SealAndSendPacket(&pSavedPacket->Header);
|
||
Cleanup();
|
||
}
|
||
|
||
virtual RPC_STATUS
|
||
InqConnection (
|
||
OUT void **ConnId,
|
||
OUT BOOL *pfFirstCall
|
||
)
|
||
{
|
||
ASSERT(Connection);
|
||
*ConnId = Connection;
|
||
|
||
if (InterlockedIncrement((LONG *) &(Connection->fFirstCall)) == 1)
|
||
{
|
||
*pfFirstCall = 1;
|
||
}
|
||
else
|
||
{
|
||
*pfFirstCall = 0;
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
private:
|
||
|
||
enum CALL_STATE
|
||
{
|
||
CallInit = 0x201,
|
||
CallBeforeDispatch,
|
||
CallDispatched,
|
||
xxxxObsolete,
|
||
CallAfterDispatch,
|
||
CallSendingResponse,
|
||
CallComplete,
|
||
CallBogus = 0xfffff004
|
||
};
|
||
|
||
CALL_STATE State;
|
||
CALL_STATE PreviousState;
|
||
|
||
boolean CallInProgress;
|
||
boolean CallWasForwarded;
|
||
boolean KnowClientAddress;
|
||
boolean TerminateWhenConvenient;
|
||
|
||
DG_SCONNECTION * Connection;
|
||
RPC_INTERFACE * Interface;
|
||
|
||
//
|
||
// Data to monitor pipe data transfer.
|
||
//
|
||
unsigned long PipeThreadId;
|
||
|
||
PENDING_OPERATION PipeWaitType;
|
||
unsigned long PipeWaitLength;
|
||
|
||
//
|
||
// The only unusual aspect of this is that it's an auto-reset event.
|
||
// It is created during the first call on a pipe interface.
|
||
//
|
||
EVENT * PipeWaitEvent;
|
||
|
||
//
|
||
// Stuff for RpcBindingInqAuthClient.
|
||
//
|
||
RPC_AUTHZ_HANDLE Privileges;
|
||
unsigned long AuthorizationService;
|
||
|
||
DWORD LocalAddress; // IP address, network byte order encoded
|
||
|
||
//---------------------------------------------------------------------
|
||
|
||
inline void
|
||
SetState(
|
||
CALL_STATE NewState
|
||
)
|
||
{
|
||
if (NewState != State)
|
||
{
|
||
LogEvent(SU_SCALL, EV_STATE, this, 0, NewState);
|
||
}
|
||
|
||
PreviousState = State;
|
||
State = NewState;
|
||
}
|
||
|
||
virtual BOOL
|
||
IssueNotification (
|
||
IN RPC_ASYNC_EVENT Event
|
||
);
|
||
|
||
void
|
||
AddPacketToReceiveList(
|
||
PDG_PACKET pPacket
|
||
);
|
||
|
||
RPC_STATUS
|
||
UnauthenticatedCallback(
|
||
unsigned * pClientSequenceNumber
|
||
);
|
||
|
||
RPC_STATUS
|
||
SendFragment(
|
||
PRPC_MESSAGE pMessage,
|
||
unsigned FragNum,
|
||
unsigned char PacketType
|
||
);
|
||
|
||
RPC_STATUS
|
||
SealAndSendPacket(
|
||
NCA_PACKET_HEADER * Header
|
||
);
|
||
|
||
RPC_STATUS
|
||
SendPacketBack(
|
||
NCA_PACKET_HEADER * pNcaPacketHeader,
|
||
unsigned TrailerSize
|
||
);
|
||
|
||
RPC_STATUS
|
||
CreateReverseBinding (
|
||
RPC_BINDING_HANDLE * pServerBinding,
|
||
BOOL IncludeEndpoint
|
||
);
|
||
|
||
void
|
||
SaveOriginalClientInfo(
|
||
DG_PACKET * pPacket
|
||
);
|
||
|
||
inline RPC_STATUS
|
||
AssembleBufferFromPackets(
|
||
IN OUT PRPC_MESSAGE Message
|
||
);
|
||
|
||
RPC_STATUS WaitForPipeEvent();
|
||
|
||
//------------------------------------------------
|
||
// ConvertSidToUserW() is used to get transport supplied
|
||
// auth. info. The only DG transport that uses this is
|
||
// Falcon. The SID for the client user that sent the
|
||
// "current" request is cashed along with the user name.
|
||
// So, if the next call on this activity has the same
|
||
// SID we can return the user without hitting the domain
|
||
// server.
|
||
|
||
RPC_STATUS
|
||
ConvertSidToUserW(
|
||
IN SID *pSid,
|
||
OUT RPC_CHAR **ppwsPrincipal
|
||
);
|
||
|
||
SID *pCachedSid;
|
||
RPC_CHAR *pwsCachedUserName;
|
||
DWORD dwCachedUserNameSize;
|
||
|
||
boolean FinalSendBufferPresent;
|
||
|
||
RPC_MESSAGE RpcMessage;
|
||
RPC_RUNTIME_INFO RpcRuntimeInfo ;
|
||
};
|
||
|
||
|
||
inline void *
|
||
DG_SCALL::operator new(
|
||
IN size_t ObjectLength,
|
||
IN RPC_DATAGRAM_TRANSPORT * TransportInterface
|
||
)
|
||
{
|
||
return new char[ObjectLength + TransportInterface->AddressSize];
|
||
}
|
||
|
||
inline void DG_SCALL::DecrementRefCount()
|
||
{
|
||
Connection->Mutex.VerifyOwned();
|
||
|
||
--ReferenceCount;
|
||
|
||
LogEvent(SU_SCALL, EV_DEC, this, 0, ReferenceCount);
|
||
}
|
||
|
||
inline void DG_SCALL::IncrementRefCount()
|
||
{
|
||
Connection->Mutex.VerifyOwned();
|
||
|
||
++ReferenceCount;
|
||
|
||
LogEvent(SU_SCALL, EV_INC, this, 0, ReferenceCount);
|
||
}
|
||
|
||
|
||
void
|
||
DG_SCALL::BindToConnection(
|
||
PDG_SCONNECTION a_Connection
|
||
)
|
||
{
|
||
Connection = a_Connection;
|
||
|
||
ReadConnectionInfo(Connection, this + 1);
|
||
|
||
pSavedPacket->Header.ServerBootTime = ProcessStartTime;
|
||
pSavedPacket->Header.ActivityHint = (unsigned short) Connection->ActivityHint;
|
||
pSavedPacket->Header.InterfaceHint = 0xffff;
|
||
}
|
||
|
||
inline BOOL
|
||
DG_SCALL::IsSynchronous(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Simply tells whether the call is sycnhronous or asynchronous.
|
||
|
||
The return value won't be reliable if the call was instantiated
|
||
by a packet other than a REQUEST and no REQUEST has yet arrived,
|
||
so be careful to call it only after a REQUEST has arrived.
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
TRUE if synchronous
|
||
FALSE if asynchronous
|
||
|
||
--*/
|
||
|
||
{
|
||
if (BufferFlags & RPC_BUFFER_ASYNC)
|
||
{
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
|
||
inline RPC_STATUS
|
||
DG_SCALL::AssembleBufferFromPackets(
|
||
IN OUT PRPC_MESSAGE Message
|
||
)
|
||
{
|
||
RPC_STATUS Status = DG_PACKET_ENGINE::AssembleBufferFromPackets(Message, this);
|
||
|
||
if (RPC_S_OK == Status && (Message->RpcFlags & RPC_BUFFER_EXTRA))
|
||
{
|
||
PRPC_RUNTIME_INFO Info = (PRPC_RUNTIME_INFO) Message->ReservedForRuntime;
|
||
|
||
Info->OldBuffer = Message->Buffer;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
inline RPC_STATUS
|
||
DG_SCALL::InqTransportType(
|
||
OUT unsigned int __RPC_FAR * Type
|
||
)
|
||
{
|
||
*Type = TRANSPORT_TYPE_DG ;
|
||
|
||
return (RPC_S_OK) ;
|
||
}
|
||
|
||
inline RPC_STATUS
|
||
DG_SCALL::SealAndSendPacket(
|
||
NCA_PACKET_HEADER * Header
|
||
)
|
||
{
|
||
Header->ServerBootTime = ProcessStartTime;
|
||
SetMyDataRep(Header);
|
||
|
||
unsigned Frag = (Header->PacketType << 16) | Header->FragmentNumber;
|
||
LogEvent(SU_SCALL, EV_PKT_OUT, this, 0, Frag);
|
||
|
||
return Connection->SealAndSendPacket(SourceEndpoint, RemoteAddress, Header, 0);
|
||
}
|
||
|
||
//------------------------------------------------------------------------
|
||
|
||
|
||
class SERVER_ACTIVITY_TABLE : private UUID_HASH_TABLE
|
||
{
|
||
public:
|
||
|
||
inline
|
||
SERVER_ACTIVITY_TABLE(
|
||
RPC_STATUS * pStatus
|
||
) :
|
||
UUID_HASH_TABLE ( pStatus )
|
||
{
|
||
LastFinishTime = 0;
|
||
BucketCounter = 0;
|
||
}
|
||
|
||
inline
|
||
~SERVER_ACTIVITY_TABLE(
|
||
)
|
||
{
|
||
}
|
||
|
||
inline DG_SCONNECTION *
|
||
FindOrCreate(
|
||
DG_ADDRESS * Address,
|
||
PDG_PACKET pPacket
|
||
);
|
||
|
||
inline void Prune();
|
||
|
||
BOOL
|
||
PruneEntireTable(
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
BOOL PruneSpecificBucket(
|
||
unsigned Bucket,
|
||
BOOL Aggressive,
|
||
RPC_INTERFACE * Interface
|
||
);
|
||
|
||
void SERVER_ACTIVITY_TABLE::BeginIdlePruning();
|
||
|
||
static void SERVER_ACTIVITY_TABLE::PruneWhileIdle( PVOID unused );
|
||
|
||
private:
|
||
|
||
long LastFinishTime;
|
||
long BucketCounter;
|
||
|
||
DELAYED_ACTION_NODE IdleScavengerTimer;
|
||
};
|
||
|
||
|
||
class ASSOC_GROUP_TABLE : private UUID_HASH_TABLE
|
||
{
|
||
public:
|
||
|
||
inline
|
||
ASSOC_GROUP_TABLE(
|
||
RPC_STATUS * pStatus
|
||
)
|
||
: UUID_HASH_TABLE(pStatus)
|
||
{
|
||
}
|
||
|
||
inline
|
||
~ASSOC_GROUP_TABLE(
|
||
)
|
||
{
|
||
}
|
||
|
||
inline ASSOCIATION_GROUP *
|
||
FindOrCreate(
|
||
RPC_UUID * pUuid,
|
||
unsigned short InitialPduSize
|
||
);
|
||
|
||
inline void
|
||
DecrementRefCount(
|
||
ASSOCIATION_GROUP * pClient
|
||
);
|
||
};
|
||
|
||
|
||
inline void
|
||
DG_SCONNECTION::AddCallToCache(
|
||
DG_SCALL * Call
|
||
)
|
||
{
|
||
Mutex.VerifyOwned();
|
||
|
||
ASSERT( !Call->InvalidHandle(DG_SCALL_TYPE) );
|
||
ASSERT( !CachedCalls || !CachedCalls->InvalidHandle(DG_SCALL_TYPE) );
|
||
|
||
Call->TimeStamp = GetTickCount();
|
||
Call->Next = CachedCalls;
|
||
CachedCalls = Call;
|
||
|
||
LogEvent(SU_SCALL, EV_STOP, Call, this, Call->GetSequenceNumber() );
|
||
}
|
||
|
||
//------------------------------------------------------------------------
|
||
|
||
BOOL
|
||
StripForwardedPacket(
|
||
IN PDG_PACKET pPacket,
|
||
IN void * pFromEndpoint
|
||
);
|
||
|
||
extern unsigned long ServerBootTime;
|
||
|
||
|
||
#endif // __DGSVR_HXX__
|
||
|
||
|