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