/*++ Copyright (c) 2000 Microsoft Corporation Module Name: sockp.h Abstract: Declarations internal to Winsock implementation Revision History: 05/30/2000 davidx Created it. --*/ #ifndef _SOCKP_H #define _SOCKP_H //------------------------------------------------------------------------ // Per-thread Winsock data //------------------------------------------------------------------------ typedef struct _WinsockThreadbuf { CHAR* data; UINT size; } WinsockThreadbuf; typedef struct _WinsockTlsData { WinsockThreadbuf strbuf; WinsockThreadbuf hostentbuf; WinsockThreadbuf serventbuf; WinsockThreadbuf protoentbuf; } WinsockTlsData; WinsockTlsData* SockAllocThreadData(); VOID SockFreeThreadData(WinsockTlsData* tlsData); #if defined(BUILD_FOR_DEBUGGER) INLINE WinsockTlsData* SockGetThreadData() { return (WinsockTlsData*) DmGetCurrentDmtd()->WinSockData; } INLINE VOID SockSetThreadData(WinsockTlsData* tlsData) { DmGetCurrentDmtd()->WinSockData = tlsData; } #else // !BUILD_FOR_DEBUGGER extern __declspec(thread) WinsockTlsData* WinsockTlsDataPtr; INLINE WinsockTlsData* SockGetThreadData() { return WinsockTlsDataPtr; } INLINE VOID SockSetThreadData(WinsockTlsData* tlsData) { WinsockTlsDataPtr = tlsData; } #endif // !BUILD_FOR_DEBUGGER // Allocate per-thread temporary buffer VOID* SockAllocThreadbuf(WinsockThreadbuf* buf, UINT size); //------------------------------------------------------------------------ // Map an API-level socket handle to // a pointer to our internal socket data structure //------------------------------------------------------------------------ INLINE PCB* SockLock(SOCKET s) { PCB* pcb; INT err; LONG cookie; // NOTE: We don't allow multiple threads to access the same // socket simultaneously. If the app tries to do that, the first // thread will succeed and other threads will get an error return. if (s == 0 || s == INVALID_SOCKET) { err = WSAENOTSOCK; } else { pcb = (PCB*) s; cookie = InterlockedCompareExchange( &pcb->magicCookie, BUSY_PCB_COOKIE, ACTIVE_PCB_COOKIE); if (cookie == ACTIVE_PCB_COOKIE) return pcb; err = (cookie == BUSY_PCB_COOKIE) ? WSAEINPROGRESS : WSAENOTSOCK; } #if DBG #if !defined(BUILD_FOR_DEBUGGER) if (err == WSAEINPROGRESS) { WARNING_("Thread contention on socket handle: tid = %x, socket = %x", GetCurrentThreadId(), s); } else #endif { WARNING_("Invalid socket handle: socket = %x, error = %d", s, err); } #endif SetLastError(err); return NULL; } INLINE VOID SockUnlock(PCB* pcb) { pcb->magicCookie = ACTIVE_PCB_COOKIE; } // // Socket address length // #define SOCKADDRLEN ((INT) sizeof(SOCKADDR_IN)) // // Network stack initialization state // extern LONG XnetInitState; #define XNETSTATE_INVALID 0 // not initialized #define XNETSTATE_READY 1 // successfully initialized // // Find a supported protocol that matches the specified parameters // INT MatchTcpipProtocol( IN INT af, IN INT type, IN INT protocol, OUT const WSAPROTOCOL_INFOW** protoinfo ); //------------------------------------------------------------------------ // Prolog and epilog code for Winsock API functions //------------------------------------------------------------------------ INT SockEnterApiSlow(WinsockTlsData** tlsData); #if DBG #define SOCKTRACE_WSAStartup BIT(0) #define SOCKTRACE_WSACleanup BIT(0) #define SOCKTRACE_socket BIT(1) #define SOCKTRACE_closesocket BIT(1) #define SOCKTRACE_shutdown BIT(1) #define SOCKTRACE_setsockopt BIT(2) #define SOCKTRACE_getsockopt BIT(2) #define SOCKTRACE_ioctlsocket BIT(2) #define SOCKTRACE_WSARecv BIT(3) #define SOCKTRACE_WSARecvFrom BIT(3) #define SOCKTRACE_recv BIT(3) #define SOCKTRACE_recvfrom BIT(3) #define SOCKTRACE_WSASend BIT(4) #define SOCKTRACE_WSASendTo BIT(4) #define SOCKTRACE_send BIT(4) #define SOCKTRACE_sendto BIT(4) #define SOCKTRACE_bind BIT(5) #define SOCKTRACE_connect BIT(5) #define SOCKTRACE_listen BIT(5) #define SOCKTRACE_accept BIT(5) #define SOCKTRACE_getsockname BIT(5) #define SOCKTRACE_getpeername BIT(5) #define SOCKTRACE_select BIT(6) #define SOCKTRACE_WSAGetOverlappedResult BIT(6) #define SOCKTRACE_WSACancelOverlappedIO BIT(6) #define SOCKTRACE_inet_addr BIT(7) #define SOCKTRACE_inet_ntoa BIT(7) #define SOCKTRACE_gethostbyaddr BIT(7) #define SOCKTRACE_gethostbyname BIT(7) #define SOCKTRACE_gethostname BIT(7) #define SOCKTRACE_getprotoby_ BIT(7) #define SOCKTRACE_getprotobyname BIT(7) #define SOCKTRACE_getprotobynumber BIT(7) #define SOCKTRACE_getservby_ BIT(7) #define SOCKTRACE_getservbyname BIT(7) #define SOCKTRACE_getservbyport BIT(7) #define SOCKTRACE_WSAEnumProtocols BIT(7) #define SOCKTRACE_XnetInitialize BIT(8) #define SOCKTRACE_XnetCleanup BIT(8) #define SOCKTRACE_XnetGetIpAddress BIT(8) extern INT _winsockTraceFlag; #define WinsockApiProlog_(_apiname, _result) \ static const CHAR* fname_ = #_apiname; \ WinsockTlsData* tlsData; \ INT err; \ if (_winsockTraceFlag & SOCKTRACE_##_apiname) { \ DbgPrint("Entering %s...\n", fname_); \ } \ err = (XnetInitState == XNETSTATE_INVALID) ? WSASYSNOTREADY : \ ((tlsData = SockGetThreadData()) != NULL) ? NO_ERROR : \ SockEnterApiSlow(&tlsData); \ WinsockApiCheckError_(_result) #define WinsockApiPrologLight_(_apiname) \ static const CHAR* fname_ = #_apiname; \ if (_winsockTraceFlag & SOCKTRACE_##_apiname) { \ DbgPrint("Entering %s...\n", fname_); \ } #define WinsockApiWarnError_(_err) { \ if ((_err) != WSA_IO_PENDING && \ (_err) != WSA_IO_INCOMPLETE && \ (_err) != WSAETIMEDOUT && \ (_err) != WSAEWOULDBLOCK) { \ WARNING_("%s failed: %d", fname_, _err); \ } \ } #define WinsockApiParamCheck_(_exp) { \ if (!(_exp)) { \ DbgPrint("%s: %s\n", fname_, #_exp); \ RIP("bad winsock parameters\n"); \ } \ } #else // !DBG #define WinsockApiProlog_(_apiname, _result) \ WinsockTlsData* tlsData; \ INT err; \ err = (XnetInitState == XNETSTATE_INVALID) ? WSASYSNOTREADY : \ ((tlsData = SockGetThreadData()) != NULL) ? NO_ERROR : \ SockEnterApiSlow(&tlsData); \ WinsockApiCheckError_(_result) #define WinsockApiPrologLight_(_apiname) #define WinsockApiWarnError_(_err) #define WinsockApiParamCheck_(_exp) #endif // !DBG #define WinsockApiReturnError_(_err, _result) { \ WinsockApiWarnError_(_err); \ SetLastError(_err); \ return (_result); \ } #define WinsockApiCheckError_(_result) { \ if (err != NO_ERROR) { \ WinsockApiReturnError_(err, _result); \ } \ } #define WinsockApiPrologSockLock_(_apiname, _result) \ PCB* pcb; \ WinsockApiProlog_(_apiname, _result); \ pcb = SockLock(s); \ if (!pcb) return (_result) #define WinsockApiExitSockUnlock_(_resultOk, _resultErr) \ exit: SockUnlock(pcb); \ WinsockApiCheckError_(_resultErr); \ return (_resultOk) #define WinsockApiGotoExit_(_err) \ { err = (_err); goto exit; } #define MapNtStatusToWinsockError_(_err) \ ((_err) = NT_SUCCESS(_err) ? NO_ERROR : RtlNtStatusToDosError(_err)) #endif // !_SOCKP_H