From 572a5df9ee47a39d346a4f6b7cd76f6a8804d63f Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Jul 08 2014 13:52:58 +0000 Subject: add support for systemd socket activation (#1111648) --- diff --git a/10-listen443.conf b/10-listen443.conf new file mode 100644 index 0000000..7e2df97 --- /dev/null +++ b/10-listen443.conf @@ -0,0 +1,5 @@ +# This file is part of mod_ssl. It enables listening on port 443 when +# socket activation is used. + +[Socket] +ListenStream=443 diff --git a/httpd-2.4.9-socket-activation.patch b/httpd-2.4.9-socket-activation.patch new file mode 100644 index 0000000..87397f9 --- /dev/null +++ b/httpd-2.4.9-socket-activation.patch @@ -0,0 +1,338 @@ +diff --git a/configure.in b/configure.in +index 19a5f88..a2cd821 100644 +--- a/configure.in ++++ b/configure.in +@@ -509,6 +509,19 @@ if test "$ac_cv_struct_tm_gmtoff" = "yes"; then + AC_DEFINE(HAVE_GMTOFF, 1, [Define if struct tm has a tm_gmtoff field]) + fi + ++dnl Check for systemd support for listen.c's socket activation. ++case $host in ++*-linux-*) ++ AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") ++ AC_CHECK_HEADERS(systemd/sd-daemon.h) ++ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then ++ AC_MSG_WARN([Your system does not support systemd.]) ++ else ++ APR_ADDTO(LIBS, $SYSTEMD_LIBS) ++ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported]) ++ fi ++esac ++ + dnl ## Set up any appropriate OS-specific environment variables for apachectl + + case $host in +diff --git a/modules/arch/unix/config5.m4 b/modules/arch/unix/config5.m4 +index 0b89435..a08550a 100644 +--- a/modules/arch/unix/config5.m4 ++++ b/modules/arch/unix/config5.m4 +@@ -22,7 +22,7 @@ APACHE_MODULE(privileges, Per-virtualhost Unix UserIDs and enhanced security for + APACHE_MODULE(systemd, Systemd support, , , $unixd_mods_enabled, [ + 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 ++ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then + AC_MSG_WARN([Your system does not support systemd.]) + enable_systemd="no" + else +diff --git a/server/listen.c b/server/listen.c +index 7950a10..428fa5e 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -28,6 +28,10 @@ + #include "http_log.h" + #include "mpm_common.h" + ++#ifdef HAVE_SYSTEMD ++#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 HAVE_SYSTEMD ++static int use_systemd = -1; ++#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,124 @@ static apr_status_t close_listeners_on_exec(void *v) + return APR_SUCCESS; + } + ++ ++#ifdef HAVE_SYSTEMD ++ ++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, const char *proto, ++ ap_listen_rec **out_rec) ++{ ++ apr_status_t rv; ++ struct sockaddr sa; ++ socklen_t len = sizeof(struct sockaddr); ++ 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.local = &sa; ++ 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; ++ } ++ ++ rec->protocol = apr_pstrdup(process->pool, proto); ++ ++ *out_rec = rec; ++ ++ return make_sock(process->pool, rec, 0); ++} ++ ++static const char *set_systemd_listener(process_rec *process, apr_port_t port, ++ const char *proto) ++{ ++ ap_listen_rec *last, *new; ++ apr_status_t rv; ++ 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; ++ while (last && last->next) { ++ last = last->next; ++ } ++ ++ rv = alloc_systemd_listener(process, fd, proto, &new); ++ if (rv != APR_SUCCESS) { ++ return "Failed to setup socket passed by systemd using socket activation"; ++ } ++ ++ if (last == NULL) { ++ ap_listeners = last = new; ++ } ++ else { ++ last->next = new; ++ last = new; ++ } ++ ++ return NULL; ++} ++ ++#endif /* HAVE_SYSTEMD */ ++ + static const char *alloc_listener(process_rec *process, char *addr, + apr_port_t port, const char* proto, + void *slave) +@@ -441,7 +568,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 +684,29 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + } + } + +- if (open_listeners(s->process->pool)) { +- return 0; ++ ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ 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 ++ { ++ if (open_listeners(s->process->pool)) { ++ return 0; ++ } + } + + for (lr = ap_listeners; lr; lr = lr->next) { +@@ -591,6 +739,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; +@@ -630,6 +779,11 @@ 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."; + } ++#ifdef HAVE_SYSTEMD ++ if (use_systemd == -1) { ++ use_systemd = sd_listen_fds(0) > 0; ++ } ++#endif + + rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); + if (rv != APR_SUCCESS) { +@@ -661,6 +815,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, NULL); + } + diff --git a/httpd.socket b/httpd.socket new file mode 100644 index 0000000..5858a7f --- /dev/null +++ b/httpd.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Apache httpd Server Socket + +[Socket] +ListenStream=80 + +[Install] +WantedBy=sockets.target diff --git a/httpd.spec b/httpd.spec index 4895a3f..92d845e 100644 --- a/httpd.spec +++ b/httpd.spec @@ -14,7 +14,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.9 -Release: 7%{?dist} +Release: 8%{?dist} URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -41,6 +41,8 @@ Source22: welcome.conf Source23: manual.conf Source24: 00-systemd.conf Source25: 01-session.conf +Source26: 10-listen443.conf +Source27: httpd.socket # Documentation Source30: README.confd Source31: README.confmod @@ -63,6 +65,7 @@ Patch30: httpd-2.4.4-cachehardmax.patch Patch31: httpd-2.4.6-sslmultiproxy.patch Patch32: httpd-2.4.7-r1537535.patch Patch33: httpd-2.4.9-r1573626.patch +Patch34: httpd-2.4.9-socket-activation.patch # Bug fixes Patch55: httpd-2.4.4-malformed-host.patch Patch56: httpd-2.4.4-mod_unique_id.patch @@ -200,6 +203,7 @@ interface for storing and accessing per-user session data. %patch31 -p1 -b .sslmultiproxy %patch32 -p1 -b .r1537535 %patch33 -p1 -b .r1573626 +%patch34 -p1 -b .socketactivation %patch55 -p1 -b .malformedhost %patch56 -p1 -b .uniqueid @@ -282,9 +286,9 @@ make DESTDIR=$RPM_BUILD_ROOT install # Install systemd service files mkdir -p $RPM_BUILD_ROOT%{_unitdir} -for s in httpd htcacheclean; do - install -p -m 644 $RPM_SOURCE_DIR/${s}.service \ - $RPM_BUILD_ROOT%{_unitdir}/${s}.service +for s in httpd.service htcacheclean.service httpd.socket; do + install -p -m 644 $RPM_SOURCE_DIR/${s} \ + $RPM_BUILD_ROOT%{_unitdir}/${s} done # install conf file/directory @@ -305,6 +309,10 @@ done # Web application packages can drop snippets into this location if # they need ExecStart[pre|post]. mkdir $RPM_BUILD_ROOT%{_unitdir}/httpd.service.d +mkdir $RPM_BUILD_ROOT%{_unitdir}/httpd.socket.d + +install -m 644 -p $RPM_SOURCE_DIR/10-listen443.conf \ + $RPM_BUILD_ROOT%{_unitdir}/httpd.socket.d/10-listen443.conf for f in welcome.conf ssl.conf manual.conf userdir.conf; do install -m 644 -p $RPM_SOURCE_DIR/$f \ @@ -445,10 +453,10 @@ rm -rf $RPM_BUILD_ROOT/etc/httpd/conf/{original,extra} -s /sbin/nologin -r -d %{contentdir} apache 2> /dev/null || : %post -%systemd_post httpd.service htcacheclean.service +%systemd_post httpd.service htcacheclean.service httpd.socket %preun -%systemd_preun httpd.service htcacheclean.service +%systemd_preun httpd.service htcacheclean.service httpd.socket %postun %systemd_postun @@ -575,7 +583,9 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/* %{_unitdir}/*.service +%{_unitdir}/*.socket %attr(755,root,root) %dir %{_unitdir}/httpd.service.d +%attr(755,root,root) %dir %{_unitdir}/httpd.socket.d %files filesystem %dir %{_sysconfdir}/httpd @@ -607,6 +617,7 @@ rm -rf $RPM_BUILD_ROOT %config(noreplace) %{_sysconfdir}/httpd/conf.d/ssl.conf %attr(0700,apache,root) %dir %{_localstatedir}/cache/httpd/ssl %{_libexecdir}/httpd-ssl-pass-dialog +%{_unitdir}/httpd.socket.d/10-listen443.conf %files -n mod_proxy_html %defattr(-,root,root) @@ -636,6 +647,9 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Tue Jul 08 2014 Jan Kaluza - 2.4.9-8 +- add support for systemd socket activation (#1111648) + * Mon Jul 07 2014 Jan Kaluza - 2.4.9-7 - remove conf.modules.d from httpd-filesystem subpackage (#1081453)