On Tue, Feb 22, 2005 at 10:52:57PM -0800, Justin Erenkrantz wrote:
> No idea why I'm suddenly hitting this, but in preparation for 2.1.3, I 
> spent another one of my patented hours searching for bugs in httpd that end 
> up being bugs in the perl-framework tests.  =(
> 
> perl-framework generates Listen directives in the order of:
> 'Listen 0.0.0.0:8529'
> 
> For me, this causes errors like:
> (48)Address already in use: make_sock: could not bind to address 
> 0.0.0.0:8531
> no listening sockets available, shutting down
> Unable to open logs
> 
> On Mac OS X 10.3.8 (7.8.0 via uname -r), getaddrinfo() without AI_PASSIVE 
> can return duplicate IP addresses.  This leads to the error condition that 
> causes the failure.  And, based on my reading of the docs, I'm not sure 
> that's patently incorrect behavior on Darwin's part: that's 0.0.0.0 for 
> both the localhost and the network card.

But there is no way to differentiate between any different interfaces
for the address (without doing magic), so I would say that is a resolver
misfeature.

"Listen 0.0.0.0:<port>" should always work because there's no other way
to configure httpd to bind only to "all IPv4 addresses on the local host
with port X" (right?), which is certainly a valid and useful thing to
do.

I think httpd should work around this: does something like the attached
work? (tested only to compile ;) Not necessarily the best place to put
this logic.

> The issue with this is that wildcard IP addresses aren't really supposed to 
> be explicit in Listen statements.  httpd has a bunch of logic for inferring 
> the right IP wildcards - trying to out-guess can lead to real badness. 
> Specifically, this mucks with APR's ability to set AI_PASSIVE - which is 
> required for use with address that we will later call bind() on - i.e. our 
> listeners.  So, Listen with an IP address should only be used for real 
> addresses.

The problem was that 2.0.x will only accept connections to IPv6
addresses with a single "Listen <port>"; but since LWP doesn't support
IPv6, that doesn't work for httpd-test.  The alternative is to start
getting complicated but with the different logic in 2.0 and 2.1 I think
it would be better to avoid this.

joe
Index: server/listen.c
===================================================================
--- server/listen.c     (revision 154212)
+++ server/listen.c     (working copy)
@@ -353,6 +353,18 @@
                 continue;
             }
 #endif
+            /* Skip duplicates addresses returned for an AI_PASSIVE
+             * lookup for 0.0.0.0 on Darwin: */
+            if (previous != NULL
+                && lr->bind_addr->family == APR_INET
+                && lr->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY
+                && previous->bind_addr->family == APR_INET
+                && previous->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY
+                && lr->bind_addr->port == previous->bind_addr->port) {
+                previous->next = lr->next;
+                continue;
+            }
+
             if (make_sock(pool, lr) == APR_SUCCESS) {
                 ++num_open;
                 lr->active = 1;

Reply via email to