From 40c60cfc54fe894d058ce712541c727115104ffe Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sat, 26 Jan 2013 04:11:28 +0100 Subject: [PATCH] win/tcp: make uv_tcp_set_socket set UV_HANDLE_IPV6 This makes uv_tcp_set_socket responsible for setting the UV_HANDLE_IPV6 flag. This fixes a couple of situations where the the fact that a socket is an IPv6 socket is not taken into account when deciding whether a call to SetFileCompletionNotificationModes is appropriate. It also fixes the issue that uv_tcp_open would never set this flag at all. --- src/win/tcp.c | 79 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index ff7b27b8..c16bbe4e 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -81,7 +81,7 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, - SOCKET socket, int imported) { + SOCKET socket, int family, int imported) { DWORD yes = 1; int non_ifs_lsp; @@ -107,8 +107,11 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, } } - non_ifs_lsp = (handle->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : - uv_tcp_non_ifs_lsp_ipv4; + if (family == AF_INET6) { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6; + } else { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; + } if (pSetFileCompletionNotificationModes && !non_ifs_lsp) { if (pSetFileCompletionNotificationModes((HANDLE) socket, @@ -134,6 +137,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, handle->socket = socket; + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + return 0; } @@ -230,14 +239,14 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { static int uv__bind(uv_tcp_t* handle, - int domain, + int family, struct sockaddr* addr, int addrsize) { DWORD err; int r; if (handle->socket == INVALID_SOCKET) { - SOCKET sock = socket(domain, SOCK_STREAM, 0); + SOCKET sock = socket(family, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; @@ -250,7 +259,7 @@ static int uv__bind(uv_tcp_t* handle, return -1; } - if (uv_tcp_set_socket(handle->loop, handle, sock, 0) == -1) { + if (uv_tcp_set_socket(handle->loop, handle, sock, family, 0) < 0) { closesocket(sock); return -1; } @@ -285,17 +294,10 @@ int uv__tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) { int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { - if (uv_allow_ipv6) { - handle->flags |= UV_HANDLE_IPV6; - return uv__bind(handle, - AF_INET6, - (struct sockaddr*)&addr, - sizeof(struct sockaddr_in6)); - - } else { - uv__set_sys_error(handle->loop, WSAEAFNOSUPPORT); - return -1; - } + return uv__bind(handle, + AF_INET6, + (struct sockaddr*)&addr, + sizeof(struct sockaddr_in6)); } @@ -584,6 +586,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { uv_loop_t* loop = server->loop; int rv = 0; + int family; uv_tcp_accept_t* req = server->pending_accepts; @@ -598,7 +601,17 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { return -1; } - if (uv_tcp_set_socket(client->loop, client, req->accept_socket, 0) == -1) { + if (server->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + if (uv_tcp_set_socket(client->loop, + client, + req->accept_socket, + family, + 0) < 0) { closesocket(req->accept_socket); rv = -1; } else { @@ -1148,7 +1161,11 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, return -1; } - if (uv_tcp_set_socket(tcp->loop, tcp, socket, 1) != 0) { + if (uv_tcp_set_socket(tcp->loop, + tcp, + socket, + socket_protocol_info->iAddressFamily, + 1) < 0) { closesocket(socket); return -1; } @@ -1161,10 +1178,6 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, tcp->flags |= UV_HANDLE_BOUND; tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; - if (socket_protocol_info->iAddressFamily == AF_INET6) { - tcp->flags |= UV_HANDLE_IPV6; - } - tcp->loop->active_tcp_streams++; return 0; } @@ -1381,13 +1394,31 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + uv__set_sys_error(handle->loop, GetLastError()); + return -1; + } + /* Make the socket non-inheritable */ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { uv__set_sys_error(handle->loop, GetLastError()); return -1; } - if (uv_tcp_set_socket(handle->loop, handle, sock, 0) == -1) { + if (uv_tcp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily, + 1) < 0) { return -1; }