Here's a patch to enable IPv6 on Windows XP & 2003. In addition we'll need to change the setting of APR_HAVE_IPV6 in apr.hw - seems like we'll need some awk magic to do that.
Note that enabling IPv6 drags in the need for the XP or 2003 platform SDK but I don't see any way around it. I believe the platform SDK can be freely downloaded from MS for those who want to do an IPv6 build.
Any comments before I commit to 2.1?
Allan
Index: server/mpm/winnt/child.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/mpm/winnt/child.c,v retrieving revision 1.26 diff -u -d -b -r1.26 child.c --- server/mpm/winnt/child.c 9 Feb 2004 20:40:51 -0000 1.26 +++ server/mpm/winnt/child.c 25 Feb 2004 16:20:51 -0000 @@ -314,13 +314,17 @@ int wait_time = 1; int csd; SOCKET nsd = INVALID_SOCKET; - struct sockaddr_in sa_client; int count_select_errors = 0; int rc; int clen; ap_listen_rec *lr; struct fd_set listenfds; SOCKET listenmaxfd = INVALID_SOCKET; +#if APR_HAVE_IPV6 + struct sockaddr_in6 sa_client; +#else + struct sockaddr_in sa_client; +#endif
/* Setup the listeners * ToDo: Use apr_poll() @@ -395,7 +399,13 @@ static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) { apr_os_sock_info_t sockinfo; - int len; + int len, salen; +#if APR_HAVE_IPV6 + salen = sizeof(struct sockaddr_in6); +#else + salen = sizeof(struct sockaddr_in); +#endif +
if (context == NULL) { /* allocate the completion context and the transaction pool */ @@ -415,7 +425,7 @@ if (context->accept_socket == INVALID_SOCKET) { return NULL; } - len = sizeof(struct sockaddr); + len = salen; context->sa_server = apr_palloc(context->ptrans, len); if (getsockname(context->accept_socket, context->sa_server, &len)== SOCKET_ERROR) { @@ -423,7 +433,7 @@ "getsockname failed"); continue; } - len = sizeof(struct sockaddr); + len = salen; context->sa_client = apr_palloc(context->ptrans, len); if ((getpeername(context->accept_socket, context->sa_client, &len)) == SOCKET_ERROR) { @@ -434,7 +444,7 @@ sockinfo.os_sock = &context->accept_socket; sockinfo.local = context->sa_server; sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; + sockinfo.family = context->sa_server->sa_family; sockinfo.type = SOCK_STREAM; apr_os_sock_make(&context->sock, &sockinfo, context->ptrans);
@@ -465,9 +475,21 @@ DWORD BytesRead; SOCKET nlsd; int rv, err_count = 0; +#if APR_HAVE_IPV6 + SOCKADDR_STORAGE ss_listen; + int namelen = sizeof(ss_listen); +#endif
apr_os_sock_get(&nlsd, lr->sd);
+#if APR_HAVE_IPV6 + if (getsockname(nlsd, (struct sockaddr *)&ss_listen, &namelen) == SOCKET_ERROR) { + ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_netos_error(), ap_server_conf, + "winnt_accept: getsockname error on listening socket, is IPv6 available?"); + return; + } +#endif + while (!shutdown_in_progress) { if (!context) { context = mpm_get_completion_context(); @@ -479,6 +501,25 @@ }
/* Create and initialize the accept socket */ +#if APR_HAVE_IPV6 + if (context->accept_socket == INVALID_SOCKET) { + context->accept_socket = socket(ss_listen.ss_family, SOCK_STREAM, IPPROTO_TCP); + context->socket_family = ss_listen.ss_family; + } + else if (context->socket_family != ss_listen.ss_family) { + closesocket(context->accept_socket); + context->accept_socket = socket(ss_listen.ss_family, SOCK_STREAM, IPPROTO_TCP); + context->socket_family = ss_listen.ss_family; + } + + if (context->accept_socket == INVALID_SOCKET) { + ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf, + "winnt_accept: Failed to allocate an accept socket. " + "Temporary resource constraint? Try again."); + Sleep(100); + continue; + } +#else if (context->accept_socket == INVALID_SOCKET) { context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (context->accept_socket == INVALID_SOCKET) { @@ -490,7 +531,7 @@ continue; } } - +#endif /* AcceptEx on the completion context. The completion context will be * signaled when a connection is accepted. */ @@ -607,7 +648,7 @@ sockinfo.os_sock = &context->accept_socket; sockinfo.local = context->sa_server; sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; + sockinfo.family = context->sa_server->sa_family; sockinfo.type = SOCK_STREAM; apr_os_sock_make(&context->sock, &sockinfo, context->ptrans);
Index: server/mpm/winnt/mpm_winnt.h =================================================================== RCS file: /home/cvs/httpd-2.0/server/mpm/winnt/mpm_winnt.h,v retrieving revision 1.48 diff -u -d -b -r1.48 mpm_winnt.h --- server/mpm/winnt/mpm_winnt.h 9 Feb 2004 20:40:51 -0000 1.48 +++ server/mpm/winnt/mpm_winnt.h 25 Feb 2004 16:20:51 -0000 @@ -85,7 +85,12 @@ #define CONTAINING_RECORD(address, type, field) ((type *)( \ (PCHAR)(address) - \ (PCHAR)(&((type *)0)->field))) +#if APR_HAVE_IPV6 +#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN6)+16 +#else #define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 +#endif + typedef struct CompContext { struct CompContext *next; OVERLAPPED Overlapped; @@ -98,6 +103,7 @@ int sa_client_len; apr_pool_t *ptrans; apr_bucket_alloc_t *ba; + short socket_family; } COMP_CONTEXT, *PCOMP_CONTEXT;
typedef enum { Index: srclib/apr/include/apr.hw =================================================================== RCS file: /home/cvs/apr/include/apr.hw,v retrieving revision 1.121 diff -u -d -b -r1.121 apr.hw --- srclib/apr/include/apr.hw 21 Nov 2003 10:42:03 -0000 1.121 +++ srclib/apr/include/apr.hw 25 Feb 2004 16:20:51 -0000 @@ -87,11 +87,12 @@ * C4075: slight indirection changes (unsigned short* vs short[]) * C4100: unreferenced formal parameter * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function * C4201: nonstandard extension nameless struct/unions * C4244: int to char/short - precision loss * C4514: unreferenced inline function removed */ -#pragma warning(disable: 4100 4127 4201 4514; once: 4057 4075 4244) +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244)
/* Has windows.h already been included? If so, our preferences don't matter, * but we will still need the winsock things no matter what was included.