diff options
author | Joe Orton <jorton@apache.org> | 2020-04-23 10:26:26 +0200 |
---|---|---|
committer | Joe Orton <jorton@apache.org> | 2020-04-23 10:26:26 +0200 |
commit | a42f3692b1b975ba05a8e678bafe463707e7e5df (patch) | |
tree | a8a5e9dbdd39f78248454ba5de524a230f3a3436 /server | |
parent | config: allow for environment variable substitution fallback to default value. (diff) | |
download | apache2-a42f3692b1b975ba05a8e678bafe463707e7e5df.tar.xz apache2-a42f3692b1b975ba05a8e678bafe463707e7e5df.zip |
Add optional options= argument to Listen to add listener-specific
socket options.
Reimplement "use_specific_errors" listener flag under generic
ap_listen_rec flags field holding all listener-specific options.
* include/ap_listen.h: Add AP_LISTEN_* flags.
(ap_listen_rec): Rename use_specific_errors to flags.
* server/listen.c (make_sock): Set APR_SO_FREEBIND if
AP_LISTEN_FREEBIND flag is set on listener; set APR_SO_REUSEPORT
unconditionally if AP_LISTEN_REUSEPORT is set.
(alloc_listener): Take flags argument.
(ap_setup_listeners): Set AP_LISTEN_SPECIFIC_ERRORS flag here.
(ap_set_listener): Parse optional options=... argument, catch
typos and fail if protocol name contains a "=".
(ap_duplicate_listeners): Duplicate flags.
Submitted by: jkaluza, Lubos Uhliarik <luhliari redhat.com>, jorton
PR: 61865
Github: closes #114
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1876865 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server')
-rw-r--r-- | server/listen.c | 102 |
1 files changed, 90 insertions, 12 deletions
diff --git a/server/listen.c b/server/listen.c index 87a4bafe80..d4f9936828 100644 --- a/server/listen.c +++ b/server/listen.c @@ -150,7 +150,8 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ #endif #if defined(SO_REUSEPORT) - if (ap_have_so_reuseport && ap_listencbratio > 0) { + if (server->flags & AP_LISTEN_REUSEPORT + || (ap_have_so_reuseport && ap_listencbratio > 0)) { int thesock; apr_os_sock_get(&thesock, s); if (setsockopt(thesock, SOL_SOCKET, SO_REUSEPORT, @@ -166,6 +167,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ } #endif + +#if defined(APR_SO_FREEBIND) + if (server->flags & AP_LISTEN_FREEBIND) { + if (apr_socket_opt_set(s, APR_SO_FREEBIND, one) < 0) { + stat = apr_get_netos_error(); + ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO() + "make_sock: apr_socket_opt_set: " + "error setting APR_SO_FREEBIND"); + apr_socket_close(s); + return stat; + } + } +#endif + + if (do_bind_listen) { #if APR_HAVE_IPV6 if (server->bind_addr->family == APR_INET6) { @@ -467,7 +483,7 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, static const char *alloc_listener(process_rec *process, const char *addr, apr_port_t port, const char* proto, const char *scope_id, void *slave, - apr_pool_t *temp_pool) + apr_pool_t *temp_pool, apr_uint32_t flags) { ap_listen_rec *last; apr_status_t status; @@ -511,6 +527,7 @@ static const char *alloc_listener(process_rec *process, const char *addr, new->next = 0; new->bind_addr = sa; new->protocol = apr_pstrdup(process->pool, proto); + new->flags = flags; /* Go to the next sockaddr. */ sa = sa->next; @@ -795,7 +812,7 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) } for (lr = ap_listeners; lr; lr = lr->next) { - lr->use_specific_errors = ap_accept_errors_nonfatal; + if (ap_accept_errors_nonfatal) lr->flags |= AP_LISTEN_SPECIFIC_ERRORS; num_listeners++; found = 0; for (ls = s; ls && !found; ls = ls->next) { @@ -885,6 +902,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p); duplr->bind_addr = sa; duplr->next = NULL; + duplr->flags = lr->flags; stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family, SOCK_STREAM, 0, p); if (stat != APR_SUCCESS) { @@ -1015,20 +1033,48 @@ AP_DECLARE(int) ap_accept_error_is_nonfatal(apr_status_t status) || APR_STATUS_IS_ECONNRESET(status); } +/* Parse optional flags argument for Listen. Currently just boolean + * flags handled; would need to be extended to incorporate + * ListenBacklog */ +static const char *parse_listen_flags(apr_pool_t *temp_pool, const char *arg, + apr_uint32_t *flags_out) +{ + apr_uint32_t flags = 0; + char *str = apr_pstrdup(temp_pool, arg), *token, *state = NULL; + + token = apr_strtok(str, ",", &state); + while (token) { + if (ap_cstr_casecmp(token, "freebind") == 0) + flags |= AP_LISTEN_FREEBIND; + else if (ap_cstr_casecmp(token, "reuseport") == 0) + flags |= AP_LISTEN_REUSEPORT; + else + return apr_psprintf(temp_pool, "Unknown Listen option '%s' in '%s'", + token, arg); + + token = apr_strtok(NULL, ",", &state); + } + + *flags_out = flags; + + return NULL; +} + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, int argc, char *const argv[]) { - char *host, *scope_id, *proto; + char *host, *scope_id, *proto = NULL; apr_port_t port; apr_status_t rv; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + apr_uint32_t flags = 0; if (err != NULL) { return err; } - if (argc < 1 || argc > 2) { - return "Listen requires 1 or 2 arguments."; + if (argc < 1 || argc > 3) { + return "Listen requires 1-3 arguments."; } #ifdef HAVE_SYSTEMD if (use_systemd == -1) { @@ -1058,17 +1104,49 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, return "Port must be specified"; } - if (argc != 2) { + if (argc == 3) { + if (strncasecmp(argv[2], "options=", 8)) { + return "Third argument to Listen must be options=..."; + } + + err = parse_listen_flags(cmd->temp_pool, argv[2] + 8, &flags); + if (err) { + return err; + } + + proto = argv[1]; + } + + if (argc == 2) { + /* 2-arg form is either 'Listen host:port options=...' or + * 'Listen host:port protocol' */ + if (strncasecmp(argv[1], "options=", 8) == 0) { + err = parse_listen_flags(cmd->temp_pool, argv[1] + 8, &flags); + if (err) { + return err; + } + } + else { + proto = argv[1]; + } + } + + /* Catch case where 2-arg form has typoed options=X and doesn't + * match above. */ + if (proto && ap_strchr_c(proto, '=') != NULL) { + return apr_psprintf(cmd->pool, "Invalid protocol name '%s'", proto); + } + else if (proto) { + proto = apr_pstrdup(cmd->pool, proto); + ap_str_tolower(proto); + } + else { if (port == 443) { proto = "https"; } else { proto = "http"; } } - else { - proto = apr_pstrdup(cmd->pool, argv[1]); - ap_str_tolower(proto); - } #ifdef HAVE_SYSTEMD if (use_systemd) { @@ -1077,7 +1155,7 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, #endif return alloc_listener(cmd->server->process, host, port, proto, - scope_id, NULL, cmd->temp_pool); + scope_id, NULL, cmd->temp_pool, flags); } AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, |