void _PR_InitIO(void) { const PRIOMethods *methods = PR_GetFileMethods(); _PR_InitFdCache(); _pr_flock_lock = PR_NewLock(); _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); #ifdef WIN32 _pr_stdin = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_INPUT_HANDLE), methods); _pr_stdout = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_OUTPUT_HANDLE), methods); _pr_stderr = PR_AllocFileDesc((PROsfd)GetStdHandle(STD_ERROR_HANDLE), methods); #ifdef WINNT _pr_stdin->secret->md.sync_file_io = PR_TRUE; _pr_stdout->secret->md.sync_file_io = PR_TRUE; _pr_stderr->secret->md.sync_file_io = PR_TRUE; #endif #else _pr_stdin = PR_AllocFileDesc(0, methods); _pr_stdout = PR_AllocFileDesc(1, methods); _pr_stderr = PR_AllocFileDesc(2, methods); #endif _PR_MD_INIT_FD_INHERITABLE(_pr_stdin, PR_TRUE); _PR_MD_INIT_FD_INHERITABLE(_pr_stdout, PR_TRUE); _PR_MD_INIT_FD_INHERITABLE(_pr_stderr, PR_TRUE); _PR_MD_INIT_IO(); }
PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd) { PRFileDesc *fd; if (!_pr_initialized) _PR_ImplicitInitialization(); fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); if (fd != NULL) { _PR_MD_MAKE_NONBLOCK(fd); _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); } else _PR_MD_CLOSE_SOCKET(osfd); return(fd); }
PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PROsfd osfd) { 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(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[]) { #ifdef XP_UNIX PRInt32 rv, osfd[2]; if (!_pr_initialized) _PR_ImplicitInitialization(); rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd); if (rv == -1) { return PR_FAILURE; } f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); if (!f[0]) { _PR_MD_CLOSE_SOCKET(osfd[0]); _PR_MD_CLOSE_SOCKET(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]); _PR_MD_CLOSE_SOCKET(osfd[1]); /* PR_AllocFileDesc() has invoked PR_SetError(). */ return PR_FAILURE; } _PR_MD_MAKE_NONBLOCK(f[0]); _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); _PR_MD_MAKE_NONBLOCK(f[1]); _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); return PR_SUCCESS; #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, peerAddr; 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_LOOPBACK); /* BugZilla: 35408 */ 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; } /* * A malicious local process may connect to the listening * socket, so we need to verify that the accepted connection * is made from our own socket osfd[0]. */ if (getsockname(osfd[0], (struct sockaddr *) &selfAddr, &addrLen) == SOCKET_ERROR) { goto failed; } osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen); if (osfd[1] == INVALID_SOCKET) { goto failed; } if (peerAddr.sin_port != selfAddr.sin_port) { /* the connection we accepted is not from osfd[0] */ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 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; } _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); 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, peerAddr; PRUint16 port; f[0] = f[1] = NULL; listenSock = PR_NewTCPSocket(); if (listenSock == NULL) { goto failed; } PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { goto failed; } if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { goto failed; } port = ntohs(selfAddr.inet.port); if (PR_Listen(listenSock, 5) == PR_FAILURE) { goto failed; } f[0] = PR_NewTCPSocket(); if (f[0] == NULL) { goto failed; } #ifdef _PR_CONNECT_DOES_NOT_BIND /* * If connect does not implicitly bind the socket (e.g., on * BeOS), we have to bind the socket so that we can get its * port with getsockname later. */ PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { goto failed; } #endif PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); /* * Only a thread is used to do the connect and accept. * I am relying on the fact that PR_Connect returns * successfully as soon as the connect request is put * into the listen queue (but before PR_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 (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { goto failed; } /* * A malicious local process may connect to the listening * socket, so we need to verify that the accepted connection * is made from our own socket f[0]. */ if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { goto failed; } f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); if (f[1] == NULL) { goto failed; } if (peerAddr.inet.port != selfAddr.inet.port) { /* the connection we accepted is not from f[0] */ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); goto failed; } PR_Close(listenSock); return PR_SUCCESS; failed: if (listenSock) { PR_Close(listenSock); } if (f[0]) { PR_Close(f[0]); } if (f[1]) { PR_Close(f[1]); } return PR_FAILURE; #endif }
PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) { PROsfd osfd; PRFileDesc *fd; PRInt32 tmp_domain = domain; if (!_pr_initialized) _PR_ImplicitInitialization(); if (PR_AF_INET != domain && PR_AF_INET6 != domain #if defined(XP_UNIX) || defined(XP_OS2) && PR_AF_LOCAL != domain #endif ) { PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); return NULL; } #if defined(_PR_INET6_PROBE) if (PR_AF_INET6 == domain) domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; #elif defined(_PR_INET6) if (PR_AF_INET6 == domain) domain = AF_INET6; #else if (PR_AF_INET6 == domain) domain = AF_INET; #endif /* _PR_INET6 */ osfd = _PR_MD_SOCKET(domain, type, proto); if (osfd == -1) { return 0; } if (type == SOCK_STREAM) fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); else fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); /* * Make the sockets non-blocking */ if (fd != NULL) { _PR_MD_MAKE_NONBLOCK(fd); _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); #ifdef _PR_NEED_SECRET_AF fd->secret->af = domain; #endif #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) /* * For platforms with no support for IPv6 * create layered socket for IPv4-mapped IPv6 addresses */ if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { PR_Close(fd); fd = NULL; } } #endif } else _PR_MD_CLOSE_SOCKET(osfd); return fd; }