From 62f7c7961da7ca3f9731b84e8dec95a1fcd92480 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 19 Jul 2011 02:47:15 -0700 Subject: [PATCH] Upgrade libuv to d4563a1 --- deps/uv/config-mingw.mk | 10 +- deps/uv/include/uv.h | 6 + deps/uv/msvs/c-ares.vcxproj | 10 + deps/uv/msvs/libuv-benchmark.vcxproj | 10 +- deps/uv/msvs/libuv-test.vcxproj | 10 +- deps/uv/msvs/libuv.vcxproj | 29 +- deps/uv/src/ares/inet_ntop.h | 1 + deps/uv/src/uv-common.c | 13 + deps/uv/src/uv-unix.c | 17 +- deps/uv/src/uv-win.c | 3194 -------------------------- deps/uv/test/test-bind-error.c | 12 + deps/uv/test/test-getsockname.c | 9 + deps/uv/test/test-list.h | 2 + lib/net_uv.js | 1 + 14 files changed, 115 insertions(+), 3209 deletions(-) delete mode 100644 deps/uv/src/uv-win.c diff --git a/deps/uv/config-mingw.mk b/deps/uv/config-mingw.mk index a115277a9d..8081fce8ad 100644 --- a/deps/uv/config-mingw.mk +++ b/deps/uv/config-mingw.mk @@ -28,17 +28,19 @@ CFLAGS=$(CPPFLAGS) -g --std=gnu89 -D_WIN32_WINNT=0x0501 -Isrc/ares/config_win32 LINKFLAGS=-lm CARES_OBJS += src/ares/windows_port.o +WIN_SRCS=$(wildcard src/win/*.c) +WIN_OBJS=$(WIN_SRCS:.c=.o) RUNNER_CFLAGS=$(CFLAGS) -D_GNU_SOURCE # Need _GNU_SOURCE for strdup? RUNNER_LINKFLAGS=$(LINKFLAGS) RUNNER_LIBS=-lws2_32 RUNNER_SRC=test/runner-win.c -uv.a: src/uv-win.o src/uv-common.o src/uv-eio.o src/eio/eio.o $(CARES_OBJS) - $(AR) rcs uv.a src/uv-win.o src/uv-common.o src/uv-eio.o src/eio/eio.o $(CARES_OBJS) +uv.a: $(WIN_OBJS) src/uv-common.o src/uv-eio.o src/eio/eio.o $(CARES_OBJS) + $(AR) rcs uv.a src/win/*.o src/uv-common.o src/uv-eio.o src/eio/eio.o $(CARES_OBJS) -src/uv-win.o: src/uv-win.c include/uv.h include/uv-win.h - $(CC) $(CFLAGS) -c src/uv-win.c -o src/uv-win.o +src/win/%.o: src/win/%.c src/win/internal.h + $(CC) $(CFLAGS) -o $@ -c $< src/uv-common.o: src/uv-common.c include/uv.h include/uv-win.h $(CC) $(CFLAGS) -c src/uv-common.c -o src/uv-common.o diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 4382225253..f065b9d90f 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -514,9 +514,15 @@ int64_t uv_now(); /* Utility */ + +/* Convert string ip addresses to binary structures */ struct sockaddr_in uv_ip4_addr(const char* ip, int port); struct sockaddr_in6 uv_ip6_addr(const char* ip, int port); +/* Convert binary addresses to strings */ +int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size); +int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size); + /* Gets the executable path */ int uv_exepath(char* buffer, size_t* size); diff --git a/deps/uv/msvs/c-ares.vcxproj b/deps/uv/msvs/c-ares.vcxproj index 4ada6ccb3d..0b23fade76 100644 --- a/deps/uv/msvs/c-ares.vcxproj +++ b/deps/uv/msvs/c-ares.vcxproj @@ -95,14 +95,24 @@ MultiThreaded ..\include;..\src\ares\config_win32 WIN32;HAVE_CONFIG_H;_LIB;%(PreprocessorDefinitions) + true + true + + true + MultiThreaded ..\include;..\src\ares\config_win32 WIN32;HAVE_CONFIG_H;_LIB;%(PreprocessorDefinitions) + true + true + + true + diff --git a/deps/uv/msvs/libuv-benchmark.vcxproj b/deps/uv/msvs/libuv-benchmark.vcxproj index 5727a1aa3c..17132dc3bf 100644 --- a/deps/uv/msvs/libuv-benchmark.vcxproj +++ b/deps/uv/msvs/libuv-benchmark.vcxproj @@ -55,22 +55,18 @@ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ @@ -112,6 +108,8 @@ Level3 ProgramDatabase ..\include;..\src\ares\config_win32 + true + true MachineX86 @@ -120,6 +118,7 @@ true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration @@ -129,6 +128,8 @@ Level3 ProgramDatabase ..\include;..\src\ares\config_win32 + true + true true @@ -136,6 +137,7 @@ true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration diff --git a/deps/uv/msvs/libuv-test.vcxproj b/deps/uv/msvs/libuv-test.vcxproj index e59786dde2..3d648b6ea1 100644 --- a/deps/uv/msvs/libuv-test.vcxproj +++ b/deps/uv/msvs/libuv-test.vcxproj @@ -56,22 +56,18 @@ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ - true $(SolutionDir)..\build\$(Platform)\$(Configuration)\ $(SolutionDir)..\build\$(Platform)\$(Configuration)\ @@ -113,6 +109,8 @@ Level3 ProgramDatabase ..\include;..\src\ares\config_win32 + true + true MachineX86 @@ -121,6 +119,7 @@ true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration @@ -130,6 +129,8 @@ Level3 ProgramDatabase ..\include;..\src\ares\config_win32 + true + true true @@ -137,6 +138,7 @@ true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration diff --git a/deps/uv/msvs/libuv.vcxproj b/deps/uv/msvs/libuv.vcxproj index c896c6970f..fbfca78941 100644 --- a/deps/uv/msvs/libuv.vcxproj +++ b/deps/uv/msvs/libuv.vcxproj @@ -95,13 +95,23 @@ MultiThreaded ..\include;..\src\ares\config_win32 + true + true + + true + MultiThreaded ..\include;..\src\ares\config_win32 + true + true + + true + @@ -115,7 +125,19 @@ - + + + + + + + + + + + + + @@ -124,6 +146,11 @@ + + + + + diff --git a/deps/uv/src/ares/inet_ntop.h b/deps/uv/src/ares/inet_ntop.h index c583488f75..1b5389e893 100644 --- a/deps/uv/src/ares/inet_ntop.h +++ b/deps/uv/src/ares/inet_ntop.h @@ -18,6 +18,7 @@ */ #ifdef HAVE_INET_NTOP +#include #define ares_inet_ntop(w,x,y,z) inet_ntop(w,x,y,z) #else const char *ares_inet_ntop(int af, const void *src, char *dst, size_t size); diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 2c4e0cc765..d202128ff6 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -29,6 +29,7 @@ /* use inet_pton from c-ares if necessary */ #include "ares_config.h" #include "ares/inet_net_pton.h" +#include "ares/inet_ntop.h" /* list used for ares task handles */ static uv_ares_task_t* uv_ares_handles_ = NULL; @@ -112,6 +113,18 @@ struct sockaddr_in6 uv_ip6_addr(const char* ip, int port) { } +int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { + char* d = ares_inet_ntop(AF_INET, &src->sin_addr, dst, size); + return d != dst; +} + + +int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { + char* d = ares_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); + return d != dst; +} + + /* find matching ares handle in list */ void uv_add_ares_handle(uv_ares_task_t* handle) { handle->ares_next = uv_ares_handles_; diff --git a/deps/uv/src/uv-unix.c b/deps/uv/src/uv-unix.c index f35cc6f043..2ee2f8643a 100644 --- a/deps/uv/src/uv-unix.c +++ b/deps/uv/src/uv-unix.c @@ -481,14 +481,27 @@ out: int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int r; - - assert(tcp->fd >= 0); + int fd; if (tcp->delayed_error) { uv_err_new((uv_handle_t*)tcp, tcp->delayed_error); return -1; } + if (tcp->fd <= 0) { + if ((fd = uv__socket(AF_INET, SOCK_STREAM, 0)) == -1) { + uv_err_new((uv_handle_t*)tcp, errno); + return -1; + } + + if (uv__stream_open(tcp, fd)) { + close(fd); + return -1; + } + } + + assert(tcp->fd >= 0); + r = listen(tcp->fd, backlog); if (r < 0) { uv_err_new((uv_handle_t*)tcp, errno); diff --git a/deps/uv/src/uv-win.c b/deps/uv/src/uv-win.c deleted file mode 100644 index 8241340ae8..0000000000 --- a/deps/uv/src/uv-win.c +++ /dev/null @@ -1,3194 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#include "uv.h" -#include "uv-common.h" -#include "tree.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 - - -/* - * MinGW is missing this too - */ -#ifndef _MSC_VER - typedef struct addrinfoW { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - wchar_t* ai_canonname; - struct sockaddr* ai_addr; - struct addrinfoW* ai_next; - } ADDRINFOW, *PADDRINFOW; - - DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node, - const wchar_t* service, - const ADDRINFOW* hints, - PADDRINFOW* result); - - DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); -#endif - - -/* - * 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; -/* need IPv6 versions of winsock extension functions */ -static LPFN_CONNECTEX pConnectEx6; -static LPFN_ACCEPTEX pAcceptEx6; -static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; -static LPFN_DISCONNECTEX pDisconnectEx6; -static LPFN_TRANSMITFILE pTransmitFile6; - - -/* - * Private uv_handle flags - */ -#define UV_HANDLE_CLOSING 0x0001 -#define UV_HANDLE_CLOSED 0x0002 -#define UV_HANDLE_BOUND 0x0004 -#define UV_HANDLE_LISTENING 0x0008 -#define UV_HANDLE_CONNECTION 0x0010 -#define UV_HANDLE_CONNECTED 0x0020 -#define UV_HANDLE_READING 0x0040 -#define UV_HANDLE_ACTIVE 0x0040 -#define UV_HANDLE_EOF 0x0080 -#define UV_HANDLE_SHUTTING 0x0100 -#define UV_HANDLE_SHUT 0x0200 -#define UV_HANDLE_ENDGAME_QUEUED 0x0400 -#define UV_HANDLE_BIND_ERROR 0x1000 -#define UV_HANDLE_IPV6 0x2000 -#define UV_HANDLE_PIPESERVER 0x4000 -#define UV_HANDLE_READ_PENDING 0x8000 - - -/* Binary tree used to keep the list of timers sorted. */ -static int uv_timer_compare(uv_timer_t* handle1, uv_timer_t* handle2); -RB_HEAD(uv_timer_tree_s, uv_timer_s); -RB_PROTOTYPE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare) - -/* The head of the timers tree */ -static struct uv_timer_tree_s uv_timers_ = RB_INITIALIZER(uv_timers_); - - -/* Head of a single-linked list of closed handles */ -static uv_handle_t* uv_endgame_handles_ = NULL; - - -/* Tail of a single-linked circular queue of pending reqs. If the queue is */ -/* empty, tail_ is NULL. If there is only one item, tail_->next_req == tail_ */ -static uv_req_t* uv_pending_reqs_tail_ = NULL; - - -/* The current time according to the event loop. in msecs. */ -static int64_t uv_now_ = 0; -static int64_t uv_ticks_per_msec_ = 0; - - -/* - * Global I/O completion port - */ -static HANDLE uv_iocp_; - - -/* Global error code */ -static const uv_err_t uv_ok_ = { UV_OK, ERROR_SUCCESS }; -static uv_err_t uv_last_error_ = { UV_OK, ERROR_SUCCESS }; - -/* Error message string */ -static char* uv_err_str_ = NULL; - - -/* Reference count that keeps the event loop alive */ -static int uv_refs_ = 0; - - -/* 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_read */ -static char uv_zero_[] = ""; - - -/* mark if IPv6 sockets are supported */ -static BOOL uv_allow_ipv6 = FALSE; - - -/* - * Subclass of uv_handle_t. Used for integration of c-ares. - */ -typedef struct uv_ares_action_s uv_ares_action_t; - -struct uv_ares_action_s { - UV_HANDLE_FIELDS - struct uv_req_s ares_req; - SOCKET sock; - int read; - int write; -}; - -void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req); -void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req); -void uv_ares_poll(uv_timer_t* handle, int status); - -static void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err); - -/* memory used per ares_channel */ -struct uv_ares_channel_s { - ares_channel channel; - int activesockets; - uv_timer_t pollingtimer; -}; - -typedef struct uv_ares_channel_s uv_ares_channel_t; - -/* static data to hold single ares_channel */ -static uv_ares_channel_t uv_ares_data = { NULL, 0 }; - -/* default timeout per socket request if ares does not specify value */ -/* use 20 sec */ -#define ARES_TIMEOUT_MS 20000 - - -/* getaddrinfo integration */ -static void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_t* req); -/* adjust size value to be multiple of 4. Use to keep pointer aligned */ -/* Do we need different versions of this for different architectures? */ -#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) - - -/* Atomic set operation on char */ -#ifdef _MSC_VER /* MSVC */ - -/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ -/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ -/* exist, and interlocked operations on larger targets might require the */ -/* target to be aligned. */ -#pragma intrinsic(_InterlockedOr8) - -static char __declspec(inline) uv_atomic_exchange_set(char volatile* target) { - return _InterlockedOr8(target, 1); -} - -#else /* GCC */ - -/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ -static inline char uv_atomic_exchange_set(char volatile* target) { - const char one = 1; - char old_value; - __asm__ __volatile__ ("lock xchgb %0, %1\n\t" - : "=r"(old_value), "=m"(*target) - : "0"(one), "m"(*target) - : "memory"); - return old_value; -} - -#endif - - -/* - * Display an error message and abort the event loop. - */ -static void uv_fatal_error(const int errorno, const char* syscall) { - char* buf = NULL; - const char* errmsg; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); - - if (buf) { - errmsg = buf; - } else { - errmsg = "Unknown error"; - } - - /* FormatMessage messages include a newline character already, */ - /* so don't add another. */ - if (syscall) { - fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); - } else { - fprintf(stderr, "(%d) %s", errorno, errmsg); - } - - if (buf) { - LocalFree(buf); - } - - *((char*)NULL) = 0xff; /* Force debug break */ - abort(); -} - - -uv_err_t uv_last_error() { - return uv_last_error_; -} - - -char* uv_strerror(uv_err_t err) { - if (uv_err_str_ != NULL) { - LocalFree((void*) uv_err_str_); - } - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err.sys_errno_, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&uv_err_str_, 0, NULL); - - if (uv_err_str_) { - return uv_err_str_; - } else { - return "Unknown error"; - } -} - - -static uv_err_code uv_translate_sys_error(int sys_errno) { - switch (sys_errno) { - case ERROR_SUCCESS: return UV_OK; - case ERROR_NOACCESS: return UV_EACCESS; - case WSAEACCES: return UV_EACCESS; - case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; - case WSAEADDRINUSE: return UV_EADDRINUSE; - case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; - case WSAEWOULDBLOCK: return UV_EAGAIN; - case WSAEALREADY: return UV_EALREADY; - case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; - case WSAECONNREFUSED: return UV_ECONNREFUSED; - case WSAEFAULT: return UV_EFAULT; - case ERROR_INVALID_DATA: return UV_EINVAL; - case WSAEINVAL: return UV_EINVAL; - case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; - case WSAEMFILE: return UV_EMFILE; - case ERROR_OUTOFMEMORY: return UV_ENOMEM; - case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; - case ERROR_INVALID_FLAGS: return UV_EBADF; - case ERROR_INVALID_PARAMETER: return UV_EINVAL; - case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; - case ERROR_BROKEN_PIPE: return UV_EOF; - case ERROR_PIPE_BUSY: return UV_EBUSY; - case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT; - default: return UV_UNKNOWN; - } -} - - -static uv_err_t uv_new_sys_error(int sys_errno) { - uv_err_t e; - e.code = uv_translate_sys_error(sys_errno); - e.sys_errno_ = sys_errno; - return e; -} - - -static void uv_set_sys_error(int sys_errno) { - uv_last_error_.code = uv_translate_sys_error(sys_errno); - uv_last_error_.sys_errno_ = sys_errno; -} - - -/* - * 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_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; - LARGE_INTEGER timer_frequency; - 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("::1", 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"); - } - } - - /* Create an I/O completion port */ - uv_iocp_ = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); - if (uv_iocp_ == NULL) { - uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); - } - - /* Initialize the event loop time */ - if (!QueryPerformanceFrequency(&timer_frequency)) - uv_fatal_error(GetLastError(), "QueryPerformanceFrequency"); - uv_ticks_per_msec_ = timer_frequency.QuadPart / 1000; - - uv_update_time(); -} - - -static void uv_req_init(uv_req_t* req) { - uv_counters()->req_init++; - req->type = UV_UNKNOWN_REQ; - req->error = uv_ok_; -} - - -static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { - return CONTAINING_RECORD(overlapped, uv_req_t, overlapped); -} - - -static void uv_insert_pending_req(uv_req_t* req) { - req->next_req = NULL; - if (uv_pending_reqs_tail_) { - req->next_req = uv_pending_reqs_tail_->next_req; - uv_pending_reqs_tail_->next_req = req; - uv_pending_reqs_tail_ = req; - } else { - req->next_req = req; - uv_pending_reqs_tail_ = req; - } -} - - -static uv_req_t* uv_remove_pending_req() { - uv_req_t* req; - - if (uv_pending_reqs_tail_) { - req = uv_pending_reqs_tail_->next_req; - - if (req == uv_pending_reqs_tail_) { - uv_pending_reqs_tail_ = NULL; - } else { - uv_pending_reqs_tail_->next_req = req->next_req; - } - - return req; - - } else { - /* queue empty */ - return NULL; - } -} - - -static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { - DWORD yes = 1; - - assert(handle->socket == INVALID_SOCKET); - - /* Set the socket to nonblocking mode */ - if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - /* Make the socket non-inheritable */ - if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) { - uv_set_sys_error(GetLastError()); - return -1; - } - - /* Associate it with the I/O completion port. */ - /* Use uv_handle_t pointer as completion key. */ - if (CreateIoCompletionPort((HANDLE)socket, - uv_iocp_, - (ULONG_PTR)socket, - 0) == NULL) { - uv_set_sys_error(GetLastError()); - return -1; - } - - handle->socket = socket; - - return 0; -} - - -static void uv_init_connection(uv_stream_t* handle) { - handle->flags |= UV_HANDLE_CONNECTION; - handle->write_reqs_pending = 0; - - uv_req_init((uv_req_t*) &(handle->read_req)); - handle->read_req.type = UV_READ; - handle->read_req.data = handle; -} - - -int uv_stream_init(uv_stream_t* handle) { - handle->write_queue_size = 0; - handle->flags = 0; - handle->error = uv_ok_; - - uv_counters()->handle_init++; - uv_counters()->stream_init++; - - uv_refs_++; - - return 0; -} - - -int uv_tcp_init(uv_tcp_t* handle) { - uv_stream_init((uv_stream_t*)handle); - - handle->socket = INVALID_SOCKET; - handle->type = UV_TCP; - handle->reqs_pending = 0; - handle->accept_socket = INVALID_SOCKET; - - uv_counters()->tcp_init++; - - return 0; -} - - -static void uv_tcp_endgame(uv_tcp_t* handle) { - uv_err_t err; - int status; - - if (handle->flags & UV_HANDLE_SHUTTING && - !(handle->flags & UV_HANDLE_SHUT) && - handle->write_reqs_pending == 0) { - - if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) { - status = 0; - handle->flags |= UV_HANDLE_SHUT; - } else { - status = -1; - err = uv_new_sys_error(WSAGetLastError()); - } - if (handle->shutdown_req->cb) { - if (status == -1) { - uv_last_error_ = err; - } - handle->shutdown_req->cb(handle->shutdown_req, status); - } - handle->reqs_pending--; - } - - if (handle->flags & UV_HANDLE_CLOSING && - handle->reqs_pending == 0) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_refs_--; - } -} - - -static void uv_pipe_endgame(uv_pipe_t* handle) { - uv_err_t err; - int status; - - if (handle->flags & UV_HANDLE_SHUTTING && - !(handle->flags & UV_HANDLE_SHUT) && - handle->write_reqs_pending == 0) { - close_pipe(handle, &status, &err); - - if (handle->shutdown_req->cb) { - if (status == -1) { - uv_last_error_ = err; - } - handle->shutdown_req->cb(handle->shutdown_req, status); - } - handle->reqs_pending--; - } - - if (handle->flags & UV_HANDLE_CLOSING && - handle->reqs_pending == 0) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_refs_--; - } -} - - -static void uv_timer_endgame(uv_timer_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_refs_--; - } -} - - -static void uv_loop_watcher_endgame(uv_handle_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb(handle); - } - - uv_refs_--; - } -} - - -static void uv_async_endgame(uv_async_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING && - !handle->async_sent) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_refs_--; - } -} - - -static void uv_process_endgames() { - uv_handle_t* handle; - - while (uv_endgame_handles_) { - handle = uv_endgame_handles_; - uv_endgame_handles_ = handle->endgame_next; - - handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; - - switch (handle->type) { - case UV_TCP: - uv_tcp_endgame((uv_tcp_t*)handle); - break; - - case UV_NAMED_PIPE: - uv_pipe_endgame((uv_pipe_t*)handle); - break; - - case UV_TIMER: - uv_timer_endgame((uv_timer_t*)handle); - break; - - case UV_PREPARE: - case UV_CHECK: - case UV_IDLE: - uv_loop_watcher_endgame(handle); - break; - - case UV_ASYNC: - uv_async_endgame((uv_async_t*)handle); - break; - - default: - assert(0); - break; - } - } -} - - -static void uv_want_endgame(uv_handle_t* handle) { - if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { - handle->flags |= UV_HANDLE_ENDGAME_QUEUED; - - handle->endgame_next = uv_endgame_handles_; - uv_endgame_handles_ = handle; - } -} - - -static int uv_close_error(uv_handle_t* handle, uv_err_t e) { - uv_tcp_t* tcp; - uv_pipe_t* pipe; - - if (handle->flags & UV_HANDLE_CLOSING) { - return 0; - } - - handle->error = e; - handle->flags |= UV_HANDLE_CLOSING; - - /* Handle-specific close actions */ - switch (handle->type) { - case UV_TCP: - tcp = (uv_tcp_t*)handle; - /* If we don't shutdown before calling closesocket, windows will */ - /* silently discard the kernel send buffer and reset the connection. */ - if (!(tcp->flags & UV_HANDLE_SHUT)) { - shutdown(tcp->socket, SD_SEND); - tcp->flags |= UV_HANDLE_SHUT; - } - tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); - closesocket(tcp->socket); - if (tcp->reqs_pending == 0) { - uv_want_endgame(handle); - } - return 0; - - case UV_NAMED_PIPE: - pipe = (uv_pipe_t*)handle; - pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); - close_pipe(pipe, NULL, NULL); - if (pipe->reqs_pending == 0) { - uv_want_endgame(handle); - } - return 0; - - case UV_TIMER: - uv_timer_stop((uv_timer_t*)handle); - uv_want_endgame(handle); - return 0; - - case UV_PREPARE: - uv_prepare_stop((uv_prepare_t*)handle); - uv_want_endgame(handle); - return 0; - - case UV_CHECK: - uv_check_stop((uv_check_t*)handle); - uv_want_endgame(handle); - return 0; - - case UV_IDLE: - uv_idle_stop((uv_idle_t*)handle); - uv_want_endgame(handle); - return 0; - - case UV_ASYNC: - if (!((uv_async_t*)handle)->async_sent) { - uv_want_endgame(handle); - } - return 0; - - default: - /* Not supported */ - assert(0); - return -1; - } -} - - -int uv_close(uv_handle_t* handle, uv_close_cb close_cb) { - handle->close_cb = close_cb; - return uv_close_error(handle, uv_ok_); -} - - -int uv__bind(uv_tcp_t* handle, int domain, struct sockaddr* addr, int addrsize) { - DWORD err; - int r; - SOCKET sock; - - if (handle->socket == INVALID_SOCKET) { - sock = socket(domain, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - if (uv_tcp_set_socket(handle, sock) == -1) { - closesocket(sock); - return -1; - } - } - - r = bind(handle->socket, addr, addrsize); - - if (r == SOCKET_ERROR) { - err = WSAGetLastError(); - if (err == WSAEADDRINUSE) { - /* Some errors are not to be reported until connect() or listen() */ - handle->error = uv_new_sys_error(err); - handle->flags |= UV_HANDLE_BIND_ERROR; - } else { - uv_set_sys_error(err); - return -1; - } - } - - handle->flags |= UV_HANDLE_BOUND; - - return 0; -} - - -int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) { - if (addr.sin_family != AF_INET) { - uv_set_sys_error(WSAEFAULT); - return -1; - } - - return uv__bind(handle, AF_INET, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); -} - - -int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { - if (addr.sin6_family != AF_INET6) { - uv_set_sys_error(WSAEFAULT); - return -1; - } - if (uv_allow_ipv6) { - handle->flags |= UV_HANDLE_IPV6; - return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6)); - } else { - uv_new_sys_error(UV_EAFNOSUPPORT); - return -1; - } -} - - -static void uv_tcp_queue_accept(uv_tcp_t* handle) { - uv_req_t* req; - BOOL success; - DWORD bytes; - SOCKET accept_socket; - short family; - LPFN_ACCEPTEX pAcceptExFamily; - - assert(handle->flags & UV_HANDLE_LISTENING); - assert(handle->accept_socket == INVALID_SOCKET); - - /* Prepare the uv_req structure. */ - req = &handle->accept_req; - - /* choose family and extension function */ - if ((handle->flags & UV_HANDLE_IPV6) != 0) { - family = AF_INET6; - pAcceptExFamily = pAcceptEx6; - } else { - family = AF_INET; - pAcceptExFamily = pAcceptEx; - } - - /* Open a socket for the accepted connection. */ - accept_socket = socket(family, SOCK_STREAM, 0); - if (accept_socket == INVALID_SOCKET) { - req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); - handle->reqs_pending++; - return; - } - - /* Prepare the overlapped structure. */ - memset(&(req->overlapped), 0, sizeof(req->overlapped)); - - success = pAcceptExFamily(handle->socket, - accept_socket, - (void*)&handle->accept_buffer, - 0, - sizeof(struct sockaddr_storage), - sizeof(struct sockaddr_storage), - &bytes, - &req->overlapped); - - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { - /* Make this req pending reporting an error. */ - req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); - handle->reqs_pending++; - /* Destroy the preallocated client socket. */ - closesocket(accept_socket); - return; - } - - handle->accept_socket = accept_socket; - - handle->reqs_pending++; -} - - -static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req) { - HANDLE pipeHandle; - - assert(handle->flags & UV_HANDLE_LISTENING); - assert(req->pipeHandle == INVALID_HANDLE_VALUE); - - pipeHandle = CreateNamedPipe(handle->name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - 65536, - 65536, - 0, - NULL); - - if (pipeHandle == INVALID_HANDLE_VALUE) { - req->error = uv_new_sys_error(GetLastError()); - uv_insert_pending_req((uv_req_t*) req); - handle->reqs_pending++; - return; - } - - if (CreateIoCompletionPort(pipeHandle, - uv_iocp_, - (ULONG_PTR)handle, - 0) == NULL) { - req->error = uv_new_sys_error(GetLastError()); - uv_insert_pending_req((uv_req_t*) req); - handle->reqs_pending++; - return; - } - - /* Prepare the overlapped structure. */ - memset(&(req->overlapped), 0, sizeof(req->overlapped)); - - if (!ConnectNamedPipe(pipeHandle, &req->overlapped) && GetLastError() != ERROR_IO_PENDING) { - if (GetLastError() == ERROR_PIPE_CONNECTED) { - req->pipeHandle = pipeHandle; - req->error = uv_ok_; - } else { - /* Make this req pending reporting an error. */ - req->error = uv_new_sys_error(GetLastError()); - } - uv_insert_pending_req((uv_req_t*) req); - handle->reqs_pending++; - return; - } - - req->pipeHandle = pipeHandle; - handle->reqs_pending++; -} - - -static void uv_tcp_queue_read(uv_tcp_t* handle) { - uv_req_t* req; - uv_buf_t buf; - int result; - DWORD bytes, flags; - - assert(handle->flags & UV_HANDLE_READING); - assert(!(handle->flags & UV_HANDLE_READ_PENDING)); - - req = &handle->read_req; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - buf.base = (char*) &uv_zero_; - buf.len = 0; - - flags = 0; - result = WSARecv(handle->socket, - (WSABUF*)&buf, - 1, - &bytes, - &flags, - &req->overlapped, - NULL); - if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) { - /* Make this req pending reporting an error. */ - req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); - handle->reqs_pending++; - return; - } - - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; -} - - -static void uv_pipe_queue_read(uv_pipe_t* handle) { - uv_req_t* req; - int result; - - assert(handle->flags & UV_HANDLE_READING); - assert(!(handle->flags & UV_HANDLE_READ_PENDING)); - - assert(handle->handle != INVALID_HANDLE_VALUE); - - req = &handle->read_req; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - /* Do 0-read */ - result = ReadFile(handle->handle, - &uv_zero_, - 0, - NULL, - &req->overlapped); - - if (!result && GetLastError() != ERROR_IO_PENDING) { - /* Make this req pending reporting an error. */ - req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); - handle->reqs_pending++; - return; - } - - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; -} - - -int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { - assert(backlog > 0); - - if (handle->flags & UV_HANDLE_BIND_ERROR) { - uv_last_error_ = handle->error; - return -1; - } - - if (handle->flags & UV_HANDLE_LISTENING || - handle->flags & UV_HANDLE_READING) { - /* Already listening. */ - uv_set_sys_error(WSAEALREADY); - return -1; - } - - if (!(handle->flags & UV_HANDLE_BOUND) && - uv_tcp_bind(handle, uv_addr_ip4_any_) < 0) - return -1; - - if (listen(handle->socket, backlog) == SOCKET_ERROR) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - handle->flags |= UV_HANDLE_LISTENING; - handle->connection_cb = cb; - - uv_req_init(&(handle->accept_req)); - handle->accept_req.type = UV_ACCEPT; - handle->accept_req.data = handle; - uv_tcp_queue_accept(handle); - - return 0; -} - - -static int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { - int rv = 0; - - if (server->accept_socket == INVALID_SOCKET) { - uv_set_sys_error(WSAENOTCONN); - return -1; - } - - if (uv_tcp_set_socket(client, server->accept_socket) == -1) { - closesocket(server->accept_socket); - rv = -1; - } else { - uv_init_connection((uv_stream_t*)client); - } - - server->accept_socket = INVALID_SOCKET; - - if (!(server->flags & UV_HANDLE_CLOSING)) { - uv_tcp_queue_accept(server); - } - - return rv; -} - - -static int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client) { - /* Find a connection instance that has been connected, but not yet accepted. */ - uv_pipe_accept_t* req = server->pending_accepts; - - if (!req) { - /* No valid connections found, so we error out. */ - uv_set_sys_error(WSAEWOULDBLOCK); - return -1; - } - - /* Initialize the client handle and copy the pipeHandle to the client */ - uv_pipe_init(client); - uv_init_connection((uv_stream_t*) client); - client->handle = req->pipeHandle; - - /* Prepare the req to pick up a new connection */ - server->pending_accepts = req->next_pending; - req->next_pending = NULL; - req->pipeHandle = INVALID_HANDLE_VALUE; - - if (!(server->flags & UV_HANDLE_CLOSING)) { - uv_pipe_queue_accept(server, req); - } - - return 0; -} - - -int uv_accept(uv_handle_t* server, uv_stream_t* client) { - assert(client->type == server->type); - - if (server->type == UV_TCP) { - return uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); - } else if (server->type == UV_NAMED_PIPE) { - return uv_pipe_accept((uv_pipe_t*)server, (uv_pipe_t*)client); - } - - return -1; -} - - -static int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - uv_set_sys_error(WSAEINVAL); - return -1; - } - - if (handle->flags & UV_HANDLE_READING) { - uv_set_sys_error(WSAEALREADY); - return -1; - } - - if (handle->flags & UV_HANDLE_EOF) { - uv_set_sys_error(WSAESHUTDOWN); - return -1; - } - - handle->flags |= UV_HANDLE_READING; - handle->read_cb = read_cb; - handle->alloc_cb = alloc_cb; - - /* If reading was stopped and then started again, there could stell be a */ - /* read request pending. */ - if (!(handle->flags & UV_HANDLE_READ_PENDING)) - uv_tcp_queue_read(handle); - - return 0; -} - - -static int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - uv_set_sys_error(UV_EINVAL); - return -1; - } - - if (handle->flags & UV_HANDLE_READING) { - uv_set_sys_error(UV_EALREADY); - return -1; - } - - if (handle->flags & UV_HANDLE_EOF) { - uv_set_sys_error(UV_EOF); - return -1; - } - - handle->flags |= UV_HANDLE_READING; - handle->read_cb = read_cb; - handle->alloc_cb = alloc_cb; - - /* If reading was stopped and then started again, there could stell be a */ - /* read request pending. */ - if (!(handle->flags & UV_HANDLE_READ_PENDING)) - uv_pipe_queue_read(handle); - - return 0; -} - - -int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { - if (handle->type == UV_TCP) { - return uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); - } else if (handle->type == UV_NAMED_PIPE) { - return uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); - } - - return -1; -} - - -int uv_read_stop(uv_stream_t* handle) { - handle->flags &= ~UV_HANDLE_READING; - - return 0; -} - - -int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, - struct sockaddr_in address, uv_connect_cb cb) { - int addrsize = sizeof(struct sockaddr_in); - BOOL success; - DWORD bytes; - - if (handle->flags & UV_HANDLE_BIND_ERROR) { - uv_last_error_ = handle->error; - return -1; - } - - if (address.sin_family != AF_INET) { - uv_set_sys_error(WSAEFAULT); - return -1; - } - - if (!(handle->flags & UV_HANDLE_BOUND) && - uv_tcp_bind(handle, uv_addr_ip4_any_) < 0) - return -1; - - uv_req_init((uv_req_t*) req); - req->type = UV_CONNECT; - req->handle = (uv_stream_t*) handle; - req->cb = cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - success = pConnectEx(handle->socket, - (struct sockaddr*) &address, - addrsize, - NULL, - 0, - &bytes, - &req->overlapped); - - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - handle->reqs_pending++; - - return 0; -} - - -int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, - struct sockaddr_in6 address, uv_connect_cb cb) { - int addrsize = sizeof(struct sockaddr_in6); - BOOL success; - DWORD bytes; - - if (!uv_allow_ipv6) { - uv_new_sys_error(UV_EAFNOSUPPORT); - return -1; - } - - if (handle->flags & UV_HANDLE_BIND_ERROR) { - uv_last_error_ = handle->error; - return -1; - } - - if (address.sin6_family != AF_INET6) { - uv_set_sys_error(WSAEFAULT); - return -1; - } - - if (!(handle->flags & UV_HANDLE_BOUND) && - uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0) - return -1; - - uv_req_init((uv_req_t*) req); - req->type = UV_CONNECT; - req->handle = (uv_stream_t*) handle; - req->cb = cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - success = pConnectEx6(handle->socket, - (struct sockaddr*) &address, - addrsize, - NULL, - 0, - &bytes, - &req->overlapped); - - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - handle->reqs_pending++; - - return 0; -} - - -int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - int result; - - if (handle->flags & UV_HANDLE_SHUTTING) { - uv_set_sys_error(WSAESHUTDOWN); - return -1; - } - - result = getsockname(handle->socket, name, namelen); - if (result != 0) { - uv_set_sys_error(WSAGetLastError()); - return -1; - } - - return 0; -} - - -static size_t uv_count_bufs(uv_buf_t bufs[], int count) { - size_t bytes = 0; - int i; - - for (i = 0; i < count; i++) { - bytes += (size_t)bufs[i].len; - } - - return bytes; -} - - -static int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt, - uv_write_cb cb) { - int result; - DWORD bytes, err; - - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - uv_set_sys_error(WSAEINVAL); - return -1; - } - - if (handle->flags & UV_HANDLE_SHUTTING) { - uv_set_sys_error(WSAESHUTDOWN); - return -1; - } - - uv_req_init((uv_req_t*) req); - req->type = UV_WRITE; - req->handle = (uv_stream_t*) handle; - req->cb = cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - result = WSASend(handle->socket, - (WSABUF*)bufs, - bufcnt, - &bytes, - 0, - &req->overlapped, - NULL); - if (result != 0) { - err = WSAGetLastError(); - if (err != WSA_IO_PENDING) { - /* Send failed due to an error. */ - uv_set_sys_error(WSAGetLastError()); - return -1; - } - } - - if (result == 0) { - /* Request completed immediately. */ - req->queued_bytes = 0; - } else { - /* Request queued by the kernel. */ - req->queued_bytes = uv_count_bufs(bufs, bufcnt); - handle->write_queue_size += req->queued_bytes; - } - - handle->reqs_pending++; - handle->write_reqs_pending++; - - return 0; -} - - -int uv_pipe_write(uv_write_t* req, uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt, - uv_write_cb cb) { - int result; - - if (bufcnt != 1) { - uv_set_sys_error(UV_ENOTSUP); - return -1; - } - - assert(handle->handle != INVALID_HANDLE_VALUE); - - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - uv_set_sys_error(UV_EINVAL); - return -1; - } - - if (handle->flags & UV_HANDLE_SHUTTING) { - uv_set_sys_error(UV_EOF); - return -1; - } - - uv_req_init((uv_req_t*) req); - req->type = UV_WRITE; - req->handle = (uv_stream_t*) handle; - req->cb = cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, - NULL, - &req->overlapped); - - if (!result && GetLastError() != WSA_IO_PENDING) { - uv_set_sys_error(GetLastError()); - return -1; - } - - if (result) { - /* Request completed immediately. */ - req->queued_bytes = 0; - } else { - /* Request queued by the kernel. */ - req->queued_bytes = uv_count_bufs(bufs, bufcnt); - handle->write_queue_size += req->queued_bytes; - } - - handle->reqs_pending++; - handle->write_reqs_pending++; - - return 0; -} - - -int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt, - uv_write_cb cb) { - if (handle->type == UV_TCP) { - return uv_tcp_write(req, (uv_tcp_t*) handle, bufs, bufcnt, cb); - } else if (handle->type == UV_NAMED_PIPE) { - return uv_pipe_write(req, (uv_pipe_t*) handle, bufs, bufcnt, cb); - } - - uv_set_sys_error(WSAEINVAL); - return -1; -} - - -int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - uv_set_sys_error(WSAEINVAL); - return -1; - } - - if (handle->flags & UV_HANDLE_SHUTTING) { - uv_set_sys_error(WSAESHUTDOWN); - return -1; - } - - uv_req_init((uv_req_t*) req); - req->type = UV_SHUTDOWN; - req->handle = handle; - req->cb = cb; - - handle->flags |= UV_HANDLE_SHUTTING; - handle->shutdown_req = req; - handle->reqs_pending++; - - uv_want_endgame((uv_handle_t*)handle); - - return 0; -} - - -#define DECREASE_PENDING_REQ_COUNT(handle) \ - do { \ - handle->reqs_pending--; \ - \ - if (handle->flags & UV_HANDLE_CLOSING && \ - handle->reqs_pending == 0) { \ - uv_want_endgame((uv_handle_t*)handle); \ - } \ - } while (0) - - -static void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) { - DWORD bytes, flags, err; - uv_buf_t buf; - - assert(handle->type == UV_TCP); - - handle->flags &= ~UV_HANDLE_READ_PENDING; - - if (req->error.code != UV_OK) { - /* An error occurred doing the 0-read. */ - if ((handle->flags & UV_HANDLE_READING)) { - handle->flags &= ~UV_HANDLE_READING; - uv_last_error_ = req->error; - buf.base = 0; - buf.len = 0; - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - } else { - /* Do nonblocking reads until the buffer is empty */ - while (handle->flags & UV_HANDLE_READING) { - buf = handle->alloc_cb((uv_stream_t*)handle, 65536); - assert(buf.len > 0); - flags = 0; - if (WSARecv(handle->socket, - (WSABUF*)&buf, - 1, - &bytes, - &flags, - NULL, - NULL) != SOCKET_ERROR) { - if (bytes > 0) { - /* Successful read */ - handle->read_cb((uv_stream_t*)handle, bytes, buf); - /* Read again only if bytes == buf.len */ - if (bytes < buf.len) { - break; - } - } else { - /* Connection closed */ - handle->flags &= ~UV_HANDLE_READING; - handle->flags |= UV_HANDLE_EOF; - uv_last_error_.code = UV_EOF; - uv_last_error_.sys_errno_ = ERROR_SUCCESS; - handle->read_cb((uv_stream_t*)handle, -1, buf); - break; - } - } else { - err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { - /* Read buffer was completely empty, report a 0-byte read. */ - uv_set_sys_error(WSAEWOULDBLOCK); - handle->read_cb((uv_stream_t*)handle, 0, buf); - } else { - /* Ouch! serious error. */ - uv_set_sys_error(err); - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - break; - } - } - - /* Post another 0-read if still reading and not closing. */ - if ((handle->flags & UV_HANDLE_READING) && - !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_tcp_queue_read(handle); - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) { - assert(handle->type == UV_TCP); - - handle->write_queue_size -= req->queued_bytes; - - if (req->cb) { - uv_last_error_ = req->error; - ((uv_write_cb)req->cb)(req, uv_last_error_.code == UV_OK ? 0 : -1); - } - - handle->write_reqs_pending--; - if (handle->flags & UV_HANDLE_SHUTTING && - handle->write_reqs_pending == 0) { - uv_want_endgame((uv_handle_t*)handle); - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) { - assert(handle->type == UV_TCP); - - /* If handle->accepted_socket is not a valid socket, then */ - /* uv_queue_accept must have failed. This is a serious error. We stop */ - /* accepting connections and report this error to the connection */ - /* callback. */ - if (handle->accept_socket == INVALID_SOCKET) { - if (handle->flags & UV_HANDLE_LISTENING) { - handle->flags &= ~UV_HANDLE_LISTENING; - if (handle->connection_cb) { - uv_last_error_ = req->error; - handle->connection_cb((uv_handle_t*)handle, -1); - } - } - } else if (req->error.code == UV_OK && - setsockopt(handle->accept_socket, - SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, - (char*)&handle->socket, - sizeof(handle->socket)) == 0) { - /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ - if (handle->connection_cb) { - handle->connection_cb((uv_handle_t*)handle, 0); - } - } else { - /* Error related to accepted socket is ignored because the server */ - /* socket may still be healthy. If the server socket is broken - /* uv_queue_accept will detect it. */ - closesocket(handle->accept_socket); - if (handle->flags & UV_HANDLE_LISTENING) { - uv_tcp_queue_accept(handle); - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) { - assert(handle->type == UV_TCP); - - if (req->cb) { - if (req->error.code == UV_OK) { - if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { - uv_init_connection((uv_stream_t*)handle); - ((uv_connect_cb)req->cb)(req, 0); - } else { - uv_set_sys_error(WSAGetLastError()); - ((uv_connect_cb)req->cb)(req, -1); - } - } else { - uv_last_error_ = req->error; - ((uv_connect_cb)req->cb)(req, -1); - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) { - DWORD bytes, err, mode; - uv_buf_t buf; - - assert(handle->type == UV_NAMED_PIPE); - - handle->flags &= ~UV_HANDLE_READ_PENDING; - - if (req->error.code != UV_OK) { - /* An error occurred doing the 0-read. */ - if (handle->flags & UV_HANDLE_READING) { - /* Stop reading and report error. */ - handle->flags &= ~UV_HANDLE_READING; - uv_last_error_ = req->error; - buf.base = 0; - buf.len = 0; - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - } else { - /* - * Temporarily switch to non-blocking mode. - * This is so that ReadFile doesn't block if the read buffer is empty. - */ - mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT; - if (!SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) { - /* We can't continue processing this read. */ - handle->flags &= ~UV_HANDLE_READING; - uv_set_sys_error(GetLastError()); - buf.base = 0; - buf.len = 0; - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - - /* Do non-blocking reads until the buffer is empty */ - while (handle->flags & UV_HANDLE_READING) { - buf = handle->alloc_cb((uv_stream_t*)handle, 65536); - assert(buf.len > 0); - - if (ReadFile(handle->handle, - buf.base, - buf.len, - &bytes, - NULL)) { - if (bytes > 0) { - /* Successful read */ - handle->read_cb((uv_stream_t*)handle, bytes, buf); - /* Read again only if bytes == buf.len */ - if (bytes < buf.len) { - break; - } - } else { - /* Connection closed */ - handle->flags &= ~UV_HANDLE_READING; - handle->flags |= UV_HANDLE_EOF; - uv_last_error_.code = UV_EOF; - uv_last_error_.sys_errno_ = ERROR_SUCCESS; - handle->read_cb((uv_stream_t*)handle, -1, buf); - break; - } - } else { - err = GetLastError(); - if (err == ERROR_NO_DATA) { - /* Read buffer was completely empty, report a 0-byte read. */ - uv_set_sys_error(WSAEWOULDBLOCK); - handle->read_cb((uv_stream_t*)handle, 0, buf); - } else { - /* Ouch! serious error. */ - uv_set_sys_error(err); - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - break; - } - } - - /* TODO: if the read callback stops reading we can't start reading again - because the pipe will still be in nowait mode. */ - if ((handle->flags & UV_HANDLE_READING) && - !(handle->flags & UV_HANDLE_READ_PENDING)) { - /* Switch back to blocking mode so that we can use IOCP for 0-reads */ - mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; - if (SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) { - /* Post another 0-read */ - uv_pipe_queue_read(handle); - } else { - /* Report and continue. */ - /* We can't continue processing this read. */ - handle->flags &= ~UV_HANDLE_READING; - uv_set_sys_error(GetLastError()); - buf.base = 0; - buf.len = 0; - handle->read_cb((uv_stream_t*)handle, -1, buf); - } - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req) { - assert(handle->type == UV_NAMED_PIPE); - - handle->write_queue_size -= req->queued_bytes; - - if (req->cb) { - uv_last_error_ = req->error; - ((uv_write_cb)req->cb)(req, uv_last_error_.code == UV_OK ? 0 : -1); - } - - handle->write_reqs_pending--; - if (handle->write_reqs_pending == 0 && - handle->flags & UV_HANDLE_SHUTTING) { - uv_want_endgame((uv_handle_t*)handle); - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req) { - uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; - - assert(handle->type == UV_NAMED_PIPE); - - if (req->error.code == UV_OK) { - assert(req->pipeHandle != INVALID_HANDLE_VALUE); - - req->next_pending = handle->pending_accepts; - handle->pending_accepts = req; - - if (handle->connection_cb) { - handle->connection_cb((uv_handle_t*)handle, 0); - } - } else { - if (req->pipeHandle != INVALID_HANDLE_VALUE) { - CloseHandle(req->pipeHandle); - req->pipeHandle = INVALID_HANDLE_VALUE; - } - if (!(handle->flags & UV_HANDLE_CLOSING)) { - uv_pipe_queue_accept(handle, req); - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req) { - assert(handle->type == UV_NAMED_PIPE); - - if (req->cb) { - if (req->error.code == UV_OK) { - uv_init_connection((uv_stream_t*)handle); - ((uv_connect_cb)req->cb)(req, 0); - } else { - uv_last_error_ = req->error; - ((uv_connect_cb)req->cb)(req, -1); - } - } - - DECREASE_PENDING_REQ_COUNT(handle); -} - - -static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { - if (a->due < b->due) - return -1; - if (a->due > b->due) - return 1; - if ((intptr_t)a < (intptr_t)b) - return -1; - if ((intptr_t)a > (intptr_t)b) - return 1; - return 0; -} - - -RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); - - -int uv_timer_init(uv_timer_t* handle) { - uv_counters()->handle_init++; - uv_counters()->timer_init++; - - handle->type = UV_TIMER; - handle->flags = 0; - handle->error = uv_ok_; - handle->timer_cb = NULL; - handle->repeat = 0; - - uv_refs_++; - - return 0; -} - - -int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, int64_t repeat) { - if (handle->flags & UV_HANDLE_ACTIVE) { - RB_REMOVE(uv_timer_tree_s, &uv_timers_, handle); - } - - handle->timer_cb = (void*) timer_cb; - handle->due = uv_now_ + timeout; - handle->repeat = repeat; - handle->flags |= UV_HANDLE_ACTIVE; - - if (RB_INSERT(uv_timer_tree_s, &uv_timers_, handle) != NULL) { - uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); - } - - return 0; -} - - -int uv_timer_stop(uv_timer_t* handle) { - if (!(handle->flags & UV_HANDLE_ACTIVE)) - return 0; - - RB_REMOVE(uv_timer_tree_s, &uv_timers_, handle); - - handle->flags &= ~UV_HANDLE_ACTIVE; - - return 0; -} - - -int uv_timer_again(uv_timer_t* handle) { - /* If timer_cb is NULL that means that the timer was never started. */ - if (!handle->timer_cb) { - uv_set_sys_error(ERROR_INVALID_DATA); - return -1; - } - - if (handle->flags & UV_HANDLE_ACTIVE) { - RB_REMOVE(uv_timer_tree_s, &uv_timers_, handle); - handle->flags &= ~UV_HANDLE_ACTIVE; - } - - if (handle->repeat) { - handle->due = uv_now_ + handle->repeat; - - if (RB_INSERT(uv_timer_tree_s, &uv_timers_, handle) != NULL) { - uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); - } - - handle->flags |= UV_HANDLE_ACTIVE; - } - - return 0; -} - - -void uv_timer_set_repeat(uv_timer_t* handle, int64_t repeat) { - assert(handle->type == UV_TIMER); - handle->repeat = repeat; -} - - -int64_t uv_timer_get_repeat(uv_timer_t* handle) { - assert(handle->type == UV_TIMER); - return handle->repeat; -} - - -void uv_update_time() { - LARGE_INTEGER counter; - - if (!QueryPerformanceCounter(&counter)) - uv_fatal_error(GetLastError(), "QueryPerformanceCounter"); - - uv_now_ = counter.QuadPart / uv_ticks_per_msec_; -} - - -int64_t uv_now() { - return uv_now_; -} - - -#define UV_LOOP_WATCHER_DEFINE(name, NAME) \ - /* Lists of active loop (prepare / check / idle) watchers */ \ - static uv_##name##_t* uv_##name##_handles_ = NULL; \ - \ - /* This pointer will refer to the prepare/check/idle handle whose */ \ - /* callback is scheduled to be called next. This is needed to allow */ \ - /* safe removal from one of the lists above while that list being */ \ - /* iterated over. */ \ - static uv_##name##_t* uv_next_##name##_handle_ = NULL; \ - \ - \ - int uv_##name##_init(uv_##name##_t* handle) { \ - handle->type = UV_##NAME; \ - handle->flags = 0; \ - handle->error = uv_ok_; \ - \ - uv_refs_++; \ - \ - uv_counters()->handle_init++; \ - uv_counters()->prepare_init++; \ - \ - return 0; \ - } \ - \ - \ - int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ - uv_##name##_t* old_head; \ - \ - assert(handle->type == UV_##NAME); \ - \ - if (handle->flags & UV_HANDLE_ACTIVE) \ - return 0; \ - \ - old_head = uv_##name##_handles_; \ - \ - handle->name##_next = old_head; \ - handle->name##_prev = NULL; \ - \ - if (old_head) { \ - old_head->name##_prev = handle; \ - } \ - \ - uv_##name##_handles_ = handle; \ - \ - handle->name##_cb = cb; \ - handle->flags |= UV_HANDLE_ACTIVE; \ - \ - return 0; \ - } \ - \ - \ - int uv_##name##_stop(uv_##name##_t* handle) { \ - assert(handle->type == UV_##NAME); \ - \ - if (!(handle->flags & UV_HANDLE_ACTIVE)) \ - return 0; \ - \ - /* Update loop head if needed */ \ - if (uv_##name##_handles_ == handle) { \ - uv_##name##_handles_ = handle->name##_next; \ - } \ - \ - /* Update the iterator-next pointer of needed */ \ - if (uv_next_##name##_handle_ == handle) { \ - uv_next_##name##_handle_ = handle->name##_next; \ - } \ - \ - if (handle->name##_prev) { \ - handle->name##_prev->name##_next = handle->name##_next; \ - } \ - if (handle->name##_next) { \ - handle->name##_next->name##_prev = handle->name##_prev; \ - } \ - \ - handle->flags &= ~UV_HANDLE_ACTIVE; \ - \ - return 0; \ - } \ - \ - \ - static void uv_##name##_invoke() { \ - uv_##name##_t* handle; \ - \ - uv_next_##name##_handle_ = uv_##name##_handles_; \ - \ - while (uv_next_##name##_handle_ != NULL) { \ - handle = uv_next_##name##_handle_; \ - uv_next_##name##_handle_ = handle->name##_next; \ - \ - handle->name##_cb(handle, 0); \ - } \ - } - - -UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) -UV_LOOP_WATCHER_DEFINE(check, CHECK) -UV_LOOP_WATCHER_DEFINE(idle, IDLE) - - -int uv_is_active(uv_handle_t* handle) { - switch (handle->type) { - case UV_TIMER: - case UV_IDLE: - case UV_PREPARE: - case UV_CHECK: - return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0; - - default: - return 1; - } -} - - -int uv_async_init(uv_async_t* handle, uv_async_cb async_cb) { - uv_req_t* req; - - uv_counters()->handle_init++; - uv_counters()->async_init++; - - handle->type = UV_ASYNC; - handle->flags = 0; - handle->async_sent = 0; - handle->error = uv_ok_; - handle->async_cb = async_cb; - - req = &handle->async_req; - uv_req_init(req); - req->type = UV_WAKEUP; - req->data = handle; - - uv_refs_++; - - return 0; -} - - -int uv_async_send(uv_async_t* handle) { - if (handle->type != UV_ASYNC) { - /* Can't set errno because that's not thread-safe. */ - return -1; - } - - /* The user should make sure never to call uv_async_send to a closing */ - /* or closed handle. */ - assert(!(handle->flags & UV_HANDLE_CLOSING)); - - if (!uv_atomic_exchange_set(&handle->async_sent)) { - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &handle->async_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - } - - return 0; -} - - -static void uv_process_async_wakeup_req(uv_async_t* handle, uv_req_t* req) { - assert(handle->type == UV_ASYNC); - assert(req->type == UV_WAKEUP); - - handle->async_sent = 0; - if (handle->async_cb) { - handle->async_cb((uv_async_t*) handle, 0); - } - if (handle->flags & UV_HANDLE_CLOSING) { - uv_want_endgame((uv_handle_t*)handle); - } -} - - -#define DELEGATE_STREAM_REQ(req, method, handle_at) \ - do { \ - switch (((uv_handle_t*) (req)->handle_at)->type) { \ - case UV_TCP: \ - uv_process_tcp_##method##_req((uv_tcp_t*) ((req)->handle_at), req); \ - break; \ - \ - case UV_NAMED_PIPE: \ - uv_process_pipe_##method##_req((uv_pipe_t*) ((req)->handle_at), req); \ - break; \ - \ - default: \ - assert(0); \ - } \ - } while (0) - - -static void uv_process_reqs() { - uv_req_t* req; - - while (req = uv_remove_pending_req()) { - switch (req->type) { - case UV_READ: - DELEGATE_STREAM_REQ(req, read, data); - break; - - case UV_WRITE: - DELEGATE_STREAM_REQ((uv_write_t*) req, write, handle); - break; - - case UV_ACCEPT: - DELEGATE_STREAM_REQ(req, accept, data); - break; - - case UV_CONNECT: - DELEGATE_STREAM_REQ((uv_connect_t*) req, connect, handle); - break; - - case UV_WAKEUP: - uv_process_async_wakeup_req((uv_async_t*) req->data, req); - break; - - case UV_ARES_EVENT_REQ: - uv_process_ares_event_req((uv_ares_action_t*) req->data, req); - break; - - case UV_ARES_CLEANUP_REQ: - uv_process_ares_cleanup_req((uv_ares_task_t*) req->data, req); - break; - - case UV_GETADDRINFO_REQ: - uv_process_getaddrinfo_req((uv_getaddrinfo_t*) req->data, req); - break; - - default: - assert(0); - } - } -} - - -static void uv_process_timers() { - uv_timer_t* timer; - - /* Call timer callbacks */ - for (timer = RB_MIN(uv_timer_tree_s, &uv_timers_); - timer != NULL && timer->due <= uv_now_; - timer = RB_MIN(uv_timer_tree_s, &uv_timers_)) { - RB_REMOVE(uv_timer_tree_s, &uv_timers_, timer); - - if (timer->repeat != 0) { - /* If it is a repeating timer, reschedule with repeat timeout. */ - timer->due += timer->repeat; - if (timer->due < uv_now_) { - timer->due = uv_now_; - } - if (RB_INSERT(uv_timer_tree_s, &uv_timers_, timer) != NULL) { - uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); - } - } else { - /* If non-repeating, mark the timer as inactive. */ - timer->flags &= ~UV_HANDLE_ACTIVE; - } - - timer->timer_cb((uv_timer_t*) timer, 0); - } -} - - -static DWORD uv_get_poll_timeout() { - uv_timer_t* timer; - int64_t delta; - - /* Check if there are any running timers */ - timer = RB_MIN(uv_timer_tree_s, &uv_timers_); - if (timer) { - uv_update_time(); - - delta = timer->due - uv_now_; - if (delta >= UINT_MAX) { - /* Can't have a timeout greater than UINT_MAX, and a timeout value of */ - /* UINT_MAX means infinite, so that's no good either. */ - return UINT_MAX - 1; - } else if (delta < 0) { - /* Negative timeout values are not allowed */ - return 0; - } else { - return (DWORD)delta; - } - } else { - /* No timers */ - return INFINITE; - } -} - - -static void uv_poll() { - BOOL success; - DWORD bytes; - ULONG_PTR key; - OVERLAPPED* overlapped; - uv_req_t* req; - - success = GetQueuedCompletionStatus(uv_iocp_, - &bytes, - &key, - &overlapped, - uv_get_poll_timeout()); - - uv_update_time(); - - if (overlapped) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlapped); - - if (!success) { - req->error = uv_new_sys_error(GetLastError()); - } - - uv_insert_pending_req(req); - - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } -} - - -int uv_run() { - while (1) { - uv_update_time(); - uv_process_timers(); - - /* Terrible: please fix me! */ - while (uv_refs_ > 0 && - (uv_idle_handles_ || uv_pending_reqs_tail_ || uv_endgame_handles_)) { - /* Terrible: please fix me! */ - while (uv_pending_reqs_tail_ || uv_endgame_handles_) { - uv_process_endgames(); - uv_process_reqs(); - } - - /* Call idle callbacks */ - uv_idle_invoke(); - } - - if (uv_refs_ <= 0) { - break; - } - - uv_prepare_invoke(); - - uv_poll(); - - uv_check_invoke(); - } - - assert(uv_refs_ == 0); - return 0; -} - - -void uv_ref() { - uv_refs_++; -} - - -void uv_unref() { - uv_refs_--; -} - - -int uv_utf16_to_utf8(wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size) { - return WideCharToMultiByte(CP_UTF8, 0, utf16Buffer, utf16Size, utf8Buffer, utf8Size, NULL, NULL); -} - -int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, size_t utf16Size) { - return MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, utf16Buffer, utf16Size); -} - - -int uv_exepath(char* buffer, size_t* size) { - int retVal; - size_t utf16Size; - wchar_t* utf16Buffer; - - if (!buffer || !size) { - return -1; - } - - utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * *size); - if (!utf16Buffer) { - retVal = -1; - goto done; - } - - /* Get the path as UTF-16 */ - utf16Size = GetModuleFileNameW(NULL, utf16Buffer, *size - 1); - if (utf16Size <= 0) { - uv_set_sys_error(GetLastError()); - retVal = -1; - goto done; - } - - utf16Buffer[utf16Size] = L'\0'; - - /* Convert to UTF-8 */ - *size = uv_utf16_to_utf8(utf16Buffer, utf16Size, buffer, *size); - if (!*size) { - uv_set_sys_error(GetLastError()); - retVal = -1; - goto done; - } - - buffer[*size] = '\0'; - retVal = 0; - -done: - if (utf16Buffer) { - free(utf16Buffer); - } - - return retVal; -} - - -uint64_t uv_hrtime(void) { - assert(0 && "implement me"); -} - - -/* thread pool callback when socket is signalled */ -VOID CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired) { - WSANETWORKEVENTS network_events; - uv_ares_task_t* sockhandle; - uv_ares_action_t* selhandle; - uv_req_t* uv_ares_req; - - assert(parameter != NULL); - - if (parameter != NULL) { - sockhandle = (uv_ares_task_t*)parameter; - - /* clear socket status for this event */ - /* do not fail if error, thread may run after socket close */ - /* The code assumes that c-ares will write all pending data in the callback, - unless the socket would block. We can clear the state here to avoid unecessary - signals. */ - WSAEnumNetworkEvents(sockhandle->sock, sockhandle->h_event, &network_events); - - /* setup new handle */ - selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t)); - if (selhandle == NULL) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - selhandle->type = UV_ARES_EVENT; - selhandle->close_cb = NULL; - selhandle->data = sockhandle->data; - selhandle->sock = sockhandle->sock; - selhandle->read = (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0; - selhandle->write = (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0; - - uv_ares_req = &selhandle->ares_req; - uv_req_init(uv_ares_req); - uv_ares_req->type = UV_ARES_EVENT_REQ; - uv_ares_req->data = selhandle; - - /* post ares needs to called */ - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &uv_ares_req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - } -} - -/* callback from ares when socket operation is started */ -void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int write) { - /* look to see if we have a handle for this socket in our list */ - uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(sock); - uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)data; - - int timeoutms = 0; - - if (read == 0 && write == 0) { - /* if read and write are 0, cleanup existing data */ - /* The code assumes that c-ares does a callback with read = 0 and write = 0 - when the socket is closed. After we recieve this we stop monitoring the socket. */ - if (uv_handle_ares != NULL) { - uv_req_t* uv_ares_req; - - uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL); - /* remove Wait */ - if (uv_handle_ares->h_wait) { - UnregisterWaitEx(uv_handle_ares->h_wait, uv_handle_ares->h_close_event); - uv_handle_ares->h_wait = NULL; - } - - /* detach socket from the event */ - WSAEventSelect(sock, NULL, 0); - if (uv_handle_ares->h_event != WSA_INVALID_EVENT) { - WSACloseEvent(uv_handle_ares->h_event); - uv_handle_ares->h_event = WSA_INVALID_EVENT; - } - /* remove handle from list */ - uv_remove_ares_handle(uv_handle_ares); - - /* Post request to cleanup the Task */ - uv_ares_req = &uv_handle_ares->ares_req; - uv_req_init(uv_ares_req); - uv_ares_req->type = UV_ARES_CLEANUP_REQ; - uv_ares_req->data = uv_handle_ares; - - /* post ares done with socket - finish cleanup when all threads done. */ - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &uv_ares_req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - } else { - assert(0); - uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); - } - } else { - if (uv_handle_ares == NULL) { - /* setup new handle */ - /* The code assumes that c-ares will call us when it has an open socket. - We need to call into c-ares when there is something to read, - or when it becomes writable. */ - uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t)); - if (uv_handle_ares == NULL) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - uv_handle_ares->type = UV_ARES_TASK; - uv_handle_ares->close_cb = NULL; - uv_handle_ares->data = uv_ares_data_ptr; - uv_handle_ares->sock = sock; - uv_handle_ares->h_wait = NULL; - uv_handle_ares->flags = 0; - - /* create an event to wait on socket signal */ - uv_handle_ares->h_event = WSACreateEvent(); - if (uv_handle_ares->h_event == WSA_INVALID_EVENT) { - uv_fatal_error(WSAGetLastError(), "WSACreateEvent"); - } - - /* tie event to socket */ - if (SOCKET_ERROR == WSAEventSelect(sock, uv_handle_ares->h_event, FD_READ | FD_WRITE | FD_CONNECT)) { - uv_fatal_error(WSAGetLastError(), "WSAEventSelect"); - } - - /* add handle to list */ - uv_add_ares_handle(uv_handle_ares); - uv_refs_++; - - /* - * we have a single polling timer for all ares sockets. - * This is preferred to using ares_timeout. See ares_timeout.c warning. - * if timer is not running start it, and keep socket count - */ - if (uv_ares_data_ptr->activesockets == 0) { - uv_timer_init(&uv_ares_data_ptr->pollingtimer); - uv_timer_start(&uv_ares_data_ptr->pollingtimer, uv_ares_poll, 1000L, 1000L); - } - uv_ares_data_ptr->activesockets++; - - /* specify thread pool function to call when event is signaled */ - if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait, - uv_handle_ares->h_event, - uv_ares_socksignal_tp, - (void*)uv_handle_ares, - INFINITE, - WT_EXECUTEINWAITTHREAD) == 0) { - uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); - } - } else { - /* found existing handle. */ - assert(uv_handle_ares->type == UV_ARES_TASK); - assert(uv_handle_ares->data != NULL); - assert(uv_handle_ares->h_event != WSA_INVALID_EVENT); - } - } -} - -/* called via uv_poll when ares completion port signaled */ -void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req) { - uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data; - - ares_process_fd(uv_ares_data_ptr->channel, - handle->read ? handle->sock : INVALID_SOCKET, - handle->write ? handle->sock : INVALID_SOCKET); - - /* release handle for select here */ - free(handle); -} - -/* called via uv_poll when ares is finished with socket */ -void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) { - /* check for event complete without waiting */ - unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); - - if (signaled != WAIT_TIMEOUT) { - uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data; - - uv_refs_--; - - /* close event handle and free uv handle memory */ - CloseHandle(handle->h_close_event); - free(handle); - - /* decrement active count. if it becomes 0 stop polling */ - if (uv_ares_data_ptr->activesockets > 0) { - uv_ares_data_ptr->activesockets--; - if (uv_ares_data_ptr->activesockets == 0) { - uv_close((uv_handle_t*)&uv_ares_data_ptr->pollingtimer, NULL); - } - } - } else { - /* stil busy - repost and try again */ - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - } -} - -/* periodically call ares to check for timeouts */ -void uv_ares_poll(uv_timer_t* handle, int status) { - if (uv_ares_data.channel != NULL && uv_ares_data.activesockets > 0) { - ares_process_fd(uv_ares_data.channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - } -} - - -/* set ares SOCK_STATE callback to our handler */ -int uv_ares_init_options(ares_channel *channelptr, - struct ares_options *options, - int optmask) { - int rc; - - /* only allow single init at a time */ - if (uv_ares_data.channel != NULL) { - return UV_EALREADY; - } - - /* set our callback as an option */ - options->sock_state_cb = uv_ares_sockstate_cb; - options->sock_state_cb_data = &uv_ares_data; - optmask |= ARES_OPT_SOCK_STATE_CB; - - /* We do the call to ares_init_option for caller. */ - rc = ares_init_options(channelptr, options, optmask); - - /* if success, save channel */ - if (rc == ARES_SUCCESS) { - uv_ares_data.channel = *channelptr; - } - - return rc; -} - - -/* release memory */ -void uv_ares_destroy(ares_channel channel) { - /* only allow destroy if did init */ - if (uv_ares_data.channel != NULL) { - ares_destroy(channel); - uv_ares_data.channel = NULL; - } -} - - -/* - * getaddrinfo error code mapping - * Falls back to uv_translate_sys_error if no match - */ - -static uv_err_code uv_translate_eai_error(int eai_errno) { - switch (eai_errno) { - case ERROR_SUCCESS: return UV_OK; - case EAI_BADFLAGS: return UV_EBADF; - case EAI_FAIL: return UV_EFAULT; - case EAI_FAMILY: return UV_EAIFAMNOSUPPORT; - case EAI_MEMORY: return UV_ENOMEM; - case EAI_NONAME: return UV_EAINONAME; - case EAI_AGAIN: return UV_EAGAIN; - case EAI_SERVICE: return UV_EAISERVICE; - case EAI_SOCKTYPE: return UV_EAISOCKTYPE; - default: return uv_translate_sys_error(eai_errno); - } -} - - -/* getaddrinfo worker thread implementation */ -static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { - uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*)parameter; - int ret; - - assert(handle != NULL); - - if (handle != NULL) { - /* call OS function on this thread */ - ret = GetAddrInfoW(handle->node, handle->service, handle->hints, &handle->res); - handle->retcode = ret; - - /* post getaddrinfo completed */ - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &handle->getadddrinfo_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - } - - return 0; -} - - -/* - * Called from uv_run when complete. Call user specified callback - * then free returned addrinfo - * Returned addrinfo strings are converted from UTF-16 to UTF-8. - * - * To minimize allocation we calculate total size required, - * and copy all structs and referenced strings into the one block. - * Each size calculation is adjusted to avoid unaligned pointers. - */ -static void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_t* req) { - int addrinfo_len = 0; - int name_len = 0; - size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); - struct addrinfoW* addrinfow_ptr; - struct addrinfo* addrinfo_ptr; - char* alloc_ptr = NULL; - char* cur_ptr = NULL; - uv_err_code uv_ret; - - /* release input parameter memory */ - if (handle->alloc != NULL) { - free(handle->alloc); - handle->alloc = NULL; - } - - uv_ret = uv_translate_eai_error(handle->retcode); - if (handle->retcode == 0) { - /* convert addrinfoW to addrinfo */ - /* first calculate required length */ - addrinfow_ptr = handle->res; - while (addrinfow_ptr != NULL) { - addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); - if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); - if (name_len == 0) { - uv_ret = uv_translate_sys_error(GetLastError()); - goto complete; - } - addrinfo_len += ALIGNED_SIZE(name_len); - } - addrinfow_ptr = addrinfow_ptr->ai_next; - } - - /* allocate memory for addrinfo results */ - alloc_ptr = (char*)malloc(addrinfo_len); - - /* do conversions */ - if (alloc_ptr != NULL) { - cur_ptr = alloc_ptr; - addrinfow_ptr = handle->res; - - while (addrinfow_ptr != NULL) { - /* copy addrinfo struct data */ - assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); - addrinfo_ptr = (struct addrinfo*)cur_ptr; - addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; - addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; - addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; - addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; - addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; - addrinfo_ptr->ai_canonname = NULL; - addrinfo_ptr->ai_addr = NULL; - addrinfo_ptr->ai_next = NULL; - - cur_ptr += addrinfo_struct_len; - - /* copy sockaddr */ - if (addrinfo_ptr->ai_addrlen > 0) { - assert(cur_ptr + addrinfo_ptr->ai_addrlen <= alloc_ptr + addrinfo_len); - memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); - addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; - cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); - } - - /* convert canonical name to UTF-8 */ - if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); - assert(name_len > 0); - assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, cur_ptr, name_len); - assert(name_len > 0); - addrinfo_ptr->ai_canonname = cur_ptr; - cur_ptr += ALIGNED_SIZE(name_len); - } - assert(cur_ptr <= alloc_ptr + addrinfo_len); - - /* set next ptr */ - addrinfow_ptr = addrinfow_ptr->ai_next; - if (addrinfow_ptr != NULL) { - addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; - } - } - } else { - uv_ret = UV_ENOMEM; - } - - } - - /* return memory to system */ - if (handle->res != NULL) { - FreeAddrInfoW(handle->res); - handle->res = NULL; - } - -complete: - /* finally do callback with converted result */ - handle->getaddrinfo_cb(handle, uv_ret, (struct addrinfo*)alloc_ptr); - - /* release copied result memory */ - if (alloc_ptr != NULL) { - free(alloc_ptr); - } - - uv_refs_--; -} - - -/* - * Entry point for getaddrinfo - * we convert the UTF-8 strings to UNICODE - * and save the UNICODE string pointers in the handle - * We also copy hints so that caller does not need to keep memory until the callback. - * return UV_OK if a callback will be made - * return error code if validation fails - * - * To minimize allocation we calculate total size required, - * and copy all structs and referenced strings into the one block. - * Each size calculation is adjusted to avoid unaligned pointers. - */ -int uv_getaddrinfo(uv_getaddrinfo_t* handle, - uv_getaddrinfo_cb getaddrinfo_cb, - const char* node, - const char* service, - const struct addrinfo* hints) { - int nodesize = 0; - int servicesize = 0; - int hintssize = 0; - char* alloc_ptr = NULL; - - if (handle == NULL || getaddrinfo_cb == NULL || - (node == NULL && service == NULL)) { - uv_set_sys_error(WSAEINVAL); - goto error; - } - - handle->getaddrinfo_cb = getaddrinfo_cb; - handle->res = NULL; - handle->type = UV_GETADDRINFO; - - /* calculate required memory size for all input values */ - if (node != NULL) { - nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t)); - if (nodesize == 0) { - uv_set_sys_error(GetLastError()); - goto error; - } - } - - if (service != NULL) { - servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * sizeof(wchar_t)); - if (servicesize == 0) { - uv_set_sys_error(GetLastError()); - goto error; - } - } - if (hints != NULL) { - hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); - } - - /* allocate memory for inputs, and partition it as needed */ - alloc_ptr = (char*)malloc(nodesize + servicesize + hintssize); - if (!alloc_ptr) { - uv_set_sys_error(WSAENOBUFS); - goto error; - } - - /* save alloc_ptr now so we can free if error */ - handle->alloc = (void*)alloc_ptr; - - /* convert node string to UTF16 into allocated memory and save pointer in handle */ - if (node != NULL) { - handle->node = (wchar_t*)alloc_ptr; - if (uv_utf8_to_utf16(node, (wchar_t*)alloc_ptr, nodesize / sizeof(wchar_t)) == 0) { - uv_set_sys_error(GetLastError()); - goto error; - } - alloc_ptr += nodesize; - } else { - handle->node = NULL; - } - - /* convert service string to UTF16 into allocated memory and save pointer in handle */ - if (service != NULL) { - handle->service = (wchar_t*)alloc_ptr; - if (uv_utf8_to_utf16(service, (wchar_t*)alloc_ptr, servicesize / sizeof(wchar_t)) == 0) { - uv_set_sys_error(GetLastError()); - goto error; - } - alloc_ptr += servicesize; - } else { - handle->service = NULL; - } - - /* copy hints to allocated memory and save pointer in handle */ - if (hints != NULL) { - handle->hints = (struct addrinfoW*)alloc_ptr; - handle->hints->ai_family = hints->ai_family; - handle->hints->ai_socktype = hints->ai_socktype; - handle->hints->ai_protocol = hints->ai_protocol; - handle->hints->ai_flags = hints->ai_flags; - handle->hints->ai_addrlen = 0; - handle->hints->ai_canonname = NULL; - handle->hints->ai_addr = NULL; - handle->hints->ai_next = NULL; - } else { - handle->hints = NULL; - } - - /* init request for Post handling */ - uv_req_init(&handle->getadddrinfo_req); - handle->getadddrinfo_req.data = handle; - handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ; - - /* Ask thread to run. Treat this as a long operation */ - if (QueueUserWorkItem(&getaddrinfo_thread_proc, handle, WT_EXECUTELONGFUNCTION) == 0) { - uv_set_sys_error(GetLastError()); - goto error; - } - - uv_refs_++; - - return 0; - -error: - if (handle != NULL && handle->alloc != NULL) { - free(handle->alloc); - } - return -1; -} - - -int uv_pipe_init(uv_pipe_t* handle) { - uv_stream_init((uv_stream_t*)handle); - - handle->type = UV_NAMED_PIPE; - handle->reqs_pending = 0; - handle->pending_accepts = NULL; - handle->name = NULL; - - uv_counters()->pipe_init++; - - return 0; -} - - -/* Creates a pipe server. */ -/* TODO: make this work with UTF8 name */ -int uv_pipe_bind(uv_pipe_t* handle, const char* name) { - int i; - uv_pipe_accept_t* req; - - if (!name) { - uv_set_sys_error(WSAEINVAL); - return -1; - } - - /* Make our own copy of the pipe name */ - handle->name = strdup(name); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { - req = &handle->accept_reqs[i]; - uv_req_init((uv_req_t*) req); - req->type = UV_ACCEPT; - req->data = handle; - req->pipeHandle = INVALID_HANDLE_VALUE; - req->next_pending = NULL; - } - - handle->flags |= UV_HANDLE_PIPESERVER; - return 0; -} - - -/* Starts listening for connections for the given pipe. */ -int uv_pipe_listen(uv_pipe_t* handle, uv_connection_cb cb) { - int i, errno; - - if (handle->flags & UV_HANDLE_LISTENING || - handle->flags & UV_HANDLE_READING) { - uv_set_sys_error(UV_EALREADY); - return -1; - } - - if (!(handle->flags & UV_HANDLE_PIPESERVER)) { - uv_set_sys_error(UV_ENOTSUP); - return -1; - } - - handle->flags |= UV_HANDLE_LISTENING; - handle->connection_cb = cb; - - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { - uv_pipe_queue_accept(handle, &handle->accept_reqs[i]); - } - - return 0; -} - - -static int uv_set_pipe_handle(uv_pipe_t* handle, HANDLE pipeHandle) { - DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; - - if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { - return -1; - } - - if (CreateIoCompletionPort(pipeHandle, - uv_iocp_, - (ULONG_PTR)handle, - 0) == NULL) { - return -1; - } - - return 0; -} - - -static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { - HANDLE pipeHandle = INVALID_HANDLE_VALUE; - int errno; - uv_pipe_t* handle; - uv_connect_t* req; - - req = (uv_connect_t*)parameter; - assert(req); - handle = (uv_pipe_t*)req->handle; - assert(handle); - - /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait for the pipe to become available with WaitNamedPipe. */ - while (WaitNamedPipe(handle->name, 30000)) { - /* The pipe is now available, try to connect. */ - pipeHandle = CreateFile(handle->name, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - NULL); - - if (pipeHandle != INVALID_HANDLE_VALUE) { - break; - } - } - - if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) { - handle->handle = pipeHandle; - req->error = uv_ok_; - } else { - req->error = uv_new_sys_error(GetLastError()); - } - - memset(&req->overlapped, 0, sizeof(req->overlapped)); - - /* Post completed */ - if (!PostQueuedCompletionStatus(uv_iocp_, - 0, - 0, - &req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } - - return 0; -} - - -/* TODO: make this work with UTF8 name */ -int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, - const char* name, uv_connect_cb cb) { - int errno; - HANDLE pipeHandle; - - handle->handle = INVALID_HANDLE_VALUE; - - uv_req_init((uv_req_t*) req); - req->type = UV_CONNECT; - req->handle = (uv_stream_t*) handle; - req->cb = cb; - - pipeHandle = CreateFile(name, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - NULL); - - if (pipeHandle == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_PIPE_BUSY) { - /* Wait for the server to make a pipe instance available. */ - handle->name = strdup(name); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - - if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { - errno = GetLastError(); - goto error; - } - - return 0; - } - - errno = GetLastError(); - goto error; - } - - if (uv_set_pipe_handle((uv_pipe_t*)req->handle, pipeHandle)) { - errno = GetLastError(); - goto error; - } - - handle->handle = pipeHandle; - - req->error = uv_ok_; - uv_insert_pending_req((uv_req_t*) req); - handle->reqs_pending++; - return 0; - -error: - if (pipeHandle != INVALID_HANDLE_VALUE) { - CloseHandle(pipeHandle); - } - uv_set_sys_error(errno); - return -1; -} - - -/* Cleans up uv_pipe_t (server or connection) and all resources associated with it */ -static void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { - int i; - HANDLE pipeHandle; - - if (handle->name) { - free(handle->name); - handle->name; - } - - if (handle->flags & UV_HANDLE_PIPESERVER) { - for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { - pipeHandle = handle->accept_reqs[i].pipeHandle; - if (pipeHandle != INVALID_HANDLE_VALUE) { - CloseHandle(pipeHandle); - } - } - - } else if (handle->handle != INVALID_HANDLE_VALUE) { - CloseHandle(handle->handle); - } - - handle->flags |= UV_HANDLE_SHUT; -} diff --git a/deps/uv/test/test-bind-error.c b/deps/uv/test/test-bind-error.c index 4ac60654f6..f3db848a75 100644 --- a/deps/uv/test/test-bind-error.c +++ b/deps/uv/test/test-bind-error.c @@ -188,3 +188,15 @@ TEST_IMPL(bind_localhost_ok) { return 0; } + + +TEST_IMPL(listen_without_bind) { + int r; + uv_tcp_t server; + + uv_init(); + r = uv_tcp_init(&server); + ASSERT(r == 0); + r = uv_tcp_listen(&server, 128, NULL); + ASSERT(r == 0); +} diff --git a/deps/uv/test/test-getsockname.c b/deps/uv/test/test-getsockname.c index f533806c3b..eeae468672 100644 --- a/deps/uv/test/test-getsockname.c +++ b/deps/uv/test/test-getsockname.c @@ -151,6 +151,15 @@ static int tcp_listener(int port) { fprintf(stderr, "uv_getsockname error (listening) %d\n", uv_last_error().code); } ASSERT(r == 0); + + char ip[20]; + r = uv_ip4_name((struct sockaddr_in*)&sockname, ip, 20); + ASSERT(r == 0); + ASSERT(ip[0] == '0'); + ASSERT(ip[1] == '.'); + ASSERT(ip[2] == '0'); + printf("sockname = %s\n", ip); + getsocknamecount++; return 0; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 919d7b760d..2a7e5676ed 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -30,6 +30,7 @@ TEST_DECLARE (bind_error_addrnotavail_2) TEST_DECLARE (bind_error_fault) TEST_DECLARE (bind_error_inval) TEST_DECLARE (bind_localhost_ok) +TEST_DECLARE (listen_without_bind) TEST_DECLARE (bind6_error_addrinuse) TEST_DECLARE (bind6_error_addrnotavail) TEST_DECLARE (bind6_error_fault) @@ -82,6 +83,7 @@ TASK_LIST_START TEST_ENTRY (bind_error_fault) TEST_ENTRY (bind_error_inval) TEST_ENTRY (bind_localhost_ok) + TEST_ENTRY (listen_without_bind) TEST_ENTRY (bind6_error_addrinuse) TEST_ENTRY (bind6_error_addrnotavail) diff --git a/lib/net_uv.js b/lib/net_uv.js index d9e0f1b2c5..c273020de0 100644 --- a/lib/net_uv.js +++ b/lib/net_uv.js @@ -514,6 +514,7 @@ function listenip(self, ip, port, addressType) { r = self._handle.bind(ip, port); } } + if (r) { self._handle.close(); self._handle = null;