diff --git a/src/platform_win32_winsock.cc b/src/platform_win32_winsock.cc index 6c858e70e1..d6eacff5b7 100644 --- a/src/platform_win32_winsock.cc +++ b/src/platform_win32_winsock.cc @@ -18,6 +18,72 @@ namespace node { +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX + const GUID WSAID_ACCEPTEX = + {0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}; + + const GUID WSAID_CONNECTEX = + {0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}; + + const GUID WSAID_GETACCEPTEXSOCKADDRS = + {0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}; + + const GUID WSAID_DISCONNECTEX = + {0x7fda2e11, 0x8630, 0x436f, {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}; + + const GUID WSAID_TRANSMITFILE = + {0xb5367df0, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}; + + typedef BOOL(*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL(*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr *name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void(*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR *LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR *RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL(*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL(*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); +#endif + + /* * Winsock version data goes here */ @@ -34,6 +100,18 @@ static WSAData winsock_info; static WSAPROTOCOL_INFOW proto_info_cache[4]; +/* + * Pointers to winsock extension functions that have to be retrieved dynamically + */ +static struct WINSOCK_EXTENSION_FUNCTIONS { + //LPFN_CONNECTEX ConnectEx; + //LPFN_ACCEPTEX AcceptEx; + //LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockAddrs; + LPFN_DISCONNECTEX DisconnectEx; + //LPFN_TRANSMITFILE TransmitFile; +} wsexf; + + /* * Does the about the same as perror(), but for winsock errors */ @@ -54,6 +132,14 @@ void wsa_perror(const char *prefix) { } +/* + * Wrapper for DisconnectEx extension function + */ +BOOL wsa_disconnect_ex(SOCKET socket, OVERLAPPED *overlapped, DWORD flags, DWORD reserved) { + return wsexf.DisconnectEx(socket, overlapped, flags, reserved); +} + + /* * Retrieves a pointer to a WSAPROTOCOL_INFOW structure * related to a certain winsock protocol from the cache @@ -315,6 +401,51 @@ static void wsa_init_proto_info_cache() { } +/* + * Gets the pointer to a winsock extension function + */ +inline static void wsa_get_extension_function(SOCKET socket, GUID guid, void **target) { + DWORD bytes; + + if (WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL) == SOCKET_ERROR) { + + *target = NULL; + wsa_perror("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); + } +} + + +/* + * Retrieves the needed winsock extension function pointers for the tcp/ip subsystem, + * storing them in the `wsexf` cache + */ +inline static void wsa_init_extension_functions() { + SOCKET dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (dummy == SOCKET_ERROR) { + memset((void*)&wsexf, 0, sizeof(wsexf)); + wsa_perror("socket"); + return; + } + + //wsa_get_extension_function(dummy, WSAID_CONNECTEX, (void**)&wsexf.ConnectEx ); + //wsa_get_extension_function(dummy, WSAID_ACCEPTEX, (void**)&wsexf.AcceptEx ); + //wsa_get_extension_function(dummy, WSAID_GETACCEPTEXSOCKADDRS, (void**)&wsexf.GetAcceptExSockAddrs); + wsa_get_extension_function(dummy, WSAID_DISCONNECTEX, (void**)&wsexf.DisconnectEx ); + //wsa_get_extension_function(dummy, WSAID_TRANSMITFILE, (void**)&wsexf.TransmitFile ); + + closesocket(dummy); +} + + /* * Initializes winsock and winsock-related stuff */ @@ -325,6 +456,7 @@ void wsa_init() { } wsa_init_proto_info_cache(); + wsa_init_extension_functions(); } diff --git a/src/platform_win32_winsock.h b/src/platform_win32_winsock.h index 126ee0dd4d..a80f612136 100644 --- a/src/platform_win32_winsock.h +++ b/src/platform_win32_winsock.h @@ -11,6 +11,8 @@ void wsa_init(); void wsa_perror(const char* prefix = ""); +BOOL wsa_disconnect_ex(SOCKET socket, OVERLAPPED *overlapped, DWORD flags, DWORD reserved); + SOCKET wsa_sync_socket(int af, int type, int proto); int wsa_socketpair(int af, int type, int proto, SOCKET sock[2]); int wsa_sync_async_socketpair(int af, int type, int proto, SOCKET *syncSocket, SOCKET *asyncSocket);