From d1a63c40031b3b17f4b58db863181dc8a3696e2a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 21 Aug 2011 21:46:40 +0200 Subject: [PATCH] win: move winsock intialization out of tcp.c --- src/win/core.c | 2 +- src/win/internal.h | 4 +- src/win/tcp.c | 212 +-------------------------------------------- src/win/winsock.c | 155 +++++++++++++++++++++++++++++++++ src/win/winsock.h | 130 +++++++++++++++++++++++++++ uv.gyp | 2 + 6 files changed, 291 insertions(+), 214 deletions(-) create mode 100644 src/win/winsock.c create mode 100644 src/win/winsock.h diff --git a/src/win/core.c b/src/win/core.c index b7a066eb..00f20323 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -68,7 +68,7 @@ static void uv_loop_init() { void uv_init() { /* Initialize winsock */ - uv_winsock_startup(); + uv_winsock_init(); /* Fetch winapi function pointers */ uv_winapi_init(); diff --git a/src/win/internal.h b/src/win/internal.h index cf739a92..1c0c5465 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -27,6 +27,7 @@ #include "tree.h" #include "winapi.h" +#include "winsock.h" /* @@ -162,8 +163,6 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count); /* * TCP */ -void uv_winsock_startup(); - void uv_tcp_endgame(uv_tcp_t* handle); int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); @@ -258,6 +257,7 @@ void uv_set_error(uv_err_code code, int sys_errno); * Initialization for the windows and winsock api */ void uv_winapi_init(); +void uv_winsock_init(); #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/tcp.c b/src/win/tcp.c index 3967a685..e5de42ec 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -25,232 +25,22 @@ #include "../uv-common.h" #include "internal.h" -/* - * Guids and typedefs for winsock extension functions - * Mingw32 doesn't have these :-( - */ -#ifndef WSAID_ACCEPTEX -# define WSAID_ACCEPTEX \ - {0xb5367df1, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - -# define WSAID_CONNECTEX \ - {0x25a207b9, 0xddf3, 0x4660, \ - {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} - -# define WSAID_GETACCEPTEXSOCKADDRS \ - {0xb5367df2, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - -# define WSAID_DISCONNECTEX \ - {0x7fda2e11, 0x8630, 0x436f, \ - {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} - -# define WSAID_TRANSMITFILE \ - {0xb5367df0, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - - typedef BOOL PASCAL (*LPFN_ACCEPTEX) - (SOCKET sListenSocket, - SOCKET sAcceptSocket, - PVOID lpOutputBuffer, - DWORD dwReceiveDataLength, - DWORD dwLocalAddressLength, - DWORD dwRemoteAddressLength, - LPDWORD lpdwBytesReceived, - LPOVERLAPPED lpOverlapped); - - typedef BOOL PASCAL (*LPFN_CONNECTEX) - (SOCKET s, - const struct sockaddr* name, - int namelen, - PVOID lpSendBuffer, - DWORD dwSendDataLength, - LPDWORD lpdwBytesSent, - LPOVERLAPPED lpOverlapped); - - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) - (PVOID lpOutputBuffer, - DWORD dwReceiveDataLength, - DWORD dwLocalAddressLength, - DWORD dwRemoteAddressLength, - LPSOCKADDR* LocalSockaddr, - LPINT LocalSockaddrLength, - LPSOCKADDR* RemoteSockaddr, - LPINT RemoteSockaddrLength); - - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) - (SOCKET hSocket, - LPOVERLAPPED lpOverlapped, - DWORD dwFlags, - DWORD reserved); - - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) - (SOCKET hSocket, - HANDLE hFile, - DWORD nNumberOfBytesToWrite, - DWORD nNumberOfBytesPerSend, - LPOVERLAPPED lpOverlapped, - LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, - DWORD dwFlags); -#endif /* - * MinGW is missing this too - */ -#ifndef SO_UPDATE_CONNECT_CONTEXT -# define SO_UPDATE_CONNECT_CONTEXT 0x7010 -#endif - - -/* * Threshold of active tcp streams for which to preallocate tcp read buffers. */ const unsigned int uv_active_tcp_streams_threshold = 50; - /* * Number of simultaneous pending AcceptEx calls. */ const unsigned int uv_simultaneous_server_accepts = 32; - -/* Pointers to winsock extension functions to be retrieved dynamically */ -static LPFN_CONNECTEX pConnectEx; -static LPFN_ACCEPTEX pAcceptEx; -static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; -static LPFN_DISCONNECTEX pDisconnectEx; -static LPFN_TRANSMITFILE pTransmitFile; - -/* IPv6 version of these extension functions */ -static LPFN_CONNECTEX pConnectEx6; -static LPFN_ACCEPTEX pAcceptEx6; -static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; -static LPFN_DISCONNECTEX pDisconnectEx6; -static LPFN_TRANSMITFILE pTransmitFile6; - -/* Ip address used to bind to any port at any interface */ -static struct sockaddr_in uv_addr_ip4_any_; -static struct sockaddr_in6 uv_addr_ip6_any_; - /* A zero-size buffer for use by uv_tcp_read */ static char uv_zero_[] = ""; -/* mark if IPv6 sockets are supported */ -static BOOL uv_allow_ipv6 = FALSE; - /* Counter to keep track of active tcp streams */ -static uint64_t active_tcp_streams; - - -/* - * Retrieves the pointer to a winsock extension function. - */ -static BOOL uv_get_extension_function(SOCKET socket, GUID guid, - void **target) { - DWORD result, bytes; - - result = WSAIoctl(socket, - SIO_GET_EXTENSION_FUNCTION_POINTER, - &guid, - sizeof(guid), - (void*)target, - sizeof(*target), - &bytes, - NULL, - NULL); - - if (result == SOCKET_ERROR) { - *target = NULL; - return FALSE; - } else { - return TRUE; - } -} - - -/* - * Setup tcp subsystem - */ -void uv_winsock_startup() { - const GUID wsaid_connectex = WSAID_CONNECTEX; - const GUID wsaid_acceptex = WSAID_ACCEPTEX; - const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; - const GUID wsaid_disconnectex = WSAID_DISCONNECTEX; - const GUID wsaid_transmitfile = WSAID_TRANSMITFILE; - - WSADATA wsa_data; - int errorno; - SOCKET dummy; - SOCKET dummy6; - - /* Initialize winsock */ - errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); - if (errorno != 0) { - uv_fatal_error(errorno, "WSAStartup"); - } - - /* Set implicit binding address used by connectEx */ - uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); - uv_addr_ip6_any_ = uv_ip6_addr("::", 0); - - /* Retrieve the needed winsock extension function pointers. */ - dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - if (dummy == INVALID_SOCKET) { - uv_fatal_error(WSAGetLastError(), "socket"); - } - - if (!uv_get_extension_function(dummy, - wsaid_connectex, - (void**)&pConnectEx) || - !uv_get_extension_function(dummy, - wsaid_acceptex, - (void**)&pAcceptEx) || - !uv_get_extension_function(dummy, - wsaid_getacceptexsockaddrs, - (void**)&pGetAcceptExSockAddrs) || - !uv_get_extension_function(dummy, - wsaid_disconnectex, - (void**)&pDisconnectEx) || - !uv_get_extension_function(dummy, - wsaid_transmitfile, - (void**)&pTransmitFile)) { - uv_fatal_error(WSAGetLastError(), - "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); - } - - if (closesocket(dummy) == SOCKET_ERROR) { - uv_fatal_error(WSAGetLastError(), "closesocket"); - } - - /* optional IPv6 versions of winsock extension functions */ - dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); - if (dummy6 != INVALID_SOCKET) { - uv_allow_ipv6 = TRUE; - - if (!uv_get_extension_function(dummy6, - wsaid_connectex, - (void**)&pConnectEx6) || - !uv_get_extension_function(dummy6, - wsaid_acceptex, - (void**)&pAcceptEx6) || - !uv_get_extension_function(dummy6, - wsaid_getacceptexsockaddrs, - (void**)&pGetAcceptExSockAddrs6) || - !uv_get_extension_function(dummy6, - wsaid_disconnectex, - (void**)&pDisconnectEx6) || - !uv_get_extension_function(dummy6, - wsaid_transmitfile, - (void**)&pTransmitFile6)) { - uv_allow_ipv6 = FALSE; - } - - if (closesocket(dummy6) == SOCKET_ERROR) { - uv_fatal_error(WSAGetLastError(), "closesocket"); - } - } -} +static unsigned int active_tcp_streams = 0; static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { diff --git a/src/win/winsock.c b/src/win/winsock.c new file mode 100644 index 00000000..9c654f64 --- /dev/null +++ b/src/win/winsock.c @@ -0,0 +1,155 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "../uv-common.h" +#include "internal.h" + + +/* Winsock extension functions (ipv4) */ +LPFN_CONNECTEX pConnectEx; +LPFN_ACCEPTEX pAcceptEx; +LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; +LPFN_DISCONNECTEX pDisconnectEx; +LPFN_TRANSMITFILE pTransmitFile; + +/* Winsock extension functions (ipv6) */ +LPFN_CONNECTEX pConnectEx6; +LPFN_ACCEPTEX pAcceptEx6; +LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; +LPFN_DISCONNECTEX pDisconnectEx6; +LPFN_TRANSMITFILE pTransmitFile6; + +/* Whether ipv6 is supported */ +int uv_allow_ipv6; + +/* Ip address used to bind to any port at any interface */ +struct sockaddr_in uv_addr_ip4_any_; +struct sockaddr_in6 uv_addr_ip6_any_; + + +/* + * Retrieves the pointer to a winsock extension function. + */ +static BOOL uv_get_extension_function(SOCKET socket, GUID guid, + void **target) { + DWORD result, bytes; + + result = WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL); + + if (result == SOCKET_ERROR) { + *target = NULL; + return FALSE; + } else { + return TRUE; + } +} + + +void uv_winsock_init() { + const GUID wsaid_connectex = WSAID_CONNECTEX; + const GUID wsaid_acceptex = WSAID_ACCEPTEX; + const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; + const GUID wsaid_disconnectex = WSAID_DISCONNECTEX; + const GUID wsaid_transmitfile = WSAID_TRANSMITFILE; + + WSADATA wsa_data; + int errorno; + SOCKET dummy; + SOCKET dummy6; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + + /* Set implicit binding address used by connectEx */ + uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); + uv_addr_ip6_any_ = uv_ip6_addr("::", 0); + + /* Retrieve the needed winsock extension function pointers. */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (dummy == INVALID_SOCKET) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + if (!uv_get_extension_function(dummy, + wsaid_connectex, + (void**)&pConnectEx) || + !uv_get_extension_function(dummy, + wsaid_acceptex, + (void**)&pAcceptEx) || + !uv_get_extension_function(dummy, + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs) || + !uv_get_extension_function(dummy, + wsaid_disconnectex, + (void**)&pDisconnectEx) || + !uv_get_extension_function(dummy, + wsaid_transmitfile, + (void**)&pTransmitFile)) { + uv_fatal_error(WSAGetLastError(), + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); + } + + if (closesocket(dummy) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + + /* optional IPv6 versions of winsock extension functions */ + dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + if (dummy6 != INVALID_SOCKET) { + uv_allow_ipv6 = TRUE; + + if (!uv_get_extension_function(dummy6, + wsaid_connectex, + (void**)&pConnectEx6) || + !uv_get_extension_function(dummy6, + wsaid_acceptex, + (void**)&pAcceptEx6) || + !uv_get_extension_function(dummy6, + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs6) || + !uv_get_extension_function(dummy6, + wsaid_disconnectex, + (void**)&pDisconnectEx6) || + !uv_get_extension_function(dummy6, + wsaid_transmitfile, + (void**)&pTransmitFile6)) { + uv_allow_ipv6 = FALSE; + } + + if (closesocket(dummy6) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + } +} diff --git a/src/win/winsock.h b/src/win/winsock.h new file mode 100644 index 00000000..40994b37 --- /dev/null +++ b/src/win/winsock.h @@ -0,0 +1,130 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include + + +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ + {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ + {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} + +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + + typedef BOOL PASCAL (*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL PASCAL (*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR* LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR* RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); +#endif + +/* + * MinGW is missing this too + */ +#ifndef SO_UPDATE_CONNECT_CONTEXT +# define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + + +/* Winsock extension functions (ipv4) */ +extern LPFN_CONNECTEX pConnectEx; +extern LPFN_ACCEPTEX pAcceptEx; +extern LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; +extern LPFN_DISCONNECTEX pDisconnectEx; +extern LPFN_TRANSMITFILE pTransmitFile; + +/* Winsock extension functions (ipv6) */ +extern LPFN_CONNECTEX pConnectEx6; +extern LPFN_ACCEPTEX pAcceptEx6; +extern LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; +extern LPFN_DISCONNECTEX pDisconnectEx6; +extern LPFN_TRANSMITFILE pTransmitFile6; + +/* Whether ipv6 is supported */ +extern int uv_allow_ipv6; + +/* Ip address used to bind to any port at any interface */ +extern struct sockaddr_in uv_addr_ip4_any_; +extern struct sockaddr_in6 uv_addr_ip6_any_; + +#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/uv.gyp b/uv.gyp index 3c22129c..e202e13b 100644 --- a/uv.gyp +++ b/uv.gyp @@ -112,6 +112,8 @@ 'src/win/util.c', 'src/win/winapi.c', 'src/win/winapi.h', + 'src/win/winsock.c', + 'src/win/winsock.h', ], 'link_settings': { 'libraries': [