PRInt32 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { PROsfd osfd = fd->secret->md.osfd; PRInt32 rv; int err; if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) { err = WSAGetLastError(); if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK)) { rv = socket_io_wait(osfd, CONNECT_FD, timeout); if ( rv < 0 ) { return(-1); } else { PR_ASSERT(rv > 0); /* it's connected */ return(0); } } _PR_MD_MAP_CONNECT_ERROR(err); } return rv; }
static PRStatus PR_CALLBACK SocketConnectContinue( PRFileDesc *fd, PRInt16 out_flags) { PROsfd osfd; int err; if (out_flags & PR_POLL_NVAL) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); return PR_FAILURE; } if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { PR_ASSERT(out_flags == 0); PR_SetError(PR_IN_PROGRESS_ERROR, 0); return PR_FAILURE; } osfd = fd->secret->md.osfd; #if defined(XP_UNIX) err = _MD_unix_get_nonblocking_connect_error(osfd); if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); return PR_FAILURE; } return PR_SUCCESS; #elif defined(WIN32) || defined(WIN16) #if defined(WIN32) /* * The sleep circumvents a bug in Win32 WinSock. * See Microsoft Knowledge Base article ID: Q165989. */ Sleep(0); #endif /* WIN32 */ if (out_flags & PR_POLL_EXCEPT) { int len = sizeof(err); if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return PR_FAILURE; } if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); } else { PR_SetError(PR_UNKNOWN_ERROR, 0); } return PR_FAILURE; } PR_ASSERT(out_flags & PR_POLL_WRITE); return PR_SUCCESS; #elif defined(XP_OS2) err = _MD_os2_get_nonblocking_connect_error(osfd); if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); return PR_FAILURE; } return PR_SUCCESS; #elif defined(XP_BEOS) #ifdef BONE_VERSION /* bug 122364 */ /* temporary workaround until getsockopt(SO_ERROR) works in BONE */ if (out_flags & PR_POLL_EXCEPT) { PR_SetError(PR_CONNECT_REFUSED_ERROR, 0); return PR_FAILURE; } PR_ASSERT(out_flags & PR_POLL_WRITE); return PR_SUCCESS; #else err = _MD_beos_get_nonblocking_connect_error(fd); if( err != 0 ) { _PR_MD_MAP_CONNECT_ERROR(err); return PR_FAILURE; } else return PR_SUCCESS; #endif /* BONE_VERSION */ #else PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); return PR_FAILURE; #endif }
PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) { PRInt32 osfd; PRFileDesc *bottom = pd->fd; int err, len; if (pd->out_flags & PR_POLL_NVAL) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); return PR_FAILURE; } if ((pd->out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { PR_ASSERT(pd->out_flags == 0); PR_SetError(PR_IN_PROGRESS_ERROR, 0); return PR_FAILURE; } while (bottom->lower != NULL) { bottom = bottom->lower; } osfd = bottom->secret->md.osfd; #if defined(XP_UNIX) err = _MD_unix_get_nonblocking_connect_error(osfd); if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); return PR_FAILURE; } return PR_SUCCESS; #elif defined(WIN32) || defined(WIN16) if (pd->out_flags & PR_POLL_EXCEPT) { #if defined(WIN32) /* Note: There is a bug in Win32 WinSock. The sleep circumvents the ** bug. See wtc. /s lth. */ Sleep(0); #endif /* WIN32 */ len = sizeof(err); if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return PR_FAILURE; } if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); } else { PR_SetError(PR_UNKNOWN_ERROR, 0); } return PR_FAILURE; } PR_ASSERT(pd->out_flags & PR_POLL_WRITE); return PR_SUCCESS; #elif defined(XP_OS2) if (pd->out_flags & PR_POLL_EXCEPT) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) { _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); return PR_FAILURE; } if (err != 0) { _PR_MD_MAP_CONNECT_ERROR(err); } else { PR_SetError(PR_UNKNOWN_ERROR, 0); } return PR_FAILURE; } PR_ASSERT(pd->out_flags & PR_POLL_WRITE); return PR_SUCCESS; #elif defined(XP_MAC) err = _MD_mac_get_nonblocking_connect_error(osfd); if (err == -1) return PR_FAILURE; else return PR_SUCCESS; #else PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); return PR_FAILURE; #endif }
static PRInt32 socket_io_wait( PROsfd osfd, PRInt32 fd_type, PRIntervalTime timeout) { PRInt32 rv = -1; struct timeval tv; PRThread *me = _PR_MD_CURRENT_THREAD(); PRIntervalTime elapsed, remaining; PRBool wait_for_remaining; fd_set rd_wr, ex; int err, len; switch (timeout) { case PR_INTERVAL_NO_WAIT: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; case PR_INTERVAL_NO_TIMEOUT: /* * This is a special case of the 'default' case below. * Please see the comments there. */ tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1 ) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } } while (rv == 0); break; default: remaining = timeout; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { /* * We block in _MD_SELECT for at most * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, * so that there is an upper limit on the delay * before the interrupt bit is checked. */ wait_for_remaining = PR_TRUE; tv.tv_sec = PR_IntervalToSeconds(remaining); if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { wait_for_remaining = PR_FALSE; tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; } else { tv.tv_usec = PR_IntervalToMicroseconds( remaining - PR_SecondsToInterval(tv.tv_sec)); } FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } /* * We loop again if _MD_SELECT timed out and the * timeout deadline has not passed yet. */ if (rv == 0 ) { if (wait_for_remaining) { elapsed = remaining; } else { elapsed = PR_SecondsToInterval(tv.tv_sec) + PR_MicrosecondsToInterval(tv.tv_usec); } if (elapsed >= remaining) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); rv = -1; break; } else { remaining = remaining - elapsed; } } } while (rv == 0 ); break; } return(rv); } /* end socket_io_wait() */