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
This commit is contained in:
theanarkh 2020-12-25 01:03:52 +08:00
parent dec0723864
commit f44a4d0a5f
5 changed files with 177 additions and 2 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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)

View File

@ -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) {

View File

@ -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);