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;