Merge pull request #16419 from yashykt/tcpusertimeout

Set TCP_USER_TIMEOUT socket option for linux
pull/16625/head
Yash Tibrewal 6 years ago committed by GitHub
commit edfec1b131
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      src/core/lib/iomgr/port.h
  2. 90
      src/core/lib/iomgr/socket_utils_common_posix.cc
  3. 7
      src/core/lib/iomgr/socket_utils_posix.h
  4. 3
      src/core/lib/iomgr/tcp_client_posix.cc
  5. 3
      src/core/lib/iomgr/tcp_server_utils_posix_common.cc

@ -82,6 +82,11 @@
#define GRPC_LINUX_SOCKETUTILS 1
#endif
#endif
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
#define GRPC_HAVE_TCP_USER_TIMEOUT
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */
#endif /* LINUX_VERSION_CODE */
#ifndef __GLIBC__
#define GRPC_LINUX_EPOLL 1
#define GRPC_LINUX_EPOLL_CREATE1 1

@ -41,6 +41,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/sockaddr.h"
@ -222,6 +223,95 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
return GRPC_ERROR_NONE;
}
/* The default values for TCP_USER_TIMEOUT are currently configured to be in
* line with the default values of KEEPALIVE_TIMEOUT as proposed in
* https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */
#define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
#define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
static int g_default_client_tcp_user_timeout_ms =
DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
static int g_default_server_tcp_user_timeout_ms =
DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
static bool g_default_client_tcp_user_timeout_enabled = false;
static bool g_default_server_tcp_user_timeout_enabled = true;
void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
if (is_client) {
g_default_client_tcp_user_timeout_enabled = enable;
if (timeout > 0) {
g_default_client_tcp_user_timeout_ms = timeout;
}
} else {
g_default_server_tcp_user_timeout_enabled = enable;
if (timeout > 0) {
g_default_server_tcp_user_timeout_ms = timeout;
}
}
}
/* Set TCP_USER_TIMEOUT */
grpc_error* grpc_set_socket_tcp_user_timeout(
int fd, const grpc_channel_args* channel_args, bool is_client) {
#ifdef GRPC_HAVE_TCP_USER_TIMEOUT
bool enable;
int timeout;
if (is_client) {
enable = g_default_client_tcp_user_timeout_enabled;
timeout = g_default_client_tcp_user_timeout_ms;
} else {
enable = g_default_server_tcp_user_timeout_enabled;
timeout = g_default_server_tcp_user_timeout_ms;
}
if (channel_args) {
for (unsigned int i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
/* Continue using default if value is 0 */
if (value == 0) {
continue;
}
/* Disable if value is INT_MAX */
enable = value != INT_MAX;
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
/* Continue using default if value is 0 */
if (value == 0) {
continue;
}
timeout = value;
}
}
}
if (enable) {
extern grpc_core::TraceFlag grpc_tcp_trace;
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
timeout);
}
int newval;
socklen_t len = sizeof(newval);
if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
sizeof(timeout))) {
return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)");
}
if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)");
}
if (newval != timeout) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Failed to set TCP_USER_TIMEOUT");
}
}
#else
gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
#endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
return GRPC_ERROR_NONE;
}
/* set a socket using a grpc_socket_mutator */
grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
GPR_ASSERT(mutator);

@ -53,6 +53,13 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
/* set SO_REUSEPORT */
grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
/* Configure the default values for TCP_USER_TIMEOUT */
void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
/* Set TCP_USER_TIMEOUT */
grpc_error* grpc_set_socket_tcp_user_timeout(
int fd, const grpc_channel_args* channel_args, bool is_client);
/* Returns true if this system can create AF_INET6 sockets bound to ::1.
The value is probed once, and cached for the life of the process.

@ -76,6 +76,9 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
true /* is_client */);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;

@ -166,6 +166,9 @@ grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd,
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_reuse_addr(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_tcp_user_timeout(fd, s->channel_args,
false /* is_client */);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;

Loading…
Cancel
Save