From 455211d898417d7fd9c4efd40ff2684d4cb7cdb6 Mon Sep 17 00:00:00 2001 From: Paul Querna Date: Tue, 6 Aug 2013 16:51:15 +0000 Subject: [PATCH 01/10] Add support for systemd socket activation to listener sockets. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1511033 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit ba9ab903c448f1866544e2b91317e10ebe922844) --- configure.in | 9 ++ server/listen.c | 222 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 199 insertions(+), 32 deletions(-) diff --git a/configure.in b/configure.in index d2a009d7902..9a240a764d9 100644 --- a/configure.in +++ b/configure.in @@ -337,6 +337,15 @@ case $host in APR_SETVAR(SINGLE_LISTEN_UNSERIALIZED_ACCEPT, [1]) ;; *-linux-*) + AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") + AC_CHECK_HEADERS(systemd/sd-daemon.h, [ap_HAVE_SD_DAEMON_H="yes"], [ap_HAVE_SD_DAEMON_H="no"]) + if test $ap_HAVE_SD_DAEMON_H = "no" || test -z "${SYSTEMD_LIBS}"; then + AC_MSG_WARN([Your system does not support systemd.]) + else + APR_ADDTO(LIBS, $SYSTEMD_LIBS) + APR_ADDTO(INTERNAL_CPPFLAGS, [-DAP_SYSTEMD_SUPPORT]) + fi + case `uname -r` in # Unserialized accept() was not recommended until Linux 2.2. [[01]].* | 2.[[01]]* ) diff --git a/server/listen.c b/server/listen.c index 9577d60269a..f26ed46b325 100644 --- a/server/listen.c +++ b/server/listen.c @@ -60,9 +60,12 @@ static int ap_listenbacklog; static int ap_listencbratio; static int send_buffer_size; static int receive_buffer_size; +#ifdef AP_SYSTEMD_SUPPORT +static int use_systemd; +#endif /* TODO: make_sock is just begging and screaming for APR abstraction */ -static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) +static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen) { apr_socket_t *s = server->sd; int one = 1; @@ -95,20 +98,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) return stat; } -#if APR_HAVE_IPV6 - if (server->bind_addr->family == APR_INET6) { - stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); - if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) - "make_sock: for address %pI, apr_socket_opt_set: " - "(IPV6_V6ONLY)", - server->bind_addr); - apr_socket_close(s); - return stat; - } - } -#endif - /* * To send data over high bandwidth-delay connections at full * speed we must force the TCP window to open wide enough to keep the @@ -170,21 +159,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) } #endif - if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) - "make_sock: could not bind to address %pI", - server->bind_addr); - apr_socket_close(s); - return stat; - } + if (do_bind_listen) { +#if APR_HAVE_IPV6 + if (server->bind_addr->family == APR_INET6) { + stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); + if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) + "make_sock: for address %pI, apr_socket_opt_set: " + "(IPV6_V6ONLY)", + server->bind_addr); + apr_socket_close(s); + return stat; + } + } +#endif - if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) - "make_sock: unable to listen for connections " - "on address %pI", - server->bind_addr); - apr_socket_close(s); - return stat; + if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) + "make_sock: could not bind to address %pI", + server->bind_addr); + apr_socket_close(s); + return stat; + } + + if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) + "make_sock: unable to listen for connections " + "on address %pI", + server->bind_addr); + apr_socket_close(s); + return stat; + } } #ifdef WIN32 @@ -278,6 +283,130 @@ static apr_status_t close_listeners_on_exec(void *v) return APR_SUCCESS; } +#ifdef AP_SYSTEMD_SUPPORT + +static apr_status_t alloc_systemd_listener(process_rec * process, + int fd, + ap_listen_rec **out_rec) +{ + apr_status_t rv; + struct sockaddr sa; + socklen_t len; + apr_os_sock_info_t si; + ap_listen_rec *rec; + *out_rec = NULL; + + memset(&si, 0, sizeof(si)); + + rv = getsockname(fd, &sa, &len); + + if (rv != 0) { + rv = apr_get_netos_error(); + ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489) + "getsockname on %d failed.", fd); + return rv; + } + + si.os_sock = &fd; + si.family = sa.sa_family; + si.type = SOCK_STREAM; + si.protocol = APR_PROTO_TCP; + + rec = apr_palloc(process->pool, sizeof(ap_listen_rec)); + rec->active = 0; + rec->next = 0; + + + rv = apr_os_sock_make(&rec->sd, &si, process->pool); + if (rv != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490) + "apr_os_sock_make on %d failed.", fd); + return rv; + } + + rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd); + if (rv != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491) + "apr_socket_addr_get on %d failed.", fd); + return rv; + } + + if (rec->bind_addr->port == 443) { + rec->protocol = apr_pstrdup(process->pool, "https"); + } else { + rec->protocol = apr_pstrdup(process->pool, "http"); + } + + *out_rec = rec; + + return make_sock(process->pool, rec, 0); +} + +static int open_systemd_listeners(process_rec *process) +{ + ap_listen_rec *last, *new; + int fdcount, fd; + apr_status_t rv; + void *data; + const char *userdata_key = "ap_systemd_listeners"; + int sdc = sd_listen_fds(0); + + if (sdc < 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) + "open_systemd_listeners: Error parsing enviroment, sd_listen_fds returned %d", + sdc); + return 1; + } + + if (sdc == 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) + "open_systemd_listeners: At least one socket must be set."); + return 1; + } + + last = ap_listeners; + while (last && last->next) { + last = last->next; + } + + fdcount = atoi(getenv("LISTEN_FDS")); + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { + rv = alloc_systemd_listener(process, fd, &new); + + if (rv != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02488) + "open_systemd_listeners: failed to setup socket %d.", fd); + return 1; + } + + if (last == NULL) { + ap_listeners = last = new; + } + else { + last->next = new; + last = new; + } + } + + /* clear the enviroment on our second run + * so that none of our future children get confused. + */ + apr_pool_userdata_get(&data, userdata_key, process->pool); + if (!data) { + apr_pool_userdata_set((const void *)1, userdata_key, + apr_pool_cleanup_null, process->pool); + } + else { + sd_listen_fds(1); + } + + + return 0; +} + +#endif /* AP_SYSTEMD_SUPPORT */ + /* Returns non-zero if socket address SA matches hostname, port and * scope_id. p is used for temporary allocations. */ static int match_address(const apr_sockaddr_t *sa, @@ -529,7 +658,7 @@ static int open_listeners(apr_pool_t *pool) } } #endif - if (make_sock(pool, lr) == APR_SUCCESS) { + if (make_sock(pool, lr, 1) == APR_SUCCESS) { ++num_open; } else { @@ -641,8 +770,19 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) } } - if (open_listeners(s->process->pool)) { - return 0; + +#ifdef AP_SYSTEMD_SUPPORT + if (use_systemd) { + if (open_systemd_listeners(s->process) != 0) { + return 0; + } + } + else +#endif + { + if (open_listeners(s->process->pool)) { + return 0; + } } for (lr = ap_listeners; lr; lr = lr->next) { @@ -860,6 +1000,24 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, return "Listen requires 1 or 2 arguments."; } + if (strcmp("systemd", argv[0]) == 0) { +#ifdef AP_SYSTEMD_SUPPORT + use_systemd = 1; + if (ap_listeners != NULL) { + return "systemd socket activation support must be used exclusive of normal listeners."; + } + return NULL; +#else + return "systemd support was not compiled in."; +#endif + } + +#ifdef AP_SYSTEMD_SUPPORT + if (use_systemd) { + return "systemd socket activation support must be used exclusive of normal listeners."; + } +#endif + rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); if (rv != APR_SUCCESS) { return "Invalid address or port"; From 369d393c046676155a6afad4d168bfdc70f7d4e0 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 1 Oct 2013 10:15:12 +0000 Subject: [PATCH 02/10] * configure.in: Simplify/fix systemd detection: move later to fix autoconf warnings; define HAVE_SYSTEMD rather than using CPPFLAGS. * server/listen.c: Use HAVE_SYSTEMD for systemd #define. * modules/arch/unix/config5.m4: Update systemd headers check. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1528032 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit f6f568d30c9718df3b0474529b6663100f5bba41) --- configure.in | 9 --------- server/listen.c | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/configure.in b/configure.in index 9a240a764d9..d2a009d7902 100644 --- a/configure.in +++ b/configure.in @@ -337,15 +337,6 @@ case $host in APR_SETVAR(SINGLE_LISTEN_UNSERIALIZED_ACCEPT, [1]) ;; *-linux-*) - AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") - AC_CHECK_HEADERS(systemd/sd-daemon.h, [ap_HAVE_SD_DAEMON_H="yes"], [ap_HAVE_SD_DAEMON_H="no"]) - if test $ap_HAVE_SD_DAEMON_H = "no" || test -z "${SYSTEMD_LIBS}"; then - AC_MSG_WARN([Your system does not support systemd.]) - else - APR_ADDTO(LIBS, $SYSTEMD_LIBS) - APR_ADDTO(INTERNAL_CPPFLAGS, [-DAP_SYSTEMD_SUPPORT]) - fi - case `uname -r` in # Unserialized accept() was not recommended until Linux 2.2. [[01]].* | 2.[[01]]* ) diff --git a/server/listen.c b/server/listen.c index f26ed46b325..b9a8a627278 100644 --- a/server/listen.c +++ b/server/listen.c @@ -60,7 +60,7 @@ static int ap_listenbacklog; static int ap_listencbratio; static int send_buffer_size; static int receive_buffer_size; -#ifdef AP_SYSTEMD_SUPPORT +#ifdef HAVE_SYSTEMD static int use_systemd; #endif @@ -405,7 +405,7 @@ static int open_systemd_listeners(process_rec *process) return 0; } -#endif /* AP_SYSTEMD_SUPPORT */ +#endif /* HAVE_SYSTEMD */ /* Returns non-zero if socket address SA matches hostname, port and * scope_id. p is used for temporary allocations. */ @@ -771,7 +771,7 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) } -#ifdef AP_SYSTEMD_SUPPORT +#ifdef HAVE_SYSTEMD if (use_systemd) { if (open_systemd_listeners(s->process) != 0) { return 0; @@ -1001,7 +1001,7 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, } if (strcmp("systemd", argv[0]) == 0) { -#ifdef AP_SYSTEMD_SUPPORT +#ifdef HAVE_SYSTEMD use_systemd = 1; if (ap_listeners != NULL) { return "systemd socket activation support must be used exclusive of normal listeners."; @@ -1012,7 +1012,7 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, #endif } -#ifdef AP_SYSTEMD_SUPPORT +#ifdef HAVE_SYSTEMD if (use_systemd) { return "systemd socket activation support must be used exclusive of normal listeners."; } From 182ab4a90456f1071cf64cc6d70983f7ed1485b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Kalu=C5=BEa?= Date: Tue, 8 Jul 2014 07:56:59 +0000 Subject: [PATCH 03/10] * server/listen.c: duplicate sockets correctly when using systemd socket activation, fix addrlen in getsockname() call. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1608686 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 3d6f0d29e22fd35b2e74457f591d2d0b1a894fdd) --- server/listen.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/server/listen.c b/server/listen.c index b9a8a627278..a4679073b92 100644 --- a/server/listen.c +++ b/server/listen.c @@ -291,7 +291,7 @@ static apr_status_t alloc_systemd_listener(process_rec * process, { apr_status_t rv; struct sockaddr sa; - socklen_t len; + socklen_t len = sizeof(struct sockaddr); apr_os_sock_info_t si; ap_listen_rec *rec; *out_rec = NULL; @@ -309,6 +309,7 @@ static apr_status_t alloc_systemd_listener(process_rec * process, si.os_sock = &fd; si.family = sa.sa_family; + si.local = &sa; si.type = SOCK_STREAM; si.protocol = APR_PROTO_TCP; @@ -855,24 +856,36 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, char *hostname; apr_port_t port; apr_sockaddr_t *sa; - duplr = apr_palloc(p, sizeof(ap_listen_rec)); - duplr->slave = NULL; - duplr->protocol = apr_pstrdup(p, lr->protocol); - hostname = apr_pstrdup(p, lr->bind_addr->hostname); - port = lr->bind_addr->port; - apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p); - duplr->bind_addr = sa; - duplr->next = NULL; - stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family, - SOCK_STREAM, 0, p); - if (stat != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640) - "ap_duplicate_listeners: for address %pI, " - "cannot duplicate a new socket!", - duplr->bind_addr); - return stat; +#ifdef HAVE_SYSTEMD + if (use_systemd) { + int thesock; + apr_os_sock_get(&thesock, lr->sd); + if ((stat = alloc_systemd_listener(p, thesock, &duplr)) + != APR_SUCCESS) { + return stat; + } + } + else +#endif + { + duplr = apr_palloc(p, sizeof(ap_listen_rec)); + duplr->slave = NULL; + duplr->protocol = apr_pstrdup(p, lr->protocol); + hostname = apr_pstrdup(p, lr->bind_addr->hostname); + port = lr->bind_addr->port; + apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p); + duplr->bind_addr = sa; + duplr->next = NULL; + if ((stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family, + SOCK_STREAM, 0, p)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640) + "ap_duplicate_socket: for address %pI, " + "cannot duplicate a new socket!", + duplr->bind_addr); + return stat; + } + make_sock(p, duplr, 1); } - make_sock(p, duplr); #if AP_NONBLOCK_WHEN_MULTI_LISTEN use_nonblock = (ap_listeners && ap_listeners->next); stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock); From ee6ba48ccedc3d3e243ba561948cbef39ae23666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Kalu=C5=BEa?= Date: Tue, 8 Jul 2014 09:03:02 +0000 Subject: [PATCH 04/10] Follow up r1608686, pass process to alloc_systemd_listener. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1608694 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 48d05b91ce285f6ec2342b359a78b7d27a6e26cd) --- server/listen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/listen.c b/server/listen.c index a4679073b92..df95b9ba9a2 100644 --- a/server/listen.c +++ b/server/listen.c @@ -860,7 +860,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, if (use_systemd) { int thesock; apr_os_sock_get(&thesock, lr->sd); - if ((stat = alloc_systemd_listener(p, thesock, &duplr)) + if ((stat = alloc_systemd_listener(s->process, thesock, &duplr)) != APR_SUCCESS) { return stat; } From 32cafa3583030765b3ef81baca0f74a06ed7fe36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Kalu=C5=BEa?= Date: Tue, 8 Jul 2014 09:42:24 +0000 Subject: [PATCH 05/10] * server/listen.c: detect systemd socket activation using sd_listen_fds(), drop the support for "Listen systemd" and use standard Listen syntax instead. This allows using the same configuration file with or without socket activation and allows setting protocol when using socket activation. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1608703 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 4eff9ee6893d2c40191c17913be529a7611a1f85) --- server/listen.c | 143 +++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 74 deletions(-) diff --git a/server/listen.c b/server/listen.c index df95b9ba9a2..48dcb9c7375 100644 --- a/server/listen.c +++ b/server/listen.c @@ -61,7 +61,7 @@ static int ap_listencbratio; static int send_buffer_size; static int receive_buffer_size; #ifdef HAVE_SYSTEMD -static int use_systemd; +static int use_systemd = -1; #endif /* TODO: make_sock is just begging and screaming for APR abstraction */ @@ -285,8 +285,35 @@ static apr_status_t close_listeners_on_exec(void *v) #ifdef AP_SYSTEMD_SUPPORT +static int find_systemd_socket(process_rec * process, apr_port_t port) { + int fdcount, fd; + int sdc = sd_listen_fds(0); + + if (sdc < 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) + "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", + sdc); + return 1; + } + + if (sdc == 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) + "find_systemd_socket: At least one socket must be set."); + return 1; + } + + fdcount = atoi(getenv("LISTEN_FDS")); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { + if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { + return fd; + } + } + + return -1; +} + static apr_status_t alloc_systemd_listener(process_rec * process, - int fd, + int fd, const char *proto, ap_listen_rec **out_rec) { apr_status_t rv; @@ -332,37 +359,22 @@ static apr_status_t alloc_systemd_listener(process_rec * process, return rv; } - if (rec->bind_addr->port == 443) { - rec->protocol = apr_pstrdup(process->pool, "https"); - } else { - rec->protocol = apr_pstrdup(process->pool, "http"); - } + rec->protocol = apr_pstrdup(process->pool, proto); *out_rec = rec; return make_sock(process->pool, rec, 0); } -static int open_systemd_listeners(process_rec *process) +static const char *set_systemd_listener(process_rec *process, apr_port_t port, + const char *proto) { ap_listen_rec *last, *new; - int fdcount, fd; apr_status_t rv; - void *data; - const char *userdata_key = "ap_systemd_listeners"; - int sdc = sd_listen_fds(0); - - if (sdc < 0) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) - "open_systemd_listeners: Error parsing enviroment, sd_listen_fds returned %d", - sdc); - return 1; - } - - if (sdc == 0) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) - "open_systemd_listeners: At least one socket must be set."); - return 1; + int fd = find_systemd_socket(process, port); + if (fd < 0) { + return "Systemd socket activation is used, but this port is not " + "configured in systemd"; } last = ap_listeners; @@ -370,40 +382,20 @@ static int open_systemd_listeners(process_rec *process) last = last->next; } - fdcount = atoi(getenv("LISTEN_FDS")); - - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { - rv = alloc_systemd_listener(process, fd, &new); - - if (rv != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02488) - "open_systemd_listeners: failed to setup socket %d.", fd); - return 1; - } - - if (last == NULL) { - ap_listeners = last = new; - } - else { - last->next = new; - last = new; - } + rv = alloc_systemd_listener(process, fd, proto, &new); + if (rv != APR_SUCCESS) { + return "Failed to setup socket passed by systemd using socket activation"; } - /* clear the enviroment on our second run - * so that none of our future children get confused. - */ - apr_pool_userdata_get(&data, userdata_key, process->pool); - if (!data) { - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, process->pool); - } - else { - sd_listen_fds(1); - } - + if (last == NULL) { + ap_listeners = last = new; + } + else { + last->next = new; + last = new; + } - return 0; + return NULL; } #endif /* HAVE_SYSTEMD */ @@ -774,9 +766,19 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) #ifdef HAVE_SYSTEMD if (use_systemd) { - if (open_systemd_listeners(s->process) != 0) { - return 0; + const char *userdata_key = "ap_open_systemd_listeners"; + void *data; + /* clear the enviroment on our second run + * so that none of our future children get confused. + */ + apr_pool_userdata_get(&data, userdata_key, s->process->pool); + if (!data) { + apr_pool_userdata_set((const void *)1, userdata_key, + apr_pool_cleanup_null, s->process->pool); } + else { + sd_listen_fds(1); + } } else #endif @@ -860,8 +862,8 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, if (use_systemd) { int thesock; apr_os_sock_get(&thesock, lr->sd); - if ((stat = alloc_systemd_listener(s->process, thesock, &duplr)) - != APR_SUCCESS) { + if ((stat = alloc_systemd_listener(s->process, thesock, + lr->protocol, &duplr)) != APR_SUCCESS) { return stat; } } @@ -1012,22 +1014,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, if (argc < 1 || argc > 2) { return "Listen requires 1 or 2 arguments."; } - - if (strcmp("systemd", argv[0]) == 0) { #ifdef HAVE_SYSTEMD - use_systemd = 1; - if (ap_listeners != NULL) { - return "systemd socket activation support must be used exclusive of normal listeners."; - } - return NULL; -#else - return "systemd support was not compiled in."; -#endif - } - -#ifdef HAVE_SYSTEMD - if (use_systemd) { - return "systemd socket activation support must be used exclusive of normal listeners."; + if (use_systemd == -1) { + use_systemd = sd_listen_fds(0) > 0; } #endif @@ -1065,6 +1054,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, ap_str_tolower(proto); } +#ifdef HAVE_SYSTEMD + if (use_systemd) { + return set_systemd_listener(cmd->server->process, port, proto); + } +#endif + return alloc_listener(cmd->server->process, host, port, proto, scope_id, NULL, cmd->temp_pool); } From dd11e3b5491edd939c276850e488caeb2117d671 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 12 Apr 2022 15:43:04 +0000 Subject: [PATCH 06/10] Remove libsystemd dependency from main httpd binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until this change httpd was linking libsystemd to the main httpd binary. If you want to run lightweight version of httpd in container, sometimes you just want to install httpd binary with as little dependencies as possible to make container small in size and do not pull uncencessary dependencies and libraries. This change will move all systemd library calls from listen.c to mod_systemd module and remove systemd linking from the main httpd bin. Fixed mixed declaration and wrongly declared variable. Submitted by: Luboš Uhliarik Github: closes #312 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1899784 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit db0631ed09566c81d651b4a51401ea0d61b1e986) --- changes-entries/systemd_socket_activation.txt | 3 + include/ap_listen.h | 10 ++++ modules/arch/unix/mod_systemd.c | 40 +++++++++++++ server/listen.c | 59 +++++++++---------- 4 files changed, 80 insertions(+), 32 deletions(-) create mode 100644 changes-entries/systemd_socket_activation.txt diff --git a/changes-entries/systemd_socket_activation.txt b/changes-entries/systemd_socket_activation.txt new file mode 100644 index 00000000000..8da9f4460a2 --- /dev/null +++ b/changes-entries/systemd_socket_activation.txt @@ -0,0 +1,3 @@ + *) mod_systemd: Systemd socket activation can now be enabled at + build time but disabled at run time, if mod_systemd is not + loaded. [Lubos Uhliarik ] diff --git a/include/ap_listen.h b/include/ap_listen.h index 58c2574ff40..d5ed9685c54 100644 --- a/include/ap_listen.h +++ b/include/ap_listen.h @@ -29,6 +29,7 @@ #include "apr_network_io.h" #include "httpd.h" #include "http_config.h" +#include "apr_optional.h" #ifdef __cplusplus extern "C" { @@ -143,6 +144,15 @@ AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, void *dummy, const char *arg); +#ifdef HAVE_SYSTEMD +APR_DECLARE_OPTIONAL_FN(int, + ap_find_systemd_socket, (process_rec *, apr_port_t)); + +APR_DECLARE_OPTIONAL_FN(int, + ap_systemd_listen_fds, (int)); +#endif + + #define LISTEN_COMMANDS \ AP_INIT_TAKE1("ListenBacklog", ap_set_listenbacklog, NULL, RSRC_CONF, \ "Maximum length of the queue of pending connections, as used by listen(2)"), \ diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c index c3e7082df1f..6439a5c8ef9 100644 --- a/modules/arch/unix/mod_systemd.c +++ b/modules/arch/unix/mod_systemd.c @@ -34,6 +34,12 @@ #include #endif +APR_DECLARE_OPTIONAL_FN(int, + ap_find_systemd_socket, (process_rec *, apr_port_t)); + +APR_DECLARE_OPTIONAL_FN(int, + ap_systemd_listen_fds, (int)); + static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { @@ -96,8 +102,42 @@ static int systemd_monitor(apr_pool_t *p, server_rec *s) return DECLINED; } +static int ap_find_systemd_socket(process_rec * process, apr_port_t port) { + int fdcount, fd; + int sdc = sd_listen_fds(0); + + if (sdc < 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) + "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", + sdc); + return -1; + } + + if (sdc == 0) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) + "find_systemd_socket: At least one socket must be set."); + return -1; + } + + fdcount = atoi(getenv("LISTEN_FDS")); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { + if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { + return fd; + } + } + + return -1; +} + +static int ap_systemd_listen_fds(int unset_environment){ + return sd_listen_fds(unset_environment); +} + static void systemd_register_hooks(apr_pool_t *p) { + APR_REGISTER_OPTIONAL_FN(ap_systemd_listen_fds); + APR_REGISTER_OPTIONAL_FN(ap_find_systemd_socket); + /* Enable ap_extended_status. */ ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST); /* Signal service is ready. */ diff --git a/server/listen.c b/server/listen.c index 48dcb9c7375..80cfd1b059d 100644 --- a/server/listen.c +++ b/server/listen.c @@ -283,34 +283,7 @@ static apr_status_t close_listeners_on_exec(void *v) return APR_SUCCESS; } -#ifdef AP_SYSTEMD_SUPPORT - -static int find_systemd_socket(process_rec * process, apr_port_t port) { - int fdcount, fd; - int sdc = sd_listen_fds(0); - - if (sdc < 0) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) - "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", - sdc); - return 1; - } - - if (sdc == 0) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) - "find_systemd_socket: At least one socket must be set."); - return 1; - } - - fdcount = atoi(getenv("LISTEN_FDS")); - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { - if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { - return fd; - } - } - - return -1; -} +#ifdef HAVE_SYSTEMD static apr_status_t alloc_systemd_listener(process_rec * process, int fd, const char *proto, @@ -371,7 +344,16 @@ static const char *set_systemd_listener(process_rec *process, apr_port_t port, { ap_listen_rec *last, *new; apr_status_t rv; - int fd = find_systemd_socket(process, port); + APR_OPTIONAL_FN_TYPE(ap_find_systemd_socket) *find_systemd_socket; + int fd; + + find_systemd_socket = APR_RETRIEVE_OPTIONAL_FN(ap_find_systemd_socket); + + if (!find_systemd_socket) + return "Systemd socket activation is used, but mod_systemd is probably " + "not loaded"; + + fd = find_systemd_socket(process, port); if (fd < 0) { return "Systemd socket activation is used, but this port is not " "configured in systemd"; @@ -397,7 +379,6 @@ static const char *set_systemd_listener(process_rec *process, apr_port_t port, return NULL; } - #endif /* HAVE_SYSTEMD */ /* Returns non-zero if socket address SA matches hostname, port and @@ -737,6 +718,9 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) int num_listeners = 0; const char* proto; int found; +#ifdef HAVE_SYSTEMD + APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds; +#endif for (ls = s; ls; ls = ls->next) { proto = ap_get_server_protocol(ls); @@ -777,7 +761,10 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) apr_pool_cleanup_null, s->process->pool); } else { - sd_listen_fds(1); + systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds); + if (systemd_listen_fds != NULL) { + systemd_listen_fds(1); + } } } else @@ -1006,6 +993,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, apr_port_t port; apr_status_t rv; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); +#ifdef HAVE_SYSTEMD + APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds; +#endif if (err != NULL) { return err; @@ -1016,7 +1006,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, } #ifdef HAVE_SYSTEMD if (use_systemd == -1) { - use_systemd = sd_listen_fds(0) > 0; + systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds); + if (systemd_listen_fds != NULL) { + use_systemd = systemd_listen_fds(0) > 0; + } else { + use_systemd = 0; + } } #endif From 6cc39f98dfc17beab137a78b1cb62f16fcb6cefc Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 14 Mar 2024 17:12:17 +0000 Subject: [PATCH 07/10] mod_systemd: Axe APR_OPTIONAL_FN redeclarations to avoid compiler warning. ap_find_systemd_socket() and ap_systemd_listen_fds() are already declared in "ap_listen.h", so just include them. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1916312 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit e343347ab6cc304abd5977d1ab5b287898590e23) --- modules/arch/unix/mod_systemd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c index 6439a5c8ef9..2de1c9befdc 100644 --- a/modules/arch/unix/mod_systemd.c +++ b/modules/arch/unix/mod_systemd.c @@ -18,6 +18,7 @@ #include #include #include "ap_mpm.h" +#include "ap_listen.h" #include #include #include @@ -34,12 +35,6 @@ #include #endif -APR_DECLARE_OPTIONAL_FN(int, - ap_find_systemd_socket, (process_rec *, apr_port_t)); - -APR_DECLARE_OPTIONAL_FN(int, - ap_systemd_listen_fds, (int)); - static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { From 70a09c9e9528c4bcbc298c7472e6c43dcaffe6a1 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 15 Mar 2024 15:26:11 +0000 Subject: [PATCH 08/10] mod_systemd: if SELinux is available and enabled, log the SELinux context at startup, since this may vary when httpd is started via systemd vs being started directly. * modules/arch/unix/mod_systemd.c (systemd_post_config): Do nothing for the pre-config iteration. Log the SELinux context if available. * modules/arch/unix/config5.m4: Detect libselinux. Have at least one CI job build mod_systemd. Github: closes #422 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1916344 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 9b17700660769f8dc8136fd7ffa45c50050f49f2) --- changes-entries/systemd-selinux.patch | 2 ++ modules/arch/unix/config5.m4 | 5 +++++ modules/arch/unix/mod_systemd.c | 27 ++++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 changes-entries/systemd-selinux.patch diff --git a/changes-entries/systemd-selinux.patch b/changes-entries/systemd-selinux.patch new file mode 100644 index 00000000000..154dfbabdbd --- /dev/null +++ b/changes-entries/systemd-selinux.patch @@ -0,0 +1,2 @@ + *) mod_systemd: Log the SELinux context at startup if available and + enabled. [Joe Orton] diff --git a/modules/arch/unix/config5.m4 b/modules/arch/unix/config5.m4 index 3d099f86b75..7ee06663b60 100644 --- a/modules/arch/unix/config5.m4 +++ b/modules/arch/unix/config5.m4 @@ -23,6 +23,11 @@ APACHE_MODULE(systemd, Systemd support, , , no, [ AC_MSG_WARN([Your system does not support systemd.]) enable_systemd="no" else + AC_CHECK_LIB(selinux, is_selinux_enabled, [ + AC_DEFINE(HAVE_SELINUX, 1, [Defined if SELinux is supported]) + APR_ADDTO(MOD_SYSTEMD_LDADD, [-lselinux]) + ]) + APR_ADDTO(MOD_SYSTEMD_LDADD, [$SYSTEMD_LIBS]) fi ]) diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c index 2de1c9befdc..22482fd6bbc 100644 --- a/modules/arch/unix/mod_systemd.c +++ b/modules/arch/unix/mod_systemd.c @@ -29,6 +29,10 @@ #include "scoreboard.h" #include "mpm_common.h" +#ifdef HAVE_SELINUX +#include +#endif + #include "systemd/sd-daemon.h" #if APR_HAVE_UNISTD_H @@ -45,6 +49,20 @@ static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, return OK; } +#ifdef HAVE_SELINUX +static void log_selinux_context(void) +{ + char *con; + + if (is_selinux_enabled() && getcon(&con) == 0) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + APLOGNO(10497) "SELinux is enabled; " + "httpd running as context %s", con); + freecon(con); + } +} +#endif + /* Report the service is ready in post_config, which could be during * startup or after a reload. The server could still hit a fatal * startup error after this point during ap_run_mpm(), so this is @@ -52,9 +70,16 @@ static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, * the TCP ports so new connections will not be rejected. There will * always be a possible async failure event simultaneous to the * service reporting "ready", so this should be good enough. */ -static int systemd_post_config(apr_pool_t *p, apr_pool_t *plog, +static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server) { + if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) + return OK; + +#ifdef HAVE_SELINUX + log_selinux_context(); +#endif + sd_notify(0, "READY=1\n" "STATUS=Configuration loaded.\n"); return OK; From 5ca1cabb0d8b707779712c3eb3ba9f859c52c444 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 17 Aug 2018 16:51:25 +0000 Subject: [PATCH 09/10] Fix a cppcheck warning. Remove some dead code. Updating 'last' is pointless here. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1838271 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit e9d215ef047c24423c7d3caffcbb74d88b95bf3e) --- server/listen.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/listen.c b/server/listen.c index 80cfd1b059d..a39a3b5a238 100644 --- a/server/listen.c +++ b/server/listen.c @@ -370,11 +370,10 @@ static const char *set_systemd_listener(process_rec *process, apr_port_t port, } if (last == NULL) { - ap_listeners = last = new; + ap_listeners = new; } else { last->next = new; - last = new; } return NULL; From 9434236bc33631a0f9ec48ccad31b6eef62c0237 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Tue, 3 Jun 2025 15:12:14 +0000 Subject: [PATCH 10/10] Ensure that ALL fields of the ap_listen_rec structure are initialized alloc_listener initializes more fields in the created ap_listen_rec structure than alloc_systemd_listener as it has more data to add to this structure. Ensure that all fields of the ap_listen_rec structure are initialized at least with 0 as later code using this structure depends on this. Submitted by: jailletc36 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1926091 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 32ebb6bee936690e6682e5fe93192063ce25b9c0) --- server/listen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/listen.c b/server/listen.c index a39a3b5a238..cb7e59eb34c 100644 --- a/server/listen.c +++ b/server/listen.c @@ -313,9 +313,7 @@ static apr_status_t alloc_systemd_listener(process_rec * process, si.type = SOCK_STREAM; si.protocol = APR_PROTO_TCP; - rec = apr_palloc(process->pool, sizeof(ap_listen_rec)); - rec->active = 0; - rec->next = 0; + rec = apr_pcalloc(process->pool, sizeof(ap_listen_rec)); rv = apr_os_sock_make(&rec->sd, &si, process->pool);