Bug 387954 – fix NT version of PR_Accept on IPv6 listen socket. r=wtc
authornelson%bolyard.com
Wed, 25 Jul 2007 06:45:08 +0000
changeset 3852 d758704ea8e4b18960300ca11766dfd08031f62a
parent 3851 ebeb2c3a63b9e387bcfe4a36814bda340e9bfec3
child 3855 3f940533d93a9047c7aab5cc85658e9a2f6d5e29
push idunknown
push userunknown
push dateunknown
reviewerswtc
bugs387954
Bug 387954 – fix NT version of PR_Accept on IPv6 listen socket. r=wtc
pr/include/md/_openvms.h
pr/include/md/_winnt.h
pr/include/private/primpl.h
pr/src/io/prsocket.c
pr/src/md/windows/ntio.c
pr/src/pthreads/ptio.c
--- a/pr/include/md/_openvms.h
+++ b/pr/include/md/_openvms.h
@@ -96,16 +96,17 @@ struct ip_mreq {
 #define HAVE_DLL
 #define USE_DLFCN
 
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ONLY_ST_ATIME
 #define _PR_NO_LARGE_FILES
 #define _PR_STRICT_ADDR_LEN
+#define _PR_NEED_SECRET_AF
 
 /* IPv6 support */
 #ifdef _SOCKADDR_LEN
 #define _PR_HAVE_SOCKADDR_LEN
 #endif
 #define _PR_HAVE_GETIPNODEBYNAME
 #define _PR_HAVE_GETIPNODEBYADDR
 #define _PR_HAVE_GETADDRINFO
--- a/pr/include/md/_winnt.h
+++ b/pr/include/md/_winnt.h
@@ -119,16 +119,17 @@ struct _md_sockaddr_in6 {
 #if defined(_M_IX86) || defined(_X86_)
 #define _PR_HAVE_ATOMIC_CAS
 #endif
 #define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
 #define _PR_HAVE_PEEK_BUFFER
 #define _PR_PEEK_BUFFER_MAX (32 * 1024)
 #define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) \
     (!(fd)->secret->nonblocking && (fd)->secret->inheritable != _PR_TRI_TRUE)
+#define _PR_NEED_SECRET_AF
 
 /* --- Common User-Thread/Native-Thread Definitions --------------------- */
 
 /* --- Globals --- */
 extern struct PRLock                      *_pr_schedLock;
 
 /* --- Typedefs --- */
 typedef void (*FiberFunc)(void *);
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -1740,22 +1740,20 @@ struct PRFilePrivate {
 #endif
 #if !defined(_PR_HAVE_O_APPEND)
     PRBool  appendMode; /* Some platforms don't have O_APPEND or its
                          * equivalent, so they have to seek to end of
                          * file on write if the file was opened in
                          * append mode.  See Bugzilla 4090, 276330. */
 #endif
     _MDFileDesc md;
-#ifdef _PR_STRICT_ADDR_LEN
-    PRUint16 af;        /* If the platform requires passing the exact
-                         * length of the sockaddr structure for the
-                         * address family of the socket to socket
-                         * functions like accept(), we need to save
-                         * the address family of the socket. */
+#ifdef _PR_NEED_SECRET_AF
+    PRUint16 af;        /* If the platform's implementation of accept()
+                         * requires knowing the address family of the 
+			 * socket, we save the address family here. */
 #endif
 };
 
 #ifdef _WIN64
 #define PR_PRIdOSFD "lld"       /* for printing PROsfd */
 #define PR_PRIxOSFD "llx"
 #define PR_SCNdOSFD "lld"       /* for scanning PROsfd */
 #define PR_SCNxOSFD "llx"
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -194,16 +194,23 @@ PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPS
 {
 PRFileDesc *fd;
 
 	if (!_pr_initialized) _PR_ImplicitInitialization();
 	fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 	if (fd != NULL) {
 		_PR_MD_MAKE_NONBLOCK(fd);
 		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+#ifdef _PR_NEED_SECRET_AF
+		/* this means we can only import IPv4 sockets here.
+		 * but this is what the function in ptio.c does.
+		 * We need a way to import IPv6 sockets, too.
+		 */
+		fd->secret->af = AF_INET;
+#endif
 	} else
 		_PR_MD_CLOSE_SOCKET(osfd);
 	return(fd);
 }
 
 PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd)
 {
 PRFileDesc *fd;
@@ -509,16 +516,19 @@ PRIntervalTime timeout)
 		fd2->secret->md.io_model_committed = PR_TRUE;
 	        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
         	fd2->secret->md.accepted_socket = PR_TRUE;
         	memcpy(&fd2->secret->md.peer_addr, addr, al);
 #ifdef _PR_INET6
 		if (AF_INET6 == addr->raw.family)
         	addr->raw.family = PR_AF_INET6;
 #endif
+#ifdef _PR_NEED_SECRET_AF
+		fd2->secret->af = fd->secret->af;
+#endif
 	}
 	return fd2;
 }
 #endif /* WINNT */
 
 
 static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
 {
@@ -939,16 +949,19 @@ PRIntervalTime timeout)
 			(*nd)->secret->md.io_model_committed = PR_TRUE;
 			(*nd)->secret->md.accepted_socket = PR_TRUE;
 			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
 				PR_NETADDR_SIZE(*raddr));
 #ifdef _PR_INET6
 			if (AF_INET6 == *raddr->raw.family)
         		*raddr->raw.family = PR_AF_INET6;
 #endif
+#ifdef _PR_NEED_SECRET_AF
+			(*nd)->secret->af = sd->secret->af;
+#endif
 		}
 	}
 	return rv;
 }
 
 PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
 PRFileDesc *sd, PRFileDesc **nd, 
 PRNetAddr **raddr, void *buf, PRInt32 amount,
@@ -990,16 +1003,19 @@ void *callbackArg)
 			(*nd)->secret->md.io_model_committed = PR_TRUE;
 			(*nd)->secret->md.accepted_socket = PR_TRUE;
 			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
 				PR_NETADDR_SIZE(*raddr));
 #ifdef _PR_INET6
 			if (AF_INET6 == *raddr->raw.family)
         		*raddr->raw.family = PR_AF_INET6;
 #endif
+#ifdef _PR_NEED_SECRET_AF
+			(*nd)->secret->af = sd->secret->af;
+#endif
 		}
 	}
 	return rv;
 }
 #endif /* WINNT */
 
 #ifdef WINNT
 PR_IMPLEMENT(void)
@@ -1320,16 +1336,19 @@ PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRIn
 		 */
 		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
 			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
 				PR_Close(fd);
 				fd = NULL;
 			}
 		}
 #endif
+#ifdef _PR_NEED_SECRET_AF
+		fd->secret->af = domain;
+#endif
 	} else
 		_PR_MD_CLOSE_SOCKET(osfd);
 
 	return fd;
 }
 
 PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
 {
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -59,18 +59,20 @@
 #include <direct.h>
 #include <mbstring.h>
 
 static HANDLE                _pr_completion_port;
 static PRThread             *_pr_io_completion_thread;
 
 #define RECYCLE_SIZE 512
 static struct _MDLock        _pr_recycle_lock;
-static PRInt32               _pr_recycle_array[RECYCLE_SIZE];
-static PRInt32               _pr_recycle_tail = 0; 
+static PRInt32               _pr_recycle_INET_array[RECYCLE_SIZE];
+static PRInt32               _pr_recycle_INET_tail = 0; 
+static PRInt32               _pr_recycle_INET6_array[RECYCLE_SIZE];
+static PRInt32               _pr_recycle_INET6_tail = 0; 
 
 __declspec(thread) PRThread *_pr_io_restarted_io = NULL;
 DWORD _pr_io_restartedIOIndex;  /* The thread local storage slot for each
                                  * thread is initialized to NULL. */
 
 PRBool                       _nt_version_gets_lockfile_completion;
 
 struct _MDLock               _pr_ioq_lock;
@@ -960,25 +962,30 @@ void
 /* --- SOCKET IO --------------------------------------------------------- */
 
 /* _md_get_recycled_socket()
  * Get a socket from the recycle bin; if no sockets are in the bin,
  * create one.  The socket will be passed to AcceptEx() as the
  * second argument.
  */
 static SOCKET
-_md_get_recycled_socket()
+_md_get_recycled_socket(int af)
 {
     SOCKET rv;
-    int af = AF_INET;
 
     _MD_LOCK(&_pr_recycle_lock);
-    if (_pr_recycle_tail) {
-        _pr_recycle_tail--;
-        rv = _pr_recycle_array[_pr_recycle_tail];
+    if (af == AF_INET && _pr_recycle_INET_tail) {
+        _pr_recycle_INET_tail--;
+        rv = _pr_recycle_INET_array[_pr_recycle_INET_tail];
+        _MD_UNLOCK(&_pr_recycle_lock);
+        return rv;
+    }
+    if (af == AF_INET6 && _pr_recycle_INET6_tail) {
+        _pr_recycle_INET6_tail--;
+        rv = _pr_recycle_INET6_array[_pr_recycle_INET6_tail];
         _MD_UNLOCK(&_pr_recycle_lock);
         return rv;
     }
     _MD_UNLOCK(&_pr_recycle_lock);
 
     rv = _PR_MD_SOCKET(af, SOCK_STREAM, 0);
     if (rv != INVALID_SOCKET && _md_Associate((HANDLE)rv) == 0) {
         closesocket(rv);
@@ -986,24 +993,29 @@ static SOCKET
     }
     return rv;
 }
 
 /* _md_put_recycled_socket()
  * Add a socket to the recycle bin.
  */
 static void
-_md_put_recycled_socket(SOCKET newsock)
+_md_put_recycled_socket(SOCKET newsock, int af)
 {
-    PR_ASSERT(_pr_recycle_tail >= 0);
+    PR_ASSERT(_pr_recycle_INET_tail >= 0);
+    PR_ASSERT(_pr_recycle_INET6_tail >= 0);
 
     _MD_LOCK(&_pr_recycle_lock);
-    if (_pr_recycle_tail < RECYCLE_SIZE) {
-        _pr_recycle_array[_pr_recycle_tail] = newsock;
-        _pr_recycle_tail++;
+    if (af == AF_INET && _pr_recycle_INET_tail < RECYCLE_SIZE) {
+        _pr_recycle_INET_array[_pr_recycle_INET_tail] = newsock;
+        _pr_recycle_INET_tail++;
+        _MD_UNLOCK(&_pr_recycle_lock);
+    } else if (af == AF_INET6 && _pr_recycle_INET6_tail < RECYCLE_SIZE) {
+        _pr_recycle_INET6_array[_pr_recycle_INET6_tail] = newsock;
+        _pr_recycle_INET6_tail++;
         _MD_UNLOCK(&_pr_recycle_lock);
     } else {
         _MD_UNLOCK(&_pr_recycle_lock);
         closesocket(newsock);
     }
  
     return;
 }
@@ -1322,17 +1334,17 @@ PROsfd
     if (!me->md.acceptex_buf) {
         me->md.acceptex_buf = PR_MALLOC(2*INET_ADDR_PADDED);
         if (!me->md.acceptex_buf) {
             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
             return -1;
         }
     }
 
-    accept_sock = _md_get_recycled_socket();
+    accept_sock = _md_get_recycled_socket(fd->secret->af);
     if (accept_sock == INVALID_SOCKET)
         return -1;
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 	if (_native_threads_only)
 		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
 
     _PR_THREAD_LOCK(me);
@@ -1352,17 +1364,17 @@ PROsfd
                   accept_sock,
                   me->md.acceptex_buf,
                   0,
                   INET_ADDR_PADDED,
                   INET_ADDR_PADDED,
                   &bytes,
                   &(me->md.overlapped.overlapped));
 
-    if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING))  {
+    if ( (rv == 0) && ((err = WSAGetLastError()) != ERROR_IO_PENDING))  {
         /* Argh! The IO failed */
 		closesocket(accept_sock);
 		_PR_THREAD_LOCK(me);
 		me->io_pending = PR_FALSE;
 		me->state = _PR_RUNNING;
 		if (_PR_PENDING_INTERRUPT(me)) {
 			me->flags &= ~_PR_INTERRUPT;
 			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
@@ -1445,17 +1457,17 @@ PRInt32
     }
 
     if (!sd->secret->md.io_model_committed) {
         rv = _md_Associate((HANDLE)sock);
         PR_ASSERT(0 != rv);
         sd->secret->md.io_model_committed = PR_TRUE;
     }
 
-    *newSock = _md_get_recycled_socket();
+    *newSock = _md_get_recycled_socket(sd->secret->af);
     if (*newSock == INVALID_SOCKET)
         return -1;
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 	if (_native_threads_only)
 		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
 
     _PR_THREAD_LOCK(me);
@@ -1695,17 +1707,17 @@ PRInt32
     }
 
     if (me->md.blocked_io_status == 0) {
 		_PR_MD_MAP_TRANSMITFILE_ERROR(me->md.blocked_io_error);
         return -1;
     }
 
     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
-        _md_put_recycled_socket(sock->secret->md.osfd);
+        _md_put_recycled_socket(sock->secret->md.osfd, sock->secret->af);
     }
 
     PR_ASSERT(me->io_pending == PR_FALSE);
 
     return me->md.blocked_io_bytes;
 }
 
 PRInt32
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -3460,17 +3460,17 @@ PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRIn
             int on = 0;
             (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
                     &on, sizeof(on));
         }
 #endif
         fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
         if (fd == NULL) close(osfd);
     }
-#ifdef _PR_STRICT_ADDR_LEN
+#ifdef _PR_NEED_SECRET_AF
     if (fd != NULL) fd->secret->af = domain;
 #endif
 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
 	if (fd != NULL) {
 		/*
 		 * For platforms with no support for IPv6 
 		 * create layered socket for IPv4-mapped IPv6 addresses
 		 */
@@ -4451,17 +4451,17 @@ PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(
 
 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
 {
     PRFileDesc *fd;
 
     if (!_pr_initialized) _PR_ImplicitInitialization();
     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
     if (NULL == fd) close(osfd);
-#ifdef _PR_STRICT_ADDR_LEN
+#ifdef _PR_NEED_SECRET_AF
     if (NULL != fd) fd->secret->af = PF_INET;
 #endif
     return fd;
 }  /* PR_ImportTCPSocket */
 
 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
 {
     PRFileDesc *fd;