/*++ 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