From: Paul Querna Date: Tue, 6 Aug 2013 16:51:15 +0000 (+0000) Subject: Add support for systemd socket activation to listener sockets. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=61d6714c25661040c012b2f89b2134f0f02c7616;p=thirdparty%2Fapache%2Fhttpd.git 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 --- diff --git a/configure.in b/configure.in index 1332377b6e6..bcde8670785 100644 --- a/configure.in +++ b/configure.in @@ -322,6 +322,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/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index a385b0c6e25..59780dc7b1e 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -2486 +2492 diff --git a/modules/arch/unix/config5.m4 b/modules/arch/unix/config5.m4 index 0deea6b2776..a992ae2813c 100644 --- a/modules/arch/unix/config5.m4 +++ b/modules/arch/unix/config5.m4 @@ -21,8 +21,6 @@ APACHE_MODULE(privileges, Per-virtualhost Unix UserIDs and enhanced security for ]) APACHE_MODULE(systemd, Systemd support, , , all, [ - 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.]) enable_systemd="no" diff --git a/server/listen.c b/server/listen.c index 7950a10039f..7cf2e5f0cf3 100644 --- a/server/listen.c +++ b/server/listen.c @@ -28,6 +28,10 @@ #include "http_log.h" #include "mpm_common.h" +#ifdef AP_SYSTEMD_SUPPORT +#include +#endif + /* we know core's module_index is 0 */ #undef APLOG_MODULE_INDEX #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX @@ -38,9 +42,12 @@ static ap_listen_rec *old_listeners; static int ap_listenbacklog; 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; @@ -73,20 +80,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 @@ -131,21 +124,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) ap_sock_disable_nagle(s); #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 @@ -239,6 +248,131 @@ 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 */ + static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port, const char* proto, void *slave) @@ -441,7 +575,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 { @@ -557,8 +691,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) { @@ -591,6 +736,7 @@ AP_DECLARE_NONSTD(void) ap_close_listeners(void) lr->active = 0; } } + AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *slave) { ap_listen_rec *lr; @@ -631,6 +777,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";