[MEDIUM] introduce the "timeout" keyword

A new "timeout" keyword replaces old "{con|cli|srv}timeout", and
provides the ability to independantly set the following timeouts :

  - client
  - tarpit
  - queue
  - connect
  - server
  - appsession

Additionally, the "clitimeout", "contimeout" and "srvtimeout" values
are supported but deprecated. No warning is emitted yet when they are
used since the option is very new.

Other timeouts should follow soon now.
This commit is contained in:
Willy Tarreau 2007-12-03 01:30:13 +01:00
parent 1fa3126ec4
commit e219db7a46
5 changed files with 138 additions and 70 deletions

View File

@ -244,8 +244,8 @@ block - X X X
capture cookie X X X X
capture request header X X X X
capture response header X X X X
clitimeout X X X -
contimeout X X X X
clitimeout X X X - (deprecated)
contimeout X X X X (deprecated)
cookie X - X X
default_backend - X X -
disabled - X X X
@ -314,7 +314,7 @@ rspirep - X X X
rsprep - X X X
server - - X X
source X - X X
srvtimeout X - X X
srvtimeout X - X X (deprecated)
stats auth X - X X
stats enable X - X X
stats realm X - X X
@ -322,6 +322,15 @@ stats refresh X - X X
stats scope X - X X
stats uri X - X X
stats hide-version X - X X
timeout appsession X - X X
timeout client X X X -
timeout clitimeout X X X - (deprecated)
timeout connect X - X X
timeout contimeout X - X X (deprecated)
timeout queue X - X X
timeout server X - X X
timeout srvtimeout X - X X (deprecated)
timeout tarpit X X X -
transparent X X X -
use_backend - X X -
usesrc X - X X

View File

@ -36,6 +36,8 @@ void listen_proxies(void);
const char *proxy_cap_str(int cap);
const char *proxy_mode_str(int mode);
struct proxy *findproxy(const char *name, int mode, int cap);
int proxy_parse_timeout(const char **args, struct proxy *proxy,
struct proxy *defpx, char *err, int errlen);
/*
* This function returns a string containing the type of the proxy in a format

View File

@ -976,78 +976,26 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
return -1;
}
}
else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
if (!__tv_iseq(&curproxy->contimeout, &defproxy.contimeout)) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
return 0;
}
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
return 0;
else if (!strcmp(args[0], "contimeout") || !strcmp(args[0], "clitimeout") ||
!strcmp(args[0], "srvtimeout") || !strcmp(args[0], "timeout")) {
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
file, linenum, args[0]);
return -1;
}
err = parse_time_err(args[1], &val, TIME_UNIT_MS);
if (err) {
Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
file, linenum, *err, args[0]);
return -1;
}
if (val > 0)
__tv_from_ms(&curproxy->contimeout, val);
else
tv_eternity(&curproxy->contimeout);
}
else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
if (!__tv_iseq(&curproxy->clitimeout, &defproxy.clitimeout)) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
file, linenum, args[0]);
return 0;
}
else if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
return 0;
/* either we have {con|srv|cli}timeout <value> or we have the
* new form: timeout <type> <value>. The parser needs the word
* preceeding the value.
*/
const char **start_arg = (const char **)args;
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
file, linenum, args[0]);
return -1;
}
err = parse_time_err(args[1], &val, TIME_UNIT_MS);
if (err) {
Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
file, linenum, *err, args[0]);
return -1;
}
if (val > 0)
__tv_from_ms(&curproxy->clitimeout, val);
else
tv_eternity(&curproxy->clitimeout);
}
else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
if (!__tv_iseq(&curproxy->srvtimeout, &defproxy.srvtimeout)) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
return 0;
}
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
return 0;
if (strcmp(args[0], "timeout") == 0)
start_arg++;
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
file, linenum, args[0]);
snprintf(trash, sizeof(trash), "error near '%s'", args[0]);
rc = proxy_parse_timeout(start_arg, curproxy, &defproxy, trash, sizeof(trash));
if (rc < 0) {
Alert("parsing [%s:%d] : %s\n", file, linenum, trash);
return -1;
}
err = parse_time_err(args[1], &val, TIME_UNIT_MS);
if (err) {
Alert("parsing [%s:%d] : unexpected character '%c' in %s.\n",
file, linenum, *err, args[0]);
return -1;
}
if (val > 0)
__tv_from_ms(&curproxy->srvtimeout, val);
else
tv_eternity(&curproxy->srvtimeout);
if (rc > 0)
Warning("parsing [%s:%d] : %s\n", file, linenum, trash);
}
else if (!strcmp(args[0], "retries")) { /* connection retries */
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))

View File

@ -75,6 +75,89 @@ const char *proxy_mode_str(int mode) {
return "unknown";
}
/* This function parses a "timeout" statement in a proxy section. It returns
* -1 if there is any error, 1 for a warning, otherwise zero. If it does not
* return zero, it may write an error message into the <err> buffer, for at
* most <errlen> bytes, trailing zero included. The trailing '\n' must not
* be written. The function must be called with <args> pointing to the first
* word after "timeout", with <proxy> pointing to the proxy being parsed, and
* <defpx> to the default proxy or NULL. As a special case for compatibility
* with older configs, it also accepts "{cli|srv|con}timeout" in args[0].
*/
int proxy_parse_timeout(const char **args, struct proxy *proxy,
struct proxy *defpx, char *err, int errlen)
{
unsigned timeout;
int retval, cap;
const char *res, *name;
struct timeval *tv = NULL;
struct timeval *td = NULL;
retval = 0;
name = args[0];
if (!strcmp(args[0], "client") || !strcmp(args[0], "clitimeout")) {
name = "client";
tv = &proxy->clitimeout;
td = &defpx->clitimeout;
cap = PR_CAP_FE;
} else if (!strcmp(args[0], "tarpit")) {
tv = &proxy->timeout.tarpit;
td = &defpx->timeout.tarpit;
cap = PR_CAP_FE;
} else if (!strcmp(args[0], "server") || !strcmp(args[0], "srvtimeout")) {
name = "server";
tv = &proxy->srvtimeout;
td = &defpx->srvtimeout;
cap = PR_CAP_BE;
} else if (!strcmp(args[0], "connect") || !strcmp(args[0], "contimeout")) {
name = "connect";
tv = &proxy->contimeout;
td = &defpx->contimeout;
cap = PR_CAP_BE;
} else if (!strcmp(args[0], "appsession")) {
tv = &proxy->appsession_timeout;
td = &defpx->appsession_timeout;
cap = PR_CAP_BE;
} else if (!strcmp(args[0], "queue")) {
tv = &proxy->timeout.queue;
td = &defpx->timeout.queue;
cap = PR_CAP_BE;
} else {
snprintf(err, errlen, "timeout '%s': must be 'client', 'server', 'connect', 'appsession', 'queue', or 'tarpit'",
args[0]);
return -1;
}
if (*args[1] == 0) {
snprintf(err, errlen, "%s timeout expects an integer value (in milliseconds)", name);
return -1;
}
res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
if (res) {
snprintf(err, errlen, "unexpected character '%c' in %s timeout", *err, name);
return -1;
}
if (!(proxy->cap & cap)) {
snprintf(err, errlen, "%s timeout will be ignored because %s '%s' has no %s capability",
name, proxy_type_str(proxy), proxy->id,
(cap & PR_CAP_BE) ? "backend" : "frontend");
retval = 1;
}
else if (defpx && !__tv_iseq(tv, td)) {
snprintf(err, errlen, "overwriting %s timeout which was already specified", name);
retval = 1;
}
if (timeout)
__tv_from_ms(tv, timeout);
else
tv_eternity(tv);
return retval;
}
/*
* This function finds a proxy with matching name, mode and with satisfying
* capabilities. It also checks if there are more matching proxies with

26
tests/test-timeout.cfg Normal file
View File

@ -0,0 +1,26 @@
# This is a test configuration.
# It is used to check that time units are correctly parsed.
global
maxconn 1000
stats timeout 3s
listen sample1
mode http
retries 1
redispatch
timeout client 15m
timeout tarpit 20s
timeout queue 60s
timeout connect 5s
timeout server 15m
maxconn 40000
bind :8000
balance roundrobin
option allbackups
server act1 127.0.0.1:80 weight 10 check port 81 inter 500ms fall 1
server act2 127.0.0.2:80 weight 20 check port 81 inter 500ms fall 1
server act3 127.0.0.3:80 weight 30 check port 81 inter 500ms fall 1
option httpclose
stats uri /stats
stats refresh 5000ms