/*++ Copyright (C) Microsoft Corporation, 1996 - 1999 Module Name: wsload.cxx Abstract: Implements the wrapper used to avoid loading the winsock DLLs into more processes than necessary. Author: Mario Goertzel [MarioGo] Revision History: MarioGo 3/21/1996 Bits 'n pieces --*/ #include #include struct WINSOCK_FUNCTION_TABLE WFT; HMODULE hWinsock = 0; HMODULE hWinsock2 = 0; typedef int (PASCAL FAR *PWSASTARTUP)(WORD wVersionRequired, LPWSADATA lpWSAData); typedef struct tagProcAddressData { int nDllIndex; // 0 is ws2_32.dll, 1 is mswsock.dll char *pProcName; } ProcAddressData; const ProcAddressData WinsockProcData[] = { { 0, "socket" }, { 0, "bind" }, { 0, "closesocket" }, { 0, "getsockname" }, { 0, "connect" }, { 0, "listen" }, { 0, "send" }, { 0, "recv" }, { 0, "sendto" }, { 0, "recvfrom" }, { 0, "setsockopt" }, { 0, "getsockopt" }, { 0, "inet_ntoa" }, { 0, "gethostbyname" }, { 1, "GetAddressByNameA" }, { 0, "WSASocketW" }, { 0, "WSARecv" }, { 0, "WSARecvFrom" }, { 0, "WSASend" }, { 0, "WSASendTo" }, { 0, "WSAProviderConfigChange" }, { 0, "WSAEnumProtocolsW" }, { 0, "WSAIoctl" }, { 0, "getaddrinfo"}, { 0, "freeaddrinfo"}, { 0, "getnameinfo" }, { 0, "WSAGetOverlappedResult" } }; LONG TriedUsingAfd = 0; // Winsock's function IN6ADDR_SETANY uses the external constant in6addr_any. // Since we do not statically link to obtain this constatnt, we need to define // one ourselves. const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; void TryUsingAfdProc(void) { // Figure out if we can call AFD directly for datagram. // This is a performance optimization - if any thing fails // or does match exactly to MSAFD the we'll just use the // ws2_32 exported functions. static const UUID aDefaultProviders[] = { { 0xe70f1aa0, 0xab8b, 0x11cf, 0x8c, 0xa3, 0x0, 0x80, 0x5f, 0x48, 0xa1, 0x92 }, // AFD UDP { 0x9d60a9e0, 0x337a, 0x11d0, 0xbd, 0x88, 0x0, 0x00, 0xc0, 0x82, 0xe6, 0x9a }, // RSVP UDP { 0x11058240, 0xbe47, 0x11cf, 0x95, 0xc8, 0x0, 0x80, 0x5f, 0x48, 0xa1, 0x92 } // AFD IPX }; INT aProtocols[] = { IPPROTO_UDP, NSPROTO_IPX, 0 }; WSAPROTOCOL_INFO *info; DWORD dwSize; INT cProtocols; BOOL fUseAfd = TRUE; info = new WSAPROTOCOL_INFO[8]; if (info == NULL) { cProtocols = 0; fUseAfd = FALSE; } else { dwSize = sizeof(WSAPROTOCOL_INFO) * 8; } if (fUseAfd) { cProtocols = WSAEnumProtocolsT(aProtocols, info, &dwSize); if (cProtocols <= 0) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "Failed to enum protocols, using winsock. %d\n", GetLastError())); cProtocols = 0; fUseAfd = FALSE; } for (int i = 0; i < cProtocols; i++) { BOOL fFoundIt = FALSE; for (int j = 0; j < sizeof(aDefaultProviders)/sizeof(UUID); j++) { if (memcmp(&aDefaultProviders[j], &info[i].ProviderId, sizeof(UUID)) == 0) { fFoundIt = TRUE; } } if (!fFoundIt) { fUseAfd = FALSE; } } } if (fUseAfd) { WFT.pWSASendTo = AFD_SendTo; WFT.pWSARecvFrom = AFD_RecvFrom; } else { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "Non-default winsock providers loaded\n")); } if (info) delete [] info; } C_ASSERT((sizeof(WinsockProcData) / sizeof(ProcAddressData)) <= (sizeof(WINSOCK_FUNCTION_TABLE) / sizeof(FARPROC))); BOOL RPC_WSAStartup(void) { // Transport load can only be called by a single thread at a time. WSADATA data; PWSASTARTUP pStartup; FARPROC *ppProc; BOOL status; BOOL b; HMODULE ws2; HMODULE ws; HMODULE hDlls[2]; if (hWinsock == 0) { ws = LoadLibrary(RPC_CONST_SSTRING("mswsock.dll")); ws2 = LoadLibrary(RPC_CONST_SSTRING("ws2_32.dll")); if (ws == 0 || ws2 == 0) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "Unable to load windows sockets dlls, bad config? %d\n", GetLastError())); return FALSE; } } else { // loading already performed - just return true ASSERT(hWinsock2); return TRUE; } status = FALSE; pStartup = (PWSASTARTUP)GetProcAddress(ws2, "WSAStartup"); if (pStartup) { if ( (*pStartup)(2, &data) == NO_ERROR) { status = TRUE; } } if (!status) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "GetProcAddr or WSAStartup failed %d\n", GetLastError())); b = FreeLibrary(ws); if (b) b = FreeLibrary(ws2); if (!b) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "FreeLibrary failed %d\n", GetLastError())); ASSERT(0); } return(FALSE); } ppProc = (FARPROC *)&WFT; hDlls[0] = ws2; hDlls[1] = ws; // WinsockProcData is smaller than WINSOCK_FUNCTION_TABLE. Make sure the loop // is driven by WinsockProcData for (int i = 0; i < sizeof(WinsockProcData) / sizeof(ProcAddressData); i++) { *ppProc = GetProcAddress(hDlls[WinsockProcData[i].nDllIndex], WinsockProcData[i].pProcName); if (*ppProc == 0) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "Failed to load winsock procedure %s correctly\n", WinsockProcData[i].pProcName)); b = FreeLibrary(ws); if (b) b = FreeLibrary(ws2); if (!b) { TransDbgPrint((DPFLTR_RPCPROXY_ID, DPFLTR_WARNING_LEVEL, RPCTRANS "FreeLibrary failed %d\n", GetLastError())); ASSERT(0); } return(FALSE); } ppProc ++; } hWinsock = ws; hWinsock2 = ws2; return TRUE; }