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; }