From f44a4d0a5f24862388b778fb037408a17db3ff42 Mon Sep 17 00:00:00 2001 From: theanarkh <2923878201@qq.com> Date: Fri, 25 Dec 2020 01:03:52 +0800 Subject: [PATCH 1/3] net:support TCP_KEEPINTVL,TCP_KEEPCNT,TCP_USER_TIMEOUT for tcp keep-alive except TCP_KEEPIDLE, linux provide TCP_KEEPINTVL,TCP_KEEPCNT,TCP_USER_TIMEOUT for tcp keep-alive. support this then users have more control over tcp keep-alive. add two new api uv_tcp_keepalive_ex and uv_tcp_timeout for user to control tcp keepalive --- include/uv.h | 6 ++++ src/unix/internal.h | 6 ++++ src/unix/tcp.c | 84 +++++++++++++++++++++++++++++++++++++++++++ src/win/tcp.c | 77 +++++++++++++++++++++++++++++++++++++-- test/test-tcp-flags.c | 6 ++++ 5 files changed, 177 insertions(+), 2 deletions(-) diff --git a/include/uv.h b/include/uv.h index b7d9381cf..56874584d 100644 --- a/include/uv.h +++ b/include/uv.h @@ -613,6 +613,12 @@ UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay); +UV_EXTERN int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int enable, + unsigned int delay, + unsigned int interval, + unsigned int cou nt); +UV_EXTERN int uv_tcp_timeout(uv_tcp_t* handle, unsigned int timeout); UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); enum uv_tcp_flags { diff --git a/src/unix/internal.h b/src/unix/internal.h index 99c6d5e13..0c85cc0a8 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -229,6 +229,12 @@ int uv__open_cloexec(const char* path, int flags); 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_ex(int fd, + int on, + unsigned int delay, + unsigned int interval, + unsigned int count); +int uv_tcp_timeout(uv_tcp_t* handle, unsigned int timeout); /* pipe */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 18acd20df..030d62347 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -446,6 +446,90 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { return 0; } +int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int on, + unsigned int delay, + unsigned int interval, + unsigned int count) { + int err; + + if (uv__stream_fd(handle) != -1) { + err =uv__tcp_keepalive_ex(uv__stream_fd(handle), + on, + delay, + interval, + count); + if (err) + return err; + } + /* + follow the uv_tcp_keepalive api + TO DO: save params on handle and set when handle is attached to a fd + */ + if (on) + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + else + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + return 0; +} + +int uv_tcp_timeout(uv_tcp_t* handle, unsigned int timeout) { + #ifdef TCP_USER_TIMEOUT + int fd = uv__stream_fd(handle); + if (fd != -1 && setsockopt(fd, + IPPROTO_TCP, + TCP_USER_TIMEOUT, + &timeout, + sizeof(timeout))) { + return UV__ERR(errno); + } + #endif + return 0; +} + +int uv__tcp_keepalive_ex(int fd, + int on, + unsigned int delay, + unsigned int interval, + unsigned int count) { + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) + return UV__ERR(errno); + +#ifdef TCP_KEEPIDLE + if (on && delay &&setsockopt(fd, + IPPROTO_TCP, + TCP_KEEPIDLE, + &delay, + sizeof(delay))) + return UV__ERR(errno); +#endif +#ifdef TCP_KEEPINTVL + if (on && interval && setsockopt(fd, + IPPROTO_TCP, + TCP_KEEPINTVL, + &interval, + sizeof(interval))) + return UV__ERR(errno); +#endif +#ifdef TCP_KEEPCNT + if (on && count && setsockopt(fd, + IPPROTO_TCP, + TCP_KEEPCNT, + &count, + sizeof(count))) + return UV__ERR(errno); +#endif + /* Solaris/SmartOS, if you don't support keep-alive, + * then don't advertise it in your system headers... + */ + /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ +#if defined(TCP_KEEPALIVE) && !defined(__sun) + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return UV__ERR(errno); +#endif + + return 0; +} int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (enable) diff --git a/src/win/tcp.c b/src/win/tcp.c index 9926184d6..71beda317 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1267,7 +1267,6 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { return 0; } - int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { int err; @@ -1283,11 +1282,85 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; } - /* TODO: Store delay if handle->socket isn't created yet. */ + return 0; +} + +int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int enable, + unsigned int delay, + unsigned int interval, + unsigned int count) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_keepalive_ex(handle, + handle->socket, + enable, + delay, + interval, + count); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + } else { + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + } return 0; } +static int uv__tcp_keepalive_ex(uv_tcp_t* handle, + SOCKET socket, + int enable, + unsigned int delay, + unsigned int interval, + unsigned int count) { + if (setsockopt(socket, + SOL_SOCKET, + SO_KEEPALIVE, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + + #ifdef TCP_KEEPIDLE + if (enable && delay && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPIDLE, + (const char*)&delay, + sizeof delay) == -1) { + return WSAGetLastError(); + } +#endif +#ifdef TCP_KEEPINTVL + if (enable && interval && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPINTVL, + (const char*)&interval, + sizeof interval) == -1) { + return WSAGetLastError(); + } +#endif +#ifdef TCP_KEEPCNT + if (enable && count && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPCNT, + (const char*)&count, + sizeof count) == -1) { + return WSAGetLastError(); + } +#endif + + return 0; +} + +/* windows don't support this */ +int uv_tcp_timeout(uv_tcp_t* handle, unsigned int timeout) { + return 0; +} int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (handle->flags & UV_HANDLE_CONNECTION) { diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c index 68afb39f4..83bbd7ae3 100644 --- a/test/test-tcp-flags.c +++ b/test/test-tcp-flags.c @@ -42,6 +42,12 @@ TEST_IMPL(tcp_flags) { r = uv_tcp_keepalive(&handle, 1, 60); ASSERT(r == 0); + r = uv_tcp_keepalive_ex(&handle, 1, 60, 60, 60); + ASSERT(r == 0); + + r = uv_tcp_timeout(&handle, 1000); + ASSERT(r == 0); + uv_close((uv_handle_t*)&handle, NULL); r = uv_run(loop, UV_RUN_DEFAULT); From 5873ad226da36452fbb9458ecc04dd3fcdc73477 Mon Sep 17 00:00:00 2001 From: theanarkh <2923878201@qq.com> Date: Fri, 25 Dec 2020 02:12:34 +0800 Subject: [PATCH 2/3] Update uv.h net:support TCP_KEEPINTVL,TCP_KEEPCNT,TCP_USER_TIMEOUT for tcp keep-alive except TCP_KEEPIDLE, linux provide TCP_KEEPINTVL,TCP_KEEPCNT,TCP_USER_TIMEOUT for tcp keep-alive. support this then users have more control over tcp keep-alive. add two new api uv_tcp_keepalive_ex and uv_tcp_timeout for user to control tcp keepalive --- include/uv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 56874584d..a689918a6 100644 --- a/include/uv.h +++ b/include/uv.h @@ -617,7 +617,7 @@ UV_EXTERN int uv_tcp_keepalive_ex(uv_tcp_t* handle, int enable, unsigned int delay, unsigned int interval, - unsigned int cou nt); + unsigned int count); UV_EXTERN int uv_tcp_timeout(uv_tcp_t* handle, unsigned int timeout); UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); From 0c19b0a52eeb72219994e76c710ea28205d882a2 Mon Sep 17 00:00:00 2001 From: theanarkh <2923878201@qq.com> Date: Fri, 25 Dec 2020 03:28:07 +0800 Subject: [PATCH 3/3] Update tcp.c --- src/win/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index 71beda317..759a3978c 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1281,7 +1281,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } else { handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; } - + /* TODO: Store delay if handle->socket isn't created yet. */ return 0; }