On Sun, Aug 24, 2003 at 04:31:07AM +0100, Colm MacCarthaigh wrote:
> So, attachted is a best-effort patch which should solve the 
> problems.

Bah, it's always the way, 2 minutes after testing and then mailing
a patch I realise there's a small slip-up. Patch without the
stupid-obvious-bug attached :)

-- 
Colm MacCárthaigh                        Public Key: [EMAIL PROTECTED]
[EMAIL PROTECTED]                                         http://www.stdlib.net/
Index: server/listen.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/listen.c,v
retrieving revision 1.89
diff -u -r1.89 listen.c
--- server/listen.c     15 Aug 2003 02:25:41 -0000      1.89
+++ server/listen.c     24 Aug 2003 03:35:56 -0000
@@ -306,8 +306,15 @@
             return "Listen setup failed";
         }
 
-        new->next = ap_listeners;
-        ap_listeners = new;
+        /* We need to preserve the order returned by getaddrinfo() */
+        if (ap_listeners == NULL ) {
+            ap_listeners = new;
+        } else {
+            while(ap_listeners->next) {
+                ap_listeners = ap_listeners->next;
+            } 
+            ap_listeners->next = new;
+        }
     }
 
     return NULL;
@@ -317,6 +324,7 @@
 {
     ap_listen_rec *lr;
     ap_listen_rec *next;
+    ap_listen_rec *previous;
     int num_open;
     const char *userdata_key = "ap_listen_open";
     void *data;
@@ -326,16 +334,64 @@
      * config file.
      */
     num_open = 0;
-    for (lr = ap_listeners; lr; lr = lr->next) {
+    previous = NULL;
+    for (lr = ap_listeners; lr; previous = lr, lr = lr->next) {
         if (lr->active) {
             ++num_open;
         }
         else {
+#if APR_HAVE_IPV6  
+            int v6only_setting;
+            /* If we are trying to bind to 0.0.0.0 and the previous listener
+             * was :: on the same port and in turn that socket does not have
+             * the IPV6_V6ONLY flag set; we must skip the current attempt to
+             * listen (which would generate an error). IPv4 will be handled 
+             * on the established IPv6 socket.
+             */
+            if (previous != NULL && 
+                lr->bind_addr->family == APR_INET &&
+                *((in_addr_t *)lr->bind_addr->ipaddr_ptr) == INADDR_ANY &&
+                lr->bind_addr->port == previous->bind_addr->port && 
+                previous->bind_addr->family == APR_INET6 &&
+                IN6_IS_ADDR_UNSPECIFIED(previous->bind_addr->ipaddr_ptr) &&
+                apr_socket_opt_get(previous->sd, APR_IPV6_V6ONLY, 
+                                   &v6only_setting) == APR_SUCCESS && 
+                v6only_setting == 0) {
+
+                /* Remove the current listener from the list */
+                previous->next = lr->next;
+                continue;
+            }
+#endif
             if (make_sock(pool, lr) == APR_SUCCESS) {
                 ++num_open;
                 lr->active = 1;
             }
             else {
+#if APR_HAVE_IPV6  
+                /* If we tried to bind to ::, and the next listener is 
+                 * on 0.0.0.0 with the same port, don't give a fatal
+                 * error. The user will still get a warning from make_sock
+                 * though.
+                 */
+                if (lr->next != NULL && lr->bind_addr->family == APR_INET6 &&
+                    IN6_IS_ADDR_UNSPECIFIED(previous->bind_addr->ipaddr_ptr) &&
+                    lr->bind_addr->port == lr->next->bind_addr->port &&
+                    *((in_addr_t *)lr->next->bind_addr->ipaddr_ptr) 
+                    == INADDR_ANY) {
+
+                    /* Remove the current listener from the list */
+                    if (previous)
+                        previous->next = lr->next;
+                    else 
+                        ap_listeners = lr->next;   
+
+                    /* So that previous becomes NULL in the next iteration */
+                    lr = NULL;
+
+                    continue;
+                }
+#endif
                 /* fatal error */
                 return -1;
             }

Reply via email to