httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jerenkra...@apache.org
Subject cvs commit: httpd-2.0/server listen.c
Date Sun, 24 Aug 2003 22:43:36 GMT
jerenkrantz    2003/08/24 15:43:36

  Modified:    server   listen.c
  Log:
  Fixup IPv6 Listen statements on Linux by attempting to bind in the order
  that getaddrinfo() returned to us and skipping binding to IPv4 addresses
  if the previous bind was to an IPv6 of the same address and port.
  
  Justin made some style changes, added a (struct in6_addr*) to make it compile
  on *BSD as well as an attempt to make the addition of the listener to the list
  a little more efficient.
  
  Submitted by:	Colm MacCarthaigh <colm@stdlib.net>
  Reviewed by:	Justin Erenkrantz
  
  Revision  Changes    Path
  1.90      +69 -4     httpd-2.0/server/listen.c
  
  Index: listen.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/listen.c,v
  retrieving revision 1.89
  retrieving revision 1.90
  diff -u -u -r1.89 -r1.90
  --- listen.c	15 Aug 2003 02:25:41 -0000	1.89
  +++ listen.c	24 Aug 2003 22:43:36 -0000	1.90
  @@ -231,7 +231,7 @@
   
   static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port)
   {
  -    ap_listen_rec **walk;
  +    ap_listen_rec **walk, *last;
       apr_status_t status;
       apr_sockaddr_t *sa;
       int found_listener = 0;
  @@ -276,12 +276,19 @@
           return "Listen setup failed";
       }
   
  +    /* Initialize to our last configured ap_listener. */
  +    last = ap_listeners;
  +    while (last && last->next) {
  +        last = last->next;
  +    }
  +
       while (sa) {
           ap_listen_rec *new;
   
           /* this has to survive restarts */
           new = apr_palloc(process->pool, sizeof(ap_listen_rec));
           new->active = 0;
  +        new->next = 0;
           new->bind_addr = sa;
   
           /* Go to the next sockaddr. */
  @@ -306,8 +313,13 @@
               return "Listen setup failed";
           }
   
  -        new->next = ap_listeners;
  -        ap_listeners = new;
  +        /* We need to preserve the order returned by getaddrinfo() */
  +        if (last == NULL) {
  +            ap_listeners = last = new;
  +        } else {
  +            last->next = new;
  +            last = new;
  +        }
       }
   
       return NULL;
  @@ -317,6 +329,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 +339,68 @@
        * 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(
  +                        (struct in6_addr*)(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(
  +                        (struct in6_addr*)(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;
               }
  
  
  

Mime
View raw message