Redid the NT implementation of PR_NewTCPSocketPair so that neither socket
authorwtc%netscape.com
Fri, 12 Feb 1999 18:46:07 +0000
changeset 444 04fe48432b52728f255a3bcd68a11a09eeb864c2
parent 443 cecf38e5a40b56a516a86f9b56614dca963005c0
child 445 e8081a3284fd60f10d68d6004f4cda8d7f842bcc
push idunknown
push userunknown
push dateunknown
Redid the NT implementation of PR_NewTCPSocketPair so that neither socket is associated with the I/O completion port.
pr/src/io/prsocket.c
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -1193,17 +1193,110 @@ PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPa
 		PR_Close(f[0]);
 		_PR_MD_CLOSE_SOCKET(osfd[1]);
 		/* PR_AllocFileDesc() has invoked PR_SetError(). */
 		return PR_FAILURE;
 	}
 	_PR_MD_MAKE_NONBLOCK(f[0]);
 	_PR_MD_MAKE_NONBLOCK(f[1]);
 	return PR_SUCCESS;
-#else /* XP_UNIX */
+#elif defined(WINNT)
+    /*
+     * A socket pair is often used for interprocess communication,
+     * so we need to make sure neither socket is associated with
+     * the I/O completion port; otherwise it can't be used by a
+     * child process.
+     *
+     * The default implementation below cannot be used for NT
+     * because PR_Accept would have associated the I/O completion
+     * port with the listening and accepted sockets.
+     */
+    SOCKET listenSock;
+    SOCKET osfd[2];
+    struct sockaddr_in selfAddr;
+    int addrLen;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    osfd[0] = osfd[1] = INVALID_SOCKET;
+    listenSock = socket(AF_INET, SOCK_STREAM, 0);
+    if (listenSock == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_family = AF_INET;
+    selfAddr.sin_port = 0;
+    selfAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addrLen = sizeof(selfAddr);
+    if (bind(listenSock, (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
+            &addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (listen(listenSock, 5) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
+    if (osfd[0] == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[1] = accept(listenSock, NULL, NULL);
+    if (osfd[1] == INVALID_SOCKET) {
+        goto failed;
+    }
+    closesocket(listenSock);
+
+    f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+    if (!f[0]) {
+        closesocket(osfd[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+    if (!f[1]) {
+        PR_Close(f[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock != INVALID_SOCKET) {
+        closesocket(listenSock);
+    }
+    if (osfd[0] != INVALID_SOCKET) {
+        closesocket(osfd[0]);
+    }
+    if (osfd[1] != INVALID_SOCKET) {
+        closesocket(osfd[1]);
+    }
+    return PR_FAILURE;
+#else /* not Unix or NT */
+    /*
+     * default implementation
+     */
     PRFileDesc *listenSock;
     PRNetAddr selfAddr;
     PRUint16 port;
 
     f[0] = f[1] = NULL;
     listenSock = PR_NewTCPSocket();
     if (listenSock == NULL) {
         goto failed;
@@ -1248,17 +1341,17 @@ PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPa
 failed:
     if (listenSock) {
         PR_Close(listenSock);
     }
     if (f[0]) {
         PR_Close(f[0]);
     }
     return PR_FAILURE;
-#endif /* XP_UNIX */
+#endif
 }
 
 PR_IMPLEMENT(PRInt32)
 PR_FileDesc2NativeHandle(PRFileDesc *fd)
 {
 	if (fd) {
 		/*
 		 * The fd may be layered.  Chase the links to the