From d15b88a9355fbd43c85cf15f97912066c90bbfeb Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Tue, 25 Oct 2011 15:53:19 -0700 Subject: [PATCH] windows: implement uv_tcp_nodelay and uv_tcp_keepalive --- src/win/internal.h | 2 + src/win/pipe.c | 4 +- src/win/tcp.c | 114 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index ec6e3b2b..8be4fb86 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -69,6 +69,8 @@ void uv_process_timers(uv_loop_t* loop); #define UV_HANDLE_TTY_SAVED_POSITION 0x0400000 #define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x0800000 #define UV_HANDLE_SHARED_TCP_SERVER 0x1000000 +#define UV_HANDLE_TCP_NODELAY 0x2000000 +#define UV_HANDLE_TCP_KEEPALIVE 0x4000000 void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv_process_endgames(uv_loop_t* loop); diff --git a/src/win/pipe.c b/src/win/pipe.c index eb7fd33c..61281f00 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -956,7 +956,9 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, return -1; } - if (send_handle && send_handle->type != UV_TCP) { + /* Only TCP server handles are supported for sharing. */ + if (send_handle && (send_handle->type != UV_TCP || + send_handle->flags & UV_HANDLE_CONNECTION)) { uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 08869fa0..38da2a77 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -46,6 +46,42 @@ static char uv_zero_[] = ""; static unsigned int active_tcp_streams = 0; +static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_NODELAY, + (const char*)&enable, + sizeof enable) == -1) { + uv__set_sys_error(handle->loop, errno); + return -1; + } + return 0; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { + if (setsockopt(socket, + SOL_SOCKET, + SO_KEEPALIVE, + (const char*)&enable, + sizeof enable) == -1) { + uv__set_sys_error(handle->loop, errno); + return -1; + } + + if (enable && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { + uv__set_sys_error(handle->loop, errno); + return -1; + } + + return 0; +} + + static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, SOCKET socket, int imported) { DWORD yes = 1; @@ -89,6 +125,17 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, } } + if ((handle->flags & UV_HANDLE_TCP_NODELAY) && + uv__tcp_nodelay(handle, socket, 1)) { + return -1; + } + + /* TODO: Use stored delay. */ + if ((handle->flags & UV_HANDLE_TCP_KEEPALIVE) && + uv__tcp_keepalive(handle, socket, 1, 60)) { + return -1; + } + handle->socket = socket; return 0; @@ -961,38 +1008,61 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) { int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { - uv__set_artificial_error(handle->loop, UV_ENOSYS); - return -1; + if (handle->socket != INVALID_SOCKET && + uv__tcp_nodelay(handle, handle->socket, enable)) { + return -1; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_NODELAY; + } else { + handle->flags &= ~UV_HANDLE_TCP_NODELAY; + } + + return 0; } int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { - uv__set_artificial_error(handle->loop, UV_ENOSYS); - return -1; + if (handle->socket != INVALID_SOCKET && + uv__tcp_keepalive(handle, handle->socket, enable, delay)) { + return -1; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + } else { + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + } + + /* TODO: Store delay if handle->socket isn't created yet. */ + + return 0; } + int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* - * We're about to share the socket with another process. Because - * this is a server socket, we assume that the other process will - * be accepting conections on this socket. So, before sharing the - * socket with another process, we call listen here in the parent - * process. This needs to be modified if the socket is shared with - * another process for anything other than accepting connections. - */ + assert(!(handle->flags & UV_HANDLE_CONNECTION)); - if (!(handle->flags & UV_HANDLE_LISTENING)) { - if (!(handle->flags & UV_HANDLE_BOUND)) { - uv__set_artificial_error(handle->loop, UV_EINVAL); - return -1; - } - if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { - uv__set_sys_error(handle->loop, WSAGetLastError()); - return -1; - } + /* + * We're about to share the socket with another process. Because + * this is a listening socket, we assume that the other process will + * be accepting conections on it. So, before sharing the socket + * with another process, we call listen here in the parent process. + * This needs to be modified if the socket is shared with + * another process for anything other than accepting connections. + */ + + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + uv__set_sys_error(handle->loop, WSAGetLastError()); + return -1; } handle->flags |= UV_HANDLE_SHARED_TCP_SERVER;