From ce887fd3b2fa633523aa5563b9a8a56b4d87cf46 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 12 May 2012 12:50:00 +0200 Subject: [PATCH] MEDIUM: session: add support for tunnel timeouts Tunnel timeouts are used when TCP connections are forwarded, or when forwarding upgraded HTTP connections (WebSocket) as well as CONNECT requests to proxies. This timeout allows long-lived sessions to be supported without having to set large timeouts to normal requests. --- doc/configuration.txt | 60 ++++++++++++++++++++++++++++++++++++++----- include/proto/proxy.h | 1 + include/types/proxy.h | 1 + src/cfgparse.c | 4 ++- src/proxy.c | 6 ++++- src/session.c | 10 ++++++++ 6 files changed, 74 insertions(+), 8 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 9aa7e1c6d2..99e4f85848 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1117,6 +1117,7 @@ timeout queue X - X X timeout server X - X X timeout srvtimeout (deprecated) X - X X timeout tarpit X X X X +timeout tunnel X - X X transparent (deprecated) X - X X unique-id-format X X X - unique-id-header X X X - @@ -3551,7 +3552,7 @@ no option independant-streams data sent to the server. Doing so will typically break large HTTP posts from slow lines, so use it with caution. - See also : "timeout client" and "timeout server" + See also : "timeout client", "timeout server" and "timeout tunnel" option ldap-check @@ -5014,7 +5015,8 @@ srvtimeout (deprecated) This parameter is provided for compatibility but is currently deprecated. Please use "timeout server" instead. - See also : "timeout server", "timeout client" and "clitimeout". + See also : "timeout server", "timeout tunnel", "timeout client" and + "clitimeout". stats admin { if | unless } @@ -6334,7 +6336,9 @@ timeout clitimeout (deprecated) client timeout remains equal to the server timeout in order to avoid complex situations to debug. It is a good practice to cover one or several TCP packet losses by specifying timeouts that are slightly above multiples of 3 seconds - (eg: 4 or 5 seconds). + (eg: 4 or 5 seconds). If some long-lived sessions are mixed with short-lived + sessions (eg: WebSocket and HTTP), it's worth considering "timeout tunnel", + which overrides "timeout client" and "timeout server" for tunnels. This parameter is specific to frontends, but can be specified once for all in "defaults" sections. This is in fact one of the easiest solutions not to @@ -6347,7 +6351,7 @@ timeout clitimeout (deprecated) to use it to write new configurations. The form "timeout clitimeout" is provided only by backwards compatibility but its use is strongly discouraged. - See also : "clitimeout", "timeout server". + See also : "clitimeout", "timeout server", "timeout tunnel". timeout connect @@ -6508,7 +6512,10 @@ timeout srvtimeout (deprecated) order to avoid complex situations to debug. Whatever the expected server response times, it is a good practice to cover at least one or several TCP packet losses by specifying timeouts that are slightly above multiples of 3 - seconds (eg: 4 or 5 seconds minimum). + seconds (eg: 4 or 5 seconds minimum). If some long-lived sessions are mixed + with short-lived sessions (eg: WebSocket and HTTP), it's worth considering + "timeout tunnel", which overrides "timeout client" and "timeout server" for + tunnels. This parameter is specific to backends, but can be specified once for all in "defaults" sections. This is in fact one of the easiest solutions not to @@ -6521,7 +6528,7 @@ timeout srvtimeout (deprecated) to use it to write new configurations. The form "timeout srvtimeout" is provided only by backwards compatibility but its use is strongly discouraged. - See also : "srvtimeout", "timeout client". + See also : "srvtimeout", "timeout client" and "timeout tunnel". timeout tarpit @@ -6546,6 +6553,47 @@ timeout tarpit See also : "timeout connect", "contimeout". +timeout tunnel + Set the maximum inactivity time on the client and server side for tunnels. + May be used in sections : defaults | frontend | listen | backend + yes | no | yes | yes + Arguments : + is the timeout value specified in milliseconds by default, but + can be in any other unit if the number is suffixed by the unit, + as explained at the top of this document. + + The tunnel timeout applies when a bidirectionnal connection is established + between a client and a server, and the connection remains inactive in both + directions. This timeout supersedes both the client and server timeouts once + the connection becomes a tunnel. In TCP, this timeout is used as soon as no + analyser remains attached to either connection (eg: tcp content rules are + accepted). In HTTP, this timeout is used when a connection is upgraded (eg: + when switching to the WebSocket protocol, or forwarding a CONNECT request + to a proxy), or after the first response when no keepalive/close option is + specified. + + The value is specified in milliseconds by default, but can be in any other + unit if the number is suffixed by the unit, as specified at the top of this + document. Whatever the expected normal idle time, it is a good practice to + cover at least one or several TCP packet losses by specifying timeouts that + are slightly above multiples of 3 seconds (eg: 4 or 5 seconds minimum). + + This parameter is specific to backends, but can be specified once for all in + "defaults" sections. This is in fact one of the easiest solutions not to + forget about it. + + Example : + defaults http + option http-server-close + timeout connect 5s + timeout client 30s + timeout client 30s + timeout server 30s + timeout tunnel 1h # timeout to use with WebSocket and CONNECT + + See also : "timeout client", "timeout server". + + transparent (deprecated) Enable client-side transparent proxying May be used in sections : defaults | frontend | listen | backend diff --git a/include/proto/proxy.h b/include/proto/proxy.h index b2e97fe7de..d5fd3e01ac 100644 --- a/include/proto/proxy.h +++ b/include/proto/proxy.h @@ -69,6 +69,7 @@ static inline void proxy_reset_timeouts(struct proxy *proxy) proxy->timeout.appsession = TICK_ETERNITY; proxy->timeout.httpreq = TICK_ETERNITY; proxy->timeout.check = TICK_ETERNITY; + proxy->timeout.tunnel = TICK_ETERNITY; } /* increase the number of cumulated connections received on the designated frontend */ diff --git a/include/types/proxy.h b/include/types/proxy.h index 26af501544..a94eee7678 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -263,6 +263,7 @@ struct proxy { int httpreq; /* maximum time for complete HTTP request */ int httpka; /* maximum time for a new HTTP request when using keep-alive */ int check; /* maximum time for complete check */ + int tunnel; /* I/O timeout to use in tunnel mode (in ticks) */ } timeout; char *id, *desc; /* proxy id (name) and description */ struct list pendconns; /* pending connections with no server assigned yet */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 5d12056d05..49d1dbe021 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1547,6 +1547,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->timeout.tarpit = defproxy.timeout.tarpit; curproxy->timeout.httpreq = defproxy.timeout.httpreq; curproxy->timeout.httpka = defproxy.timeout.httpka; + curproxy->timeout.tunnel = defproxy.timeout.tunnel; curproxy->source_addr = defproxy.source_addr; } @@ -6127,7 +6128,8 @@ int check_config_validity() if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) && (((curproxy->cap & PR_CAP_FE) && !curproxy->timeout.client) || ((curproxy->cap & PR_CAP_BE) && (curproxy->srv) && - (!curproxy->timeout.connect || !curproxy->timeout.server)))) { + (!curproxy->timeout.connect || + (!curproxy->timeout.server && (curproxy->mode == PR_MODE_HTTP || !curproxy->timeout.tunnel)))))) { Warning("config : missing timeouts for %s '%s'.\n" " | While not properly invalid, you will certainly encounter various problems\n" " | with such a configuration. To fix this, please ensure that all following\n" diff --git a/src/proxy.c b/src/proxy.c index 9ae9889814..bc5779ff3f 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -183,10 +183,14 @@ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, tv = &proxy->timeout.queue; td = &defpx->timeout.queue; cap = PR_CAP_BE; + } else if (!strcmp(args[0], "tunnel")) { + tv = &proxy->timeout.tunnel; + td = &defpx->timeout.tunnel; + cap = PR_CAP_BE; } else { memprintf(err, "'timeout' supports 'client', 'server', 'connect', 'check', " - "'queue', 'http-keep-alive', 'http-request' or 'tarpit', (got '%s')", + "'queue', 'http-keep-alive', 'http-request', 'tunnel' or 'tarpit', (got '%s')", args[0]); return -1; } diff --git a/src/session.c b/src/session.c index 088b436631..ae20e5b38b 100644 --- a/src/session.c +++ b/src/session.c @@ -2001,6 +2001,16 @@ struct task *process_session(struct task *t) */ if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW_NOW))) buffer_forward(s->rep, BUF_INFINITE_FORWARD); + + /* if we have no analyser anymore in any direction and have a + * tunnel timeout set, use it now. + */ + if (!s->req->analysers && s->be->timeout.tunnel) { + s->req->rto = s->req->wto = s->rep->rto = s->rep->wto = + s->be->timeout.tunnel; + s->req->rex = s->req->wex = s->rep->rex = s->rep->wex = + tick_add(now_ms, s->be->timeout.tunnel); + } } /* check if it is wise to enable kernel splicing to forward response data */