From 21aff3b4c430e73da8364ddfcec87746689988b4 Mon Sep 17 00:00:00 2001 From: Manuel BACHMANN Date: Tue, 4 Feb 2020 10:59:38 +0100 Subject: [PATCH] unix: make uv_tcp_keepalive predictable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current UNIX systems define various defaults for TCP_KEEPINTVL and TCP_KEEPCNT, which makes the time between TCP_KEEPIDLE delay is reached and timeout effectively occurs unpredictable (Linux: /proc/sys /net/ipv4/tcp_keepalive_intvl;tcp_keepalive_probes). Do the following: set TCP_KEEPINTVL to 1 second (same as Win32 default) and TCP_KEEPCNT to 10 times (same as Win32 hardcoded value). Fixes: https://github.com/libuv/libuv/issues/2664 PR-URL: https://github.com/libuv/libuv/pull/2669 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- docs/src/tcp.rst | 5 +++++ src/unix/tcp.c | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index bcb163ea..3cc8efaa 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -60,6 +60,11 @@ API Enable / disable TCP keep-alive. `delay` is the initial delay in seconds, ignored when `enable` is zero. + After `delay` has been reached, 10 successive probes, each spaced 1 second + from the previous one, will still happen. If the connection is still lost + at the end of this procedure, then the handle is destroyed with a + ``UV_ETIMEDOUT`` error passed to the corresponding callback. + .. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) Enable / disable simultaneous asynchronous accept requests that are diff --git a/src/unix/tcp.c b/src/unix/tcp.c index fa660f13..d47e9433 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -379,8 +379,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { return UV__ERR(errno); #ifdef TCP_KEEPIDLE - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return UV__ERR(errno); + if (on) { + int intvl = 1; /* 1 second; same as default on Win32 */ + int cnt = 10; /* 10 retries; same as hardcoded on Win32 */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return UV__ERR(errno); + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) + return UV__ERR(errno); + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) + return UV__ERR(errno); + } #endif /* Solaris/SmartOS, if you don't support keep-alive,