From 7887e68ff752260d061d8cdc68dfcece2f6a150d Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Wed, 20 Jun 2012 03:32:55 +0200 Subject: [PATCH] uv: upgrade to 6e8eb332 --- deps/uv/src/win/tcp.c | 90 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 646ae2cdde..e13c0f3dfe 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -28,7 +28,6 @@ #include "req-inl.h" - /* * Threshold of active tcp streams for which to preallocate tcp read buffers. * (Due to node slab allocator performing poorly under this pattern, @@ -1292,31 +1291,88 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { +static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { + SOCKET socket = tcp->socket; int non_ifs_lsp; + + /* Check if we have any non-IFS LSPs stacked on top of TCP */ + non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : + uv_tcp_non_ifs_lsp_ipv4; + + /* If there are non-ifs LSPs then try to obtain a base handle for the */ + /* socket. This will always fail on Windows XP/3k. */ + if (non_ifs_lsp) { + DWORD bytes; + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &socket, + sizeof socket, + &bytes, + NULL, + NULL) != 0) { + /* Failed. We can't do CancelIo. */ + return -1; + } + } + + assert(socket != 0 && socket != INVALID_SOCKET); + + if (!CancelIo((HANDLE) socket)) { + return -1; + } + + /* It worked. */ + return 0; +} + + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int close_socket = 1; - /* - * In order for winsock to do a graceful close there must not be - * any pending reads. - */ if (tcp->flags & UV_HANDLE_READ_PENDING) { - /* Just do shutdown on non-shared sockets, which ensures graceful close. */ + /* In order for winsock to do a graceful close there must not be any */ + /* any pending reads, or the socket must be shut down for writing */ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { + /* Just do shutdown on non-shared sockets, which ensures graceful close. */ shutdown(tcp->socket, SD_SEND); tcp->flags |= UV_HANDLE_SHUT; + + } else if (uv_tcp_try_cancel_io(tcp) == 0) { + /* In case of a shared socket, we try to cancel all outstanding I/O, */ + /* If that works, don't close the socket yet - wait for the read req to */ + /* return and close the socket in uv_tcp_endgame. */ + close_socket = 0; + } else { - /* Check if we have any non-IFS LSPs stacked on top of TCP */ - non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : - uv_tcp_non_ifs_lsp_ipv4; + /* When cancelling isn't possible - which could happen when an LSP is */ + /* present on an old Windows version, we will have to close the socket */ + /* with a read pending. That is not nice because trailing sent bytes */ + /* may not make it to the other side. */ + } - if (!non_ifs_lsp) { - /* - * Shared socket with no non-IFS LSPs, request to cancel pending I/O. - * The socket will be closed inside endgame. - */ - CancelIo((HANDLE)tcp->socket); - close_socket = 0; + } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + tcp->accept_reqs != NULL) { + /* Under normal circumstances closesocket() will ensure that all pending */ + /* accept reqs are canceled. However, when the socket is shared the */ + /* presence of another reference to the socket in another process will */ + /* keep the accept reqs going, so we have to ensure that these are */ + /* canceled. */ + if (uv_tcp_try_cancel_io(tcp) != 0) { + /* When cancellation is not possible, there is another option: we can */ + /* close the incoming sockets, which will also cancel the accept */ + /* operations. However this is not cool because we might inadvertedly */ + /* close a socket that just accepted a new connection, which will */ + /* cause the connection to be aborted. */ + unsigned int i; + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + uv_tcp_accept_t* req = &tcp->accept_reqs[i]; + if (req->accept_socket != INVALID_SOCKET && + !HasOverlappedIoCompleted(&req->overlapped)) { + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + } } } }