]> granicus.if.org Git - apache/commitdiff
core: Disallow multiple Listen on the same IP:port when listener buckets
authorYann Ylavic <ylavic@apache.org>
Tue, 28 Mar 2017 20:53:07 +0000 (20:53 +0000)
committerYann Ylavic <ylavic@apache.org>
Tue, 28 Mar 2017 20:53:07 +0000 (20:53 +0000)
are configured (ListenCoresBucketsRatio > 0), consistently with the single
bucket case (default), thus fixing the leak of the corresponding socket
descriptors on graceful restart.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1789213 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
server/listen.c

diff --git a/CHANGES b/CHANGES
index ca67dd5209e7eaa30e528f21a2b512eedaeb969b..677ffd4cc5611780ba39d0eae64e6ab5dad8ef63 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,11 @@
 
 Changes with Apache 2.4.26
 
+  *) core: Disallow multiple Listen on the same IP:port when listener buckets
+     are configured (ListenCoresBucketsRatio > 0), consistently with the single
+     bucket case (default), thus fixing the leak of the corresponding socket
+     descriptors on graceful restart.  [Yann Ylavic]
+
   *) mod_cache: Fix a regression in 2.4.25 for the forward proxy case by
      computing and using the same entity key according to when the cache
      checks, loads and saves the request.
index d44c7c9f44ce0e05c908b6c0de526d6646fc7ab3..a8e9e6f6e3406561af9cf03c2da2ac9b22667b74 100644 (file)
@@ -277,18 +277,14 @@ static apr_status_t close_listeners_on_exec(void *v)
     return APR_SUCCESS;
 }
 
-static const char *alloc_listener(process_rec *process, char *addr,
-                                  apr_port_t port, const char* proto,
-                                  void *slave)
+static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
+                          const char *addr, apr_port_t port)
 {
-    ap_listen_rec **walk, *last;
-    apr_status_t status;
-    apr_sockaddr_t *sa;
-    int found_listener = 0;
+    int found = 0;
+
+    while (*from) {
+        apr_sockaddr_t *sa = (*from)->bind_addr;
 
-    /* see if we've got an old listener for this address:port */
-    for (walk = &old_listeners; *walk;) {
-        sa = (*walk)->bind_addr;
         /* Some listeners are not real so they will not have a bind_addr. */
         if (sa) {
             ap_listen_rec *new;
@@ -301,19 +297,39 @@ static const char *alloc_listener(process_rec *process, char *addr,
             if (port == oldport &&
                 ((!addr && !sa->hostname) ||
                  ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
-                new = *walk;
-                *walk = new->next;
-                new->next = ap_listeners;
-                ap_listeners = new;
-                found_listener = 1;
+                found = 1;
+                if (!to) {
+                    break;
+                }
+                new = *from;
+                *from = new->next;
+                new->next = *to;
+                *to = new;
                 continue;
             }
         }
 
-        walk = &(*walk)->next;
+        from = &(*from)->next;
+    }
+
+    return found;
+}
+
+static const char *alloc_listener(process_rec *process, const char *addr,
+                                  apr_port_t port, const char* proto,
+                                  void *slave)
+{
+    ap_listen_rec *last;
+    apr_status_t status;
+    apr_sockaddr_t *sa;
+
+    /* see if we've got a listener for this address:port, which is an error */
+    if (find_listeners(&ap_listeners, NULL, addr, port)) {
+        return "Cannot define multiple Listeners on the same IP:port";
     }
 
-    if (found_listener) {
+    /* see if we've got an old listener for this address:port */
+    if (find_listeners(&old_listeners, &ap_listeners, addr, port)) {
         if (ap_listeners->slave != slave) {
             return "Cannot define a slave on the same IP:port as a Listener";
         }