diff --git a/include/uv.h b/include/uv.h index de375d4b0e..5f943798d9 100644 --- a/include/uv.h +++ b/include/uv.h @@ -653,11 +653,16 @@ UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); /* * Enable/disable TCP keep-alive. * - * `delay` is the initial delay in seconds, ignored when `enable` is zero. + * Options below are ignored when `enable` is zero. + * `delay` is the initial delay in seconds. If 0, value is ignored. + * `interval` is the interval in seconds after initial probe. If 0, value is ignored. + * `count` is the number of failed probes before flagging socket dead. If 0, value is ignored. Unix-only. */ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable, - unsigned int delay); + unsigned int delay, + unsigned int interval, + unsigned int count); /* * This setting applies to Windows only. diff --git a/src/unix/internal.h b/src/unix/internal.h index 7d08c1dac9..ad80f6aaaa 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -152,7 +152,7 @@ int uv__accept(int sockfd); /* tcp */ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); int uv__tcp_nodelay(int fd, int on); -int uv__tcp_keepalive(int fd, int on, unsigned int delay); +int uv__tcp_keepalive(int fd, int on, unsigned int delay, unsigned int interval, unsigned int count); /* pipe */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); diff --git a/src/unix/stream.c b/src/unix/stream.c index 080535e5f1..86aba7e345 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -363,8 +363,8 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) return uv__set_sys_error(stream->loop, errno); - /* TODO Use delay the user passed in. */ - if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + /* TODO Use delay, interval, count the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60, 0, 0)) return uv__set_sys_error(stream->loop, errno); } diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a51576ba1b..58ec7be9b1 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -290,12 +290,13 @@ int uv__tcp_nodelay(int fd, int on) { } -int uv__tcp_keepalive(int fd, int on, unsigned int delay) { +int uv__tcp_keepalive(int fd, int on, unsigned int delay, + unsigned int interval, unsigned int count) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) return -1; #ifdef TCP_KEEPIDLE - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + if (on && delay && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) return -1; #endif @@ -303,7 +304,17 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { * then don't advertise it in your system headers... */ #if defined(TCP_KEEPALIVE) && !defined(__sun) - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + if (on && delay && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return -1; +#endif + +#ifdef TCP_KEEPINTVL + if (on && interval && setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval))) + return -1; +#endif + +#ifdef TCP_KEEPCNT + if (on && count && setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof (count))) return -1; #endif @@ -325,9 +336,10 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) { } -int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay, + unsigned int interval, unsigned int count) { if (uv__stream_fd(handle) != -1) - if (uv__tcp_keepalive(uv__stream_fd(handle), on, delay)) + if (uv__tcp_keepalive(uv__stream_fd(handle), on, delay, interval, count)) return -1; if (on) @@ -337,6 +349,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge * uv_tcp_t with an int that's almost never used... + * same with interval and count */ return 0; diff --git a/src/win/tcp.c b/src/win/tcp.c index 7158216131..1f3456e357 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -26,6 +26,7 @@ #include "handle-inl.h" #include "stream-inl.h" #include "req-inl.h" +#include "mstcpip.h" /* @@ -57,7 +58,8 @@ static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { } -static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { +static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay, + unsigned int interval, unsigned int count) { if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, @@ -67,14 +69,41 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign return -1; } - if (enable && setsockopt(socket, - IPPROTO_TCP, - TCP_KEEPALIVE, - (const char*)&delay, - sizeof delay) == -1) { +#ifdef TCP_KEEPALIVE + if (enable && delay && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { uv__set_sys_error(handle->loop, errno); return -1; } +#endif + +#ifdef SIO_KEEPALIVE_VALS + if (enable && (delay || interval)) { + struct tcp_keepalive vals; + DWORD outlen = 0; + vals.onoff = 1; + if (!delay) delay = 60 * 60 * 2; /* default is 2 hours */ + if (!interval) interval = 1; /* default is 1 second */ + vals.keepalivetime = delay * 1000; + vals.keepaliveinterval = interval * 1000; + if (WSAIoctl(socket, + SIO_KEEPALIVE_VALS, + &vals, + sizeof(vals), + NULL, + 0, + &outlen, + NULL, + NULL) != 0) { + return -1; + } + } +#endif + + /* count cannot be applied without registry changes and system reboot */ return 0; } @@ -129,9 +158,9 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, return -1; } - /* TODO: Use stored delay. */ + /* TODO: Use stored delay, interval, count. */ if ((handle->flags & UV_HANDLE_TCP_KEEPALIVE) && - uv__tcp_keepalive(handle, socket, 1, 60)) { + uv__tcp_keepalive(handle, socket, 1, 60, 0, 0)) { return -1; } @@ -1194,9 +1223,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { } -int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { +int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay, unsigned int interval, unsigned int count) { if (handle->socket != INVALID_SOCKET && - uv__tcp_keepalive(handle, handle->socket, enable, delay)) { + uv__tcp_keepalive(handle, handle->socket, enable, delay, interval, count)) { return -1; } diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c index 68afb39f45..eeff9cc006 100644 --- a/test/test-tcp-flags.c +++ b/test/test-tcp-flags.c @@ -39,7 +39,7 @@ TEST_IMPL(tcp_flags) { r = uv_tcp_nodelay(&handle, 1); ASSERT(r == 0); - r = uv_tcp_keepalive(&handle, 1, 60); + r = uv_tcp_keepalive(&handle, 1, 60, 60, 8); ASSERT(r == 0); uv_close((uv_handle_t*)&handle, NULL);