diff --git a/doc/configuration.txt b/doc/configuration.txt index dd8649309..85b687eb6 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -10885,7 +10885,7 @@ alpn bind :443 ssl crt pub.pem alpn h2,http/1.1 backlog - Sets the socket's backlog to this value. If unspecified, the frontend's + Sets the socket's backlog to this value. If unspecified or 0, the frontend's backlog is used instead, which generally defaults to the maxconn value. curves diff --git a/include/proto/listener.h b/include/proto/listener.h index 8ec41af11..24a01b2ed 100644 --- a/include/proto/listener.h +++ b/include/proto/listener.h @@ -109,6 +109,12 @@ void delete_listener(struct listener *listener); */ void listener_accept(int fd); +/* Returns a suitable value for a listener's backlog. It uses the listener's, + * otherwise the frontend's backlog, otherwise the listener's maxconn, + * otherwise the frontend's maxconn, otherwise 1024. + */ +int listener_backlog(const struct listener *l); + /* Notify the listener that a connection initiated from it was released. This * is used to keep the connection count consistent and to possibly re-open * listening when it was limited. diff --git a/src/cfgparse.c b/src/cfgparse.c index 21b9af540..4c8b48b1e 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -650,7 +650,6 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); l->maxaccept = 1; l->maxconn = curpeers->peers_fe->maxconn; - l->backlog = curpeers->peers_fe->backlog; l->accept = session_accept_fd; l->analysers |= curpeers->peers_fe->fe_req_ana; l->default_target = curpeers->peers_fe->default_target; @@ -854,7 +853,6 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); l->maxaccept = 1; l->maxconn = curpeers->peers_fe->maxconn; - l->backlog = curpeers->peers_fe->backlog; l->accept = session_accept_fd; l->analysers |= curpeers->peers_fe->fe_req_ana; l->default_target = curpeers->peers_fe->default_target; @@ -3743,8 +3741,6 @@ int check_config_validity() listener->options |= LI_O_NOLINGER; if (!listener->maxconn) listener->maxconn = curproxy->maxconn; - if (!listener->backlog) - listener->backlog = curproxy->backlog; if (!listener->maxaccept) listener->maxaccept = global.tune.maxaccept ? global.tune.maxaccept : 64; diff --git a/src/cli.c b/src/cli.c index 0cace77a7..9b957186d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -298,7 +298,6 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx list_for_each_entry(l, &bind_conf->listeners, by_bind) { l->maxconn = global.stats_fe->maxconn; - l->backlog = global.stats_fe->backlog; l->accept = session_accept_fd; l->default_target = global.stats_fe->default_target; l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */ @@ -2522,7 +2521,6 @@ int mworker_cli_proxy_new_listener(char *line) list_for_each_entry(l, &bind_conf->listeners, by_bind) { l->maxconn = 10; - l->backlog = 10; l->accept = session_accept_fd; l->default_target = mworker_proxy->default_target; /* don't make the peers subject to global limits and don't close it in the master */ @@ -2592,7 +2590,6 @@ int mworker_cli_sockpair_new(struct mworker_proc *mworker_proc, int proc) list_for_each_entry(l, &bind_conf->listeners, by_bind) { l->maxconn = global.stats_fe->maxconn; - l->backlog = global.stats_fe->backlog; l->accept = session_accept_fd; l->default_target = global.stats_fe->default_target; l->options |= (LI_O_UNLIMITED | LI_O_NOSTOP); diff --git a/src/listener.c b/src/listener.c index 3ae20e247..4e22e507e 100644 --- a/src/listener.c +++ b/src/listener.c @@ -350,7 +350,7 @@ int resume_listener(struct listener *l) if (l->proto->sock_prot == IPPROTO_TCP && l->state == LI_PAUSED && - listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0) { + listen(l->fd, listener_backlog(l)) != 0) { ret = 0; goto end; } @@ -568,6 +568,27 @@ void delete_listener(struct listener *listener) HA_SPIN_UNLOCK(LISTENER_LOCK, &listener->lock); } +/* Returns a suitable value for a listener's backlog. It uses the listener's, + * otherwise the frontend's backlog, otherwise the listener's maxconn, + * otherwise the frontend's maxconn, otherwise 1024. + */ +int listener_backlog(const struct listener *l) +{ + if (l->backlog) + return l->backlog; + + if (l->bind_conf->frontend->backlog) + return l->bind_conf->frontend->backlog; + + if (l->maxconn) + return l->maxconn; + + if (l->bind_conf->frontend->maxconn) + return l->bind_conf->frontend->maxconn; + + return 1024; +} + /* This function is called on a read event from a listening socket, corresponding * to an accept. It tries to accept as many connections as possible, and for each * calls the listener's accept handler (generally the frontend's accept handler). @@ -1101,7 +1122,7 @@ static int bind_parse_accept_netscaler_cip(char **args, int cur_arg, struct prox val = atol(args[cur_arg + 1]); if (val <= 0) { - memprintf(err, "'%s' : invalid value %d, must be > 0", args[cur_arg], val); + memprintf(err, "'%s' : invalid value %d, must be >= 0", args[cur_arg], val); return ERR_ALERT | ERR_FATAL; } @@ -1125,7 +1146,7 @@ static int bind_parse_backlog(char **args, int cur_arg, struct proxy *px, struct } val = atol(args[cur_arg + 1]); - if (val <= 0) { + if (val < 0) { memprintf(err, "'%s' : invalid value %d, must be > 0", args[cur_arg], val); return ERR_ALERT | ERR_FATAL; } diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 28b77503e..f1a0e4cf6 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1017,7 +1017,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) #if defined(TCP_FASTOPEN) if (listener->options & LI_O_TCP_FO) { /* TFO needs a queue length, let's use the configured backlog */ - int qlen = listener->backlog ? listener->backlog : listener->maxconn; + int qlen = listener_backlog(listener); if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) == -1) { msg = "cannot enable TCP_FASTOPEN"; err |= ERR_WARN; @@ -1058,7 +1058,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) ready = 0; if (!(ext && ready) && /* only listen if not already done by external process */ - listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) { + listen(fd, listener_backlog(listener)) == -1) { err |= ERR_RETRYABLE | ERR_ALERT; msg = "cannot listen to socket"; goto tcp_close_return; @@ -1150,7 +1150,7 @@ int tcp_pause_listener(struct listener *l) if (shutdown(l->fd, SHUT_WR) != 0) return -1; /* Solaris dies here */ - if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0) + if (listen(l->fd, listener_backlog(l)) != 0) return -1; /* OpenBSD dies here */ if (shutdown(l->fd, SHUT_RD) != 0) diff --git a/src/proto_uxst.c b/src/proto_uxst.c index d454d4ca1..980a22649 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -315,7 +315,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle ready = 0; if (!(ext && ready) && /* only listen if not already done by external process */ - listen(fd, listener->backlog ? listener->backlog : listener->maxconn) < 0) { + listen(fd, listener_backlog(listener)) < 0) { err |= ERR_FATAL | ERR_ALERT; msg = "cannot listen to UNIX socket"; goto err_unlink_temp;