windows-nt/Source/XPSP1/NT/com/rpc/runtime/trans/common/trans.hxx
2020-09-26 16:20:57 +08:00

1358 lines
33 KiB
C++

/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
trans.hxx
Abstract:
Commen base for all NT transport interfaces.
Author:
Mario Goertzel [MarioGo]
Revision History:
MarioGo 4/12/1996 Bits 'n pieces
MarioGo 10/24/1996 Async RPC
EdwardR 07/04/1997 Falcon/RPC
--*/
#ifndef __TRANS_HXX
#define __TRANS_HXX
#include "Dbg.hxx"
//
// Winsock address types.
//
union WS_SOCKADDR
{
SOCKADDR generic;
SOCKADDR_IN inetaddr;
#ifndef SPX_IPX_OFF
SOCKADDR_IPX ipxaddr;
#endif
SOCKADDR_AT ataddr;
#ifdef NETBIOS_ON
SOCKADDR_NB nbaddr;
#endif
SOCKADDR_CLUSTER clusaddr;
SOCKADDR_STORAGE ipaddr;
};
inline void
RpcpSetIpPort (
IN WS_SOCKADDR *SockAddress,
IN USHORT Port
)
{
SS_PORT(SockAddress) = Port;
}
inline USHORT
RpcpGetIpPort (
IN WS_SOCKADDR *SockAddress
)
{
return SS_PORT(SockAddress);
}
inline void
RpcpCopyIPv6Address (
IN SOCKADDR_IN6 *SourceAddress,
OUT SOCKADDR_IN6 *TargetAddress
)
{
RpcpMemoryCopy(&TargetAddress->sin6_addr,
&SourceAddress->sin6_addr,
sizeof(in6_addr));
}
inline void
RpcpCopyIPv4Address (
IN SOCKADDR_IN *SourceAddress,
OUT SOCKADDR_IN *TargetAddress
)
{
TargetAddress->sin_addr.s_addr = SourceAddress->sin_addr.s_addr;
}
//
//
// Async object types
//
struct BASE_ASYNC_OBJECT;
//
// Every outstanding async IO has an overlapped structure associated
// with it.
//
struct BASE_OVERLAPPED
{
//
// Pointer to the transport object this IO is associated with.
// This is needed since a single object may have more than one
// pending IO request.
//
BASE_ASYNC_OBJECT *pAsyncObject;
//
// System overlapped structure associated with the async IO.
//
OVERLAPPED ol;
//
// RPC thread object of the thread which started the IO. This is used
// when the IO completes to keep the count of IO pending on a thread.
//
PVOID thread;
};
typedef BASE_OVERLAPPED *PBASE_OVERLAPPED;
#ifdef NCADG_MQ_ON
struct MQ_OVERLAPPED : BASE_OVERLAPPED
{
// MSMQ Messages have there own structure which must be maintained
// during the span of the async IO request:
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
HRESULT aStatus[MAX_RECV_VAR];
};
typedef MQ_OVERLAPPED *PMQ_OVERLAPPED;
#endif
// BASE_ASYNC_OBJECT is the basis for all objects which
// are used in async I/O.
// There are three basic objects which are used in I/O,
// addresses, connections and datagrams.
//
// BASE_ADDRESS is the basis for all I/O which is
// used to listen for new client connections.
//
// BASE_CONNECTION is the basis for all I/O which is
// used to read/write to a connection.
//
// There are currently three flavors of address and
// and connections:
// WS_ (winsock connection base protocols)
// NB_ (not supported on Itaniums - winsock based, but unique historical reasons)
// NMP_ (named pipes)
//
// BASE_DATAGRAM is the basis for all I/O which is pending
// on a datagram port. The only flavor today is winsock.
//
//
// BASE_ASYNC_OBJECT
// |
// +---------------------|-------------------------+
// BASE_ADDRESS BASE_CONNECTION BASE_DATAGRAM
// | | | | | | |
// CO_ADDRESS | WS_DG_ADDR | WS_CONNECTION | WS_DATAGRAM
// | | MQ_DG_ADDR | | MQ_DATAGRAM
// NMP_ADDR | NMP_CONNECTION |
// WS_ADDR |
// | +---------+----------+
// NB_ADDR | |
// WS_CLIENT_CONNECTION WS_SAN_CONNECTION
// |
// |
// WS_SAN_CLIENT_CONNECTION
//
struct BASE_ASYNC_OBJECT;
struct BASE_ASYNC_OBJECT
{
//
// a placeholder for the vtbl of derived objects
// this makes casts safe and fast at the expense of some
// memory waste. That's ok
//
virtual void DoNothing(void)
{
}
//
// The type of this object. Used in determining where
// to send the completed I/O.
//
RPC_TRANSPORT_EVENT type;
//
// Identifies the protcol of the address/connection.
//
PROTOCOL_ID id;
//
// > 0 means that the object has been aborted
//
LONG fAborted;
//
// Used to chain objects belonging to the
// same protocol.
//
LIST_ENTRY ObjectList;
};
typedef BASE_ASYNC_OBJECT *PREQUEST;
struct BASE_ADDRESS;
class BASE_CONNECTION;
typedef void (*TRANS_ADDRESS_LISTEN)(BASE_ADDRESS *);
enum ADDRESS_STATE {
NotInList,
InTheList,
Inactive
};
#define TRANSPORT_POSTED_KEY UINT_PTR(0xFFFF0000)
//
// Address objects represent a connection oriented endpoint which
// is connected to by a client at which time a connection object
// is created for the specific client.
// There are relatively few address objects in the system
//
struct BASE_ADDRESS : BASE_ASYNC_OBJECT
{
//
// The endpoint this address is listening on.
//
RPC_CHAR *Endpoint;
//
// List of network addresses for this address
//
NETWORK_ADDRESS_VECTOR *pAddressVector;
//
// Function to call when a listen is aborted or when
// an address doesn't have an outstanding listens.
//
TRANS_ADDRESS_LISTEN SubmitListen;
//
// NotInList is address in not in the AddressManager list
// InTheList if the address has been inserted into the list
// InActive if it is in the list, but it is inactive
//
ADDRESS_STATE InAddressList;
//
// Endpoint flags used in conjunction with firewalls
//
ULONG EndpointFlags;
//
// If an address is unable to (or has not yet) submitted
// an listen request then it is stuck into a linked list.
// This is the forward list pointer.
//
BASE_ADDRESS *pNext;
//
// In order to callback into the runtime we must pass the
// first (runtime allocated) address when calling back.
//
struct BASE_ADDRESS *pFirstAddress;
//
// Each netbios address may represent several listen sockets (one
// for each lana). A list of these is maintained to facilitate aborting
// the setup of an entire address.
//
struct BASE_ADDRESS *pNextAddress;
//
// Static or dynamic ?
//
BOOL fDynamicEndpoint;
};
struct CO_ADDRESS;
typedef RPC_STATUS (*TRANS_NEW_CONNECTION)(CO_ADDRESS *, BASE_CONNECTION **);
struct CO_ADDRESS : BASE_ADDRESS
{
//
// Overlapped object associated with the pending accept/connect
//
BASE_OVERLAPPED Listen;
//
// Function to call when a connection notification arrives.
//
TRANS_NEW_CONNECTION NewConnection;
};
typedef CO_ADDRESS *PADDRESS;
struct NMP_ADDRESS : CO_ADDRESS
{
//
// The handle of the pipe instance currently
// avaliable for clients to connect to.
//
HANDLE hConnectPipe;
//
// When we disconnect a client we save an extra pipe instance here
// to use on the next client connection. This is a performance optimization,
// but also affects correctness. See NMP_ServerListen where the first
// spare pipe is created.
//
HandleCache sparePipes;
//
// The self relative security descriptor associated with
// this addresss.
//
PSECURITY_DESCRIPTOR SecurityDescriptor;
//
// The complete pipe name for this addresses
// endpoint including "\\."
//
RPC_CHAR *LocalEndpoint;
};
typedef NMP_ADDRESS *PNMP_ADDRESS;
struct WS_ADDRESS : CO_ADDRESS
{
//
// The socket listening on this addresses port.
//
SOCKET ListenSocket;
//
// The socket of the next client to connect. It is waiting
// in an AcceptEx for the client to connect.
//
SOCKET ConnectionSocket;
//
// Netbios requires that the a protocol be multiplied by the
// lana number. For other protocols this should be one.
//
DWORD ProtocolMultiplier;
//
// The PendingQueueSize parameter supplied when the address
// was created
//
INT QueueSize;
//
// Buffer for the address of the client which is part of the
// outstanding AcceptEx call on the listen socket.
//
BYTE AcceptBuffer[sizeof(WS_SOCKADDR) + 16];
//
// the sockaddr used to setup this address
//
WS_SOCKADDR ListenAddr;
union
{
struct
{
LPFN_ACCEPTEX pAcceptExFunction;
LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockaddressFunction;
};
void *ExtensionFunctionPointers[2];
};
static const int AcceptExFunctionId;
static const int GetAcceptExSockAddressFunctionId;
static const UUID ExtensionFunctionsUuids[];
BOOL GetExtensionFunctionPointers(SOCKET sock);
BOOL GetExtensionFunctionPointerForFunction(SOCKET sock, int nFunctionCode);
};
inline DWORD
GetProtocolMultiplier (
IN WS_ADDRESS *Address
)
{
#ifdef NETBIOS_ON
return Address->ProtocolMultiplier;
#else
return 1;
#endif
}
inline void
SetProtocolMultiplier (
IN WS_ADDRESS *Address,
IN DWORD ProtocolMultiplier
)
{
#ifdef NETBIOS_ON
Address->ProtocolMultiplier = ProtocolMultiplier;
#endif
}
typedef WS_ADDRESS *PWS_ADDRESS;
struct WS_DATAGRAM;
typedef WS_DATAGRAM *PWS_DATAGRAM;
struct WS_DATAGRAM_ENDPOINT : BASE_ADDRESS
{
// WS_DATAGRAM_ENDPOINTs represent either a client or server
// port. There will be a small number of these on servers and
// O(N) active threads on sync clients.
//
// The socket we're listen on.
//
SOCKET Socket;
//
// Normally FALSE, set to true by a thread which is submitting
// new IOs on the endpoint.
//
LONG fSubmittingIos;
//
// Current number of WS_DATAGRAM's submitted on this endpoint.
// Must be changed via InterlockedInc/Dec. The count of
// non-null entries in aIdleDatagrams.
//
LONG cPendingIos;
//
// If cPendingIos is less than the minimum then recvs on any idle
// WS_DATAGRAMs should be posted.
//
// const after initialization.
//
LONG cMinimumIos;
//
// The number of WS_DATAGRAMs available for this endpoint to use.
//
// const after initialization.
//
LONG cMaximumIos;
//
// Array of cMaxIos datagrams. NULL in sync endpoints.
//
PWS_DATAGRAM aDatagrams;
//
// Client or Server ?
//
BOOL fClient;
//
// Sync or Async ?
//
BOOL fAsync;
//
// Sockaddr
//
WS_SOCKADDR ListenAddr;
};
#ifdef NCADG_MQ_ON
struct MQ_DATAGRAM;
typedef MQ_DATAGRAM *PMQ_DATAGRAM;
struct MQ_DATAGRAM_ENDPOINT : BASE_ADDRESS
{
// MQ_DATAGRAM_ENDPOINTs represent either a client or server
// port. There will be a small number of these on servers and
// O(N) active threads on sync clients.
//
// The queue we're listen on.
//
UUID uuidQType; //
QUEUEHANDLE hQueue;
QUEUEHANDLE hAdminQueue;
BOOL fAllowReceives;
RPC_CHAR wsMachine[MAX_COMPUTERNAME_LEN];
RPC_CHAR wsQName[MQ_MAX_Q_NAME_LEN];
RPC_CHAR wsQPathName[MAX_PATHNAME_LEN];
RPC_CHAR wsQFormat[MAX_FORMAT_LEN];
RPC_CHAR wsAdminQFormat[MAX_FORMAT_LEN];
ULONG ulDelivery;
ULONG ulPriority;
ULONG ulJournaling;
ULONG ulTimeToReachQueue; // Seconds.
ULONG ulTimeToReceive; // Seconds.
BOOL fAck;
BOOL fAuthenticate; // Server security tracking.
BOOL fEncrypt;
ULONG ulPrivacyLevel; // Server security tracking.
//
// Normally FALSE, set to true by a thread which is submitting
// new IOs on the endpoint.
//
LONG fSubmittingIos;
//
// Current number of WS_DATAGRAM's submitted on this endpoint.
// Must be changed via InterlockedInc/Dec. The count of
// non-null entries in aIdleDatagrams.
//
LONG cPendingIos;
//
// If cPendingIos is less than the minimum then recvs on any idle
// WS_DATAGRAMs should be posted.
//
// const after initialization.
//
LONG cMinimumIos;
//
// The number of WS_DATAGRAMs available for this endpoint to use.
//
// const after initialization.
//
LONG cMaximumIos;
//
// Array of cMaxIos datagrams. NULL in sync endpoints.
//
PMQ_DATAGRAM aDatagrams;
};
#endif
//
// Structure allocated by the runtime and associated with
// a pending send operation.
//
struct CO_SEND_CONTEXT
{
//
// Overlapped object associated with the pending async write.
//
BASE_OVERLAPPED Write;
//
// The buffer which is currently being written
//
BUFFER pWriteBuffer;
//
// Size of the write buffer (as far as we know)
//
DWORD maxWriteBuffer;
};
#if defined(_ALPHA_)
#ifdef __cplusplus
extern "C" { __int64 __asm(char *,...); };
#pragma intrinsic(__asm)
#endif
#define MBInstruction __asm("mb")
#endif
//
// Connection objects are used for async reads (future: writes)
// from a single client based on that client's connection to
// this server.
//
// There maybe 100's or 1000's of connection objects allocated.
//
class BASE_CONNECTION : public BASE_ASYNC_OBJECT
{
public:
BASE_CONNECTION(void)
{
}
void
Initialize (
void
);
//
// The socket (or handle) of the client connection.
// We use a union to avoid type casting this everywhere.
//
union {
SOCKET Socket;
HANDLE Handle;
} Conn;
private:
//
// Incremented when a thread is just about to start an IO, just
// before it checks fAborted. The aborting thread must wait for
// this to reach 0 before closing the connection.
//
LONG StartingWriteIo;
LONG StartingReadIo;
public:
//
// We use a heuristic for choosing the size of receives to post. This
// starts are CO_MIN_RECV size and is increased as we see larger
// IOs on the connection.
UINT iPostSize;
//
// The size of the outstanding read buffer.
//
DWORD maxReadBuffer;
//
// The number of bytes in pReadBuffer that where read
// as part of a previous read.
//
UINT iLastRead;
//
// Overlapped object associated with the pending async read
//
BASE_OVERLAPPED Read;
//
// A buffer for the outstanding read of maxReadBuffer bytes.
// Also used a flag, if 0 then no read is pending.
//
BUFFER pReadBuffer;
inline void StartingWriteIO(void)
{
InterlockedIncrement(&StartingWriteIo);
}
inline void StartingReadIO(void)
{
#if defined(i386) || defined (_ALPHA_)
// if we are the first, we know there won't be other guys around
if (StartingReadIo == 0)
{
StartingReadIo = 1;
#if defined (_ALPHA_)
MBInstruction;
#endif
}
else
{
// there may be other guys around - be safe
InterlockedIncrement(&StartingReadIo);
}
#else
InterlockedIncrement(&StartingReadIo);
#endif
}
inline void StartingOtherIO(void)
{
// we use the StartingWriteIo because it
// doesn't shortcut transition from 0 to 1st
InterlockedIncrement(&StartingWriteIo);
}
inline void WriteIOFinished(void)
{
InterlockedDecrement(&StartingWriteIo);
}
// ********************* NOTE *************************************
// After you return from this function, if the read is successful, you
// can no longer touch the connection (transport level or runtime) -
// it may have been destroyed
inline void ReadIOFinished(void)
{
InterlockedDecrement(&StartingReadIo);
}
inline void OtherIOFinished(void)
{
InterlockedDecrement(&StartingWriteIo);
}
inline BOOL IsIoStarting(void)
{
return StartingWriteIo || StartingReadIo;
}
inline void InitIoCounter(void)
{
StartingWriteIo = 0;
StartingReadIo = 0;
}
virtual RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped) = 0;
virtual RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped) = 0;
virtual RPC_STATUS ProcessRead(IN DWORD bytes, OUT BUFFER *pBuffer,
OUT PUINT pBufferLength);
virtual RPC_STATUS Abort(void) = 0;
};
typedef BASE_CONNECTION *PCONNECTION;
RPC_STATUS
UTIL_ReadFile(
IN HANDLE hFile,
IN LPVOID lpBuffer,
IN DWORD nNumberOfBytesToRead,
OUT LPDWORD lpNumberOfBytesRead,
IN OUT LPOVERLAPPED lpOverlapped
);
RPC_STATUS
UTIL_WriteFile(
IN HANDLE hFile,
IN LPCVOID lpBuffer,
IN DWORD nNumberOfBytesToWrite,
OUT LPDWORD lpNumberOfBytesWritten,
IN OUT LPOVERLAPPED lpOverlapped
);
class NMP_CONNECTION : public BASE_CONNECTION
{
public:
//
// Pointer to my address used to store any extra pipe
// instance when closed.
//
PNMP_ADDRESS pAddress;
RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
return UTIL_ReadFile(hFile, lpBuffer, nNumberOfBytesToRead,
lpNumberOfBytesRead, lpOverlapped);
}
RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
return UTIL_WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
}
virtual RPC_STATUS Abort(void);
};
typedef NMP_CONNECTION *PNMP_CONNECTION;
class WS_CONNECTION : public BASE_CONNECTION
{
public:
WS_CONNECTION(void)
{
}
//
// The address of the client is returned as part of
// the connection and saved here to support
// *_QueryClientAddress().
//
WS_SOCKADDR saClientAddress;
WS_ADDRESS *pAddress;
virtual RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);
virtual RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
virtual RPC_STATUS Abort(void);
};
typedef WS_CONNECTION *PWS_CONNECTION;
class SAN_CONNECTION
{
public:
SAN_CONNECTION(void)
{
}
RPC_STATUS SANReceive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);
RPC_STATUS SANSend(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
private:
DWORD m_dwFlags;
};
class HTTP2SocketTransportChannel; // forward
class WS_HTTP2_CONNECTION;
typedef RPC_STATUS
(RPC_ENTRY *HTTP2_READ_HEADER)
(
IN WS_HTTP2_CONNECTION *Connection,
IN ULONG BytesRead,
OUT ULONG *NewBytesRead
);
/*++
Routine Description:
Read a channel HTTP header (usually some string). In success
case, there is real data in Connection->pReadBuffer. The
number of bytes there is in NewBytesRead
Arguments:
Connection - the connection on which the header arrived.
BytesRead - the bytes received from the net
NewBytesRead - the bytes read from the channel (success only)
Return Value:
RPC_S_OK or other RPC_S_* errors for error
--*/
class WS_HTTP2_CONNECTION : public WS_CONNECTION, public SAN_CONNECTION
{
public:
HTTP2SocketTransportChannel *Channel;
RPC_STATUS ProcessReceiveFailed (IN RPC_STATUS EventStatus);
virtual RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
virtual RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);
RPC_STATUS ProcessSendComplete (
IN RPC_STATUS EventStatus,
IN CO_SEND_CONTEXT *SendContext
);
// no-op for compatibility with common transport layer
virtual RPC_STATUS ProcessRead(
IN DWORD bytes,
OUT BUFFER *pBuffer,
OUT PUINT pBufferLength
);
// the actual read
RPC_STATUS ProcessReceiveComplete(
IN DWORD bytes,
OUT BUFFER *pBuffer,
OUT PUINT pBufferLength
);
void Initialize (
void
);
void Free (
void
);
// no-op for HTTP2 connections. They get
// aborted from RealAbort
virtual RPC_STATUS Abort(void);
// actual code to abort the connection
void RealAbort(void);
BOOL HeaderRead;
HTTP2_READ_HEADER ReadHeaderFn;
void *RuntimeConnectionPtr; // the transport connection from
// runtime perspective. Never called
// directly - just a token to pass
// to runtime
};
// WS_HTTP2_INITIAL_CONNECTION - a version of WS_HTTP2_CONNECTION that
// is used before the type of connection HTTP2 or HTTP is known on the
// server. It has the capability to recognize the first packet and morph
// into WS_HTTP2_CONNECTION (for HTTP2) or WS_CONNECTION (for HTTP)
class WS_HTTP2_INITIAL_CONNECTION : public WS_HTTP2_CONNECTION
{
public:
virtual RPC_STATUS ProcessRead(
IN DWORD bytes,
OUT BUFFER *pBuffer,
OUT PUINT pBufferLength
);
virtual RPC_STATUS Abort(void);
};
class WS_CLIENT_CONNECTION : public WS_CONNECTION
{
public:
// Additional state needed in client-side sync calls on TCP/IP to
// handle shutdowns.
//
// State of the connection, used to keep track of shutdowns for TCP/IP.
// Reset after a recv() call so that the next send operation will
// check for shutdowns.
//
BOOL fCallStarted;
//
// True if we received a shutdown packet during the last send operation.
//
BOOL fShutdownReceived;
//
// True if we posted a receive to check for a shutdown the receive
// is (was) still pending.
//
BOOL fReceivePending;
//
// The time of the last RPC call finished on this connection. This
// is used to determine if a shutdown check is needed.
//
DWORD dwLastCallTime;
//
// Com timeout
//
UINT Timeout;
};
typedef WS_CLIENT_CONNECTION *PWS_CCONNECTION;
class WS_SAN_CONNECTION : public WS_CONNECTION, public SAN_CONNECTION
{
RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
return SANReceive(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
return SANSend(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
};
class WS_SAN_CLIENT_CONNECTION : public WS_CLIENT_CONNECTION, public SAN_CONNECTION
{
RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
return SANReceive(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
return SANSend(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
};
#ifdef NETBIOS_ON
class NB_CONNECTION : public WS_CONNECTION
{
public:
// In order to support the old Netbios (3.1/Dos) style programming
// interface netbios fragments sent from the client to the server
// must contain a sequence number. It allowed for in-order delivery
// of fragments on such a system. While not required today it is still
// part of the wire protocol. The sequence numbers must be incremented
// on each fragment sent. The sequence number is reset after each call.
// REVIEW: When multiple async calls are outstanding the sequence number
// will be wrong.
ULONG SequenceNumber;
// the next members need to be aligned in a way that will ensure that
// fReceivePending is at the same offset as fReceivePending in
// WS_CLIENT_CONNECTION. Some functions manipulate them in the same
// way and we need to make sure they are consistent. This is just
// documenting an existing code idiosyncracy
BOOL Reserved[1];
BOOL fReceivePending;
virtual RPC_STATUS ProcessRead(IN DWORD bytes, OUT BUFFER *pBuffer,
OUT PUINT pBufferLength);
};
typedef NB_CONNECTION *PNB_CONNECTION;
class NB_SAN_CONNECTION : public NB_CONNECTION, SAN_CONNECTION
{
RPC_STATUS Receive(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
return SANReceive(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
RPC_STATUS Send(HANDLE hFile, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
return SANSend(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
};
#endif
//
// Datagram object represent both addresses and connections for
// datagram. Since all client IO is multiplexed through a single
// port there are not per client objects.
//
// There maybe O(# processors) of these objects allocated for
// each address (endpoint). This is not very many.
//
struct BASE_DATAGRAM : BASE_ASYNC_OBJECT
{
//
// The endpoint on which requests will be received. This will
// actually be either a WS_DATAGRAM_ENDPOINT or a MQ_DATAGRAM_ENDPOINT.
//
BASE_ADDRESS *pEndpoint;
};
struct WS_DATAGRAM : BASE_DATAGRAM
{
// If FALSE then the datagram is available to submit a recv on.
BOOL Busy;
// Size of the address received (ignored but needs to be
// writeable during the async IO completion.)
INT cRecvAddr;
// Address object to receive the remote/local address of the datagram.
// The object itself is in the runtime packet object
DatagramTransportPair *AddressPair;
// The IO buffer used to receive the packet.
WSABUF Packet;
// Async IO control information
BASE_OVERLAPPED Read;
// The message used to control the operation
WSAMSG Msg;
// The control information for the message
char MessageAncillaryData[WSA_CMSG_SPACE(sizeof(in_pktinfo))];
};
typedef WS_DATAGRAM *PWS_DATAGRAM;
#ifdef NCADG_MQ_ON
struct MQ_DATAGRAM : BASE_DATAGRAM
{
// If FALSE then the datagram is available to submit a recv on.
BOOL Busy;
// Size of the address received.
INT cRecvAddr;
// Address object to receive the source address of the datagram.
MQ_ADDRESS *pAddress;
// The IO buffer used to receive the packet.
ULONG dwPacketSize;
UCHAR *pPacket;
// Async IO control information
MQ_OVERLAPPED Read;
};
typedef MQ_DATAGRAM *PMQ_DATAGRAM;
#endif
//
// Finds the async object based on the overlapped structure an io
// completed on.
//
inline PBASE_OVERLAPPED FindOverlapped(LPOVERLAPPED pol)
{
return(CONTAINING_RECORD(pol, BASE_OVERLAPPED, ol));
}
inline PREQUEST FindRequest(LPOVERLAPPED pol)
{
return (pol) ? (FindOverlapped(pol)->pAsyncObject) : 0;
}
//
// Connection protocol loaders
//
const RPC_CONNECTION_TRANSPORT *WS_TransportLoad(PROTOCOL_ID);
#ifdef NETBIOS_ON
const RPC_CONNECTION_TRANSPORT *NB_TransportLoad(PROTOCOL_ID);
#endif
const RPC_CONNECTION_TRANSPORT *NMP_TransportLoad();
//
// Datagram protocol loaders
//
const RPC_DATAGRAM_TRANSPORT *DG_TransportLoad(PROTOCOL_ID);
//
// Misc functions
//
extern RPC_STATUS IP_BuildAddressVector(
OUT NETWORK_ADDRESS_VECTOR **,
IN ULONG NICFlags,
IN RPC_CHAR *NetworkAddress OPTIONAL,
IN WS_ADDRESS *Address OPTIONAL);
extern RPC_STATUS CDP_BuildAddressVector(NETWORK_ADDRESS_VECTOR **);
extern RPC_ADDRESS_CHANGE_FN * SpxAddressChangeFn;
//
// IP name resolver
//
const int IP_RETAIL_BUFFER_SIZE = 3*0x38;
const int IP_BUFFER_SIZE = DEBUG_MIN(1, IP_RETAIL_BUFFER_SIZE);
typedef enum tagIPVersionToUse
{
ipvtuIPv4 = 0,
ipvtuIPv6,
ipvtuIPAny
} IPVersionToUse;
typedef enum tagClientOrServer
{
cosClient,
cosServer
} ClientOrServer;
class IP_ADDRESS_RESOLVER
/*++
Class Description:
Converts the string address to an IP address.
--*/
{
public:
IP_ADDRESS_RESOLVER(
IN RPC_CHAR *Name,
IN ClientOrServer cos,
IN IPVersionToUse IPvToUse
)
/*++
Arguments:
Name - The name (dotted ip address or DNS name) to resolve.
fUseIPv6 - if TRUE, an IPv6 address will be resolved. If
FALSE, an IPv4 address will be resolved.
--*/
{
if (Name && (*Name == 0))
Name = 0;
this->Name = Name;
this->IPvToUse = IPvToUse;
this->cos = cos;
AddrInfo = NULL;
LoopbacksReturned = 0;
CurrentAddrInfo = NULL;
RpcpMemorySet(&Hint, 0, sizeof(ADDRINFO));
}
inline RPC_STATUS
NextAddress(
OUT SOCKADDR_IN *pAddress
)
{
ASSERT(IPvToUse == ipvtuIPv4);
return NextAddress((SOCKADDR_STORAGE *)pAddress);
}
RPC_STATUS
NextAddress(
OUT SOCKADDR_STORAGE *pAddress
);
~IP_ADDRESS_RESOLVER();
private:
RPC_CHAR *Name;
IPVersionToUse IPvToUse;
ADDRINFO *AddrInfo; // the start of the addr info list. NULL if enumeration hasn't
// started
ADDRINFO *CurrentAddrInfo; // the current element in the addr info list enumeration. NULL
// if enumeration hasn't started or has finished.
ClientOrServer cos;
ADDRINFO Hint;
int LoopbacksReturned;
};
//
// Common functions exported by each protocol
//
extern RPC_STATUS RPC_ENTRY
COMMON_ProcessCalls(
IN INT Timeout,
OUT RPC_TRANSPORT_EVENT *pEvent,
OUT RPC_STATUS *pEventStatus,
OUT PVOID *ppEventContext,
OUT UINT *pBufferLength,
OUT BUFFER *pBuffer,
OUT PVOID *ppSourceContext
);
extern RPC_STATUS
COMMON_PostNonIoEvent(
RPC_TRANSPORT_EVENT Event,
DWORD Type,
PVOID Context
);
extern void
COMMON_RemoveAddress (
IN BASE_ADDRESS *Address
);
extern RPC_STATUS RPC_ENTRY
COMMON_TowerConstruct(
IN PCHAR Protseq,
IN PCHAR NetworkAddress,
IN PCHAR Endpoint,
OUT PUSHORT Floors,
OUT PULONG ByteCount,
OUT PUCHAR *Tower
);
extern RPC_STATUS RPC_ENTRY
COMMON_TowerExplode(
IN PUCHAR Tower,
OUT PCHAR *Protseq,
OUT PCHAR *NetworkAddress,
OUT PCHAR *Endpoint
);
extern VOID RPC_ENTRY
COMMON_ServerCompleteListen(
IN RPC_TRANSPORT_ADDRESS
);
#ifndef NO_PLUG_AND_PLAY
extern VOID RPC_ENTRY
COMMON_ListenForPNPNotifications (
);
extern VOID RPC_ENTRY
COMMON_StartPnpNotifications (
);
#endif
// Internal to transport interface
extern RPC_STATUS
COMMON_PrepareNewHandle(
IN HANDLE hAdd
);
extern VOID
COMMON_AddressManager(
IN BASE_ADDRESS *
);
extern RPC_STATUS RPC_ENTRY
WS_Abort(
IN RPC_TRANSPORT_CONNECTION Connection
);
extern RPC_STATUS
WS_ReactivateAddress (
IN WS_ADDRESS *pAddress
);
extern VOID
WS_DeactivateAddress (
IN WS_ADDRESS *pAddress
);
extern RPC_STATUS
DG_ReactivateAddress (
IN WS_DATAGRAM_ENDPOINT *pAddress
);
extern VOID
DG_DeactivateAddress (
IN WS_DATAGRAM_ENDPOINT *pAddress
);
inline
void
TransConnectionFreePacket(
RPC_TRANSPORT_CONNECTION ThisConnection,
BUFFER Ptr
)
{
I_RpcTransConnectionFreePacket(ThisConnection, Ptr);
}
inline
BUFFER
TransConnectionAllocatePacket(
RPC_TRANSPORT_CONNECTION ThisConnection,
UINT Size
)
{
return (I_RpcTransConnectionAllocatePacket(ThisConnection, Size));
}
inline
RPC_STATUS
TransConnectionReallocPacket(
IN RPC_TRANSPORT_CONNECTION ThisConnection,
IN BUFFER *ppBuffer,
IN UINT OldSize,
IN UINT NewSize
)
{
return(I_RpcTransConnectionReallocPacket(ThisConnection, ppBuffer, OldSize, NewSize));
}
#define InitReadEvent(p) \
hEvent = I_RpcTransGetThreadEvent(); \
\
p->Read.ol.hEvent = (HANDLE)((ULONG_PTR)hEvent | 0x1)
#define ASSERT_READ_EVENT_IS_THERE(p) \
ASSERT( p->Read.ol.hEvent == (HANDLE) ((ULONG_PTR)I_RpcTransGetThreadEvent() | 0x1))
extern HMODULE hWinsock2;
#endif // __TRANS_HXX