From b4cda9dd42f26ec4e431254bffc88a4e9026b868 Mon Sep 17 00:00:00 2001 From: lixingcong Date: Sat, 31 Aug 2019 10:45:52 +0800 Subject: [PATCH] Add option '--long-idle' for server Restore the default behavior handling timeout, make an option to enable long idle connections. Previously discussion: https://github.com/shadowsocks/shadowsocks-libev/pull/2421 https://github.com/shadowsocks/shadowsocks-libev/issues/2427 --- README.md | 2 ++ completions/bash/ss-server | 2 +- completions/zsh/_ss-server | 1 + doc/ss-server.asciidoc | 4 ++++ src/common.h | 1 + src/server.c | 23 +++++++++++++++++++---- src/utils.c | 4 ++++ 7 files changed, 32 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b33df9a0..df1a9bbc 100644 --- a/README.md +++ b/README.md @@ -446,6 +446,8 @@ you may refer to the man pages of the applications, respectively. [--no-delay] Enable TCP_NODELAY. + [--long-idle] Enable TCP long idle connections. + [--executable ] Path to the executable of ss-server. (only available in manager mode) diff --git a/completions/bash/ss-server b/completions/bash/ss-server index cec983ce..5643935a 100644 --- a/completions/bash/ss-server +++ b/completions/bash/ss-server @@ -1,7 +1,7 @@ _ss_server() { local cur prev opts ciphers - opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -6 -d -v -h --reuse-port --fast-open --acl --manager-address --mtu --mptcp --no-delay --key --plugin --plugin-opts --help' + opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -6 -d -v -h --reuse-port --fast-open --acl --manager-address --mtu --mptcp --no-delay --long-idle --key --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} diff --git a/completions/zsh/_ss-server b/completions/zsh/_ss-server index 8d9f4316..7c56ec55 100644 --- a/completions/zsh/_ss-server +++ b/completions/zsh/_ss-server @@ -28,6 +28,7 @@ _arguments "-h::" \ "--mtu::" \ "--mptcp::" \ "--no-delay::" \ + "--long-idle::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ diff --git a/doc/ss-server.asciidoc b/doc/ss-server.asciidoc index 0dcddffa..e3cf5ae1 100644 --- a/doc/ss-server.asciidoc +++ b/doc/ss-server.asciidoc @@ -117,6 +117,10 @@ Only available with Linux kernel > 3.9.0. --no-delay:: Enable TCP_NODELAY. +--long-idle:: +Enable TCP long idle connections. +If enable, the connected TCP connections would not be destroyed after timeout. + --acl :: Enable ACL (Access Control List) and specify config file. diff --git a/src/common.h b/src/common.h index 696248f6..ecde2b86 100644 --- a/src/common.h +++ b/src/common.h @@ -62,6 +62,7 @@ enum { GETOPT_VAL_REUSE_PORT, GETOPT_VAL_FAST_OPEN, GETOPT_VAL_NODELAY, + GETOPT_VAL_LONGIDLE, GETOPT_VAL_ACL, GETOPT_VAL_MTU, GETOPT_VAL_MPTCP, diff --git a/src/server.c b/src/server.c index c076e0cc..7955d524 100644 --- a/src/server.c +++ b/src/server.c @@ -120,6 +120,7 @@ static int mode = TCP_ONLY; static int ipv6first = 0; int fast_open = 0; static int no_delay = 0; +static int long_idle = 0; static int ret_val = 0; #ifdef HAVE_SETRLIMIT @@ -704,6 +705,11 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (server->stage == STAGE_STREAM) { remote = server->remote; buf = remote->buf; + + if (!long_idle) { + // Only timer the watcher if a valid connection is established + ev_timer_again(EV_A_ & server->recv_ctx->watcher); + } } ssize_t r = recv(server->fd, buf->data, SOCKET_BUF_SIZE, 0); @@ -1107,6 +1113,11 @@ remote_recv_cb(EV_P_ ev_io *w, int revents) return; } + if (long_idle) + ev_timer_stop(EV_A_ & server->recv_ctx->watcher); + else + ev_timer_again(EV_A_ & server->recv_ctx->watcher); + ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { @@ -1229,9 +1240,6 @@ remote_send_cb(EV_P_ ev_io *w, int revents) int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { - // connection connected, stop the request timeout timer - ev_timer_stop(EV_A_ & server->recv_ctx->watcher); - remote_send_ctx->connected = 1; if (remote->buf->len == 0) { @@ -1391,10 +1399,12 @@ new_server(int fd, listen_ctx_t *listener) int request_timeout = min(MAX_REQUEST_TIMEOUT, listener->timeout) + rand() % MAX_REQUEST_TIMEOUT; + int repeat_interval = long_idle ? 0 : listener->timeout; + ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); ev_timer_init(&server->recv_ctx->watcher, server_timeout_cb, - request_timeout, 0); + request_timeout, repeat_interval); cork_dllist_add(&connections, &server->entries); @@ -1571,6 +1581,7 @@ main(int argc, char **argv) { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, + { "long-idle", no_argument, NULL, GETOPT_VAL_LONGIDLE }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, { "manager-address", required_argument, NULL, GETOPT_VAL_MANAGER_ADDRESS }, @@ -1600,6 +1611,10 @@ main(int argc, char **argv) no_delay = 1; LOGI("enable TCP no-delay"); break; + case GETOPT_VAL_LONGIDLE: + long_idle = 1; + LOGI("enable TCP long idle connections"); + break; case GETOPT_VAL_ACL: LOGI("initializing acl..."); acl = !init_acl(optarg); diff --git a/src/utils.c b/src/utils.c index d243003f..35924f14 100644 --- a/src/utils.c +++ b/src/utils.c @@ -406,6 +406,10 @@ usage() #ifndef MODULE_MANAGER printf( " [--no-delay] Enable TCP_NODELAY.\n"); +#ifdef MODULE_REMOTE + printf( + " [--long-idle] Enable TCP long idle connections.\n"); +#endif printf( " [--key ] Key of your remote server.\n"); #endif