diff options
Diffstat (limited to 'pr/src/md/os2/os2sock.c')
-rw-r--r-- | pr/src/md/os2/os2sock.c | 1020 |
1 files changed, 419 insertions, 601 deletions
diff --git a/pr/src/md/os2/os2sock.c b/pr/src/md/os2/os2sock.c index 529e0e5a..ecdb31ff 100644 --- a/pr/src/md/os2/os2sock.c +++ b/pr/src/md/os2/os2sock.c @@ -46,9 +46,13 @@ #include "primpl.h" #ifdef XP_OS2_EMX - #include <sys/time.h> /* For timeval. */ + #include <sys/time.h> /* For timeval. */ #endif +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 +#define READ_FD 1 +#define WRITE_FD 2 + void _PR_MD_INIT_IO() { @@ -59,34 +63,19 @@ _PR_MD_INIT_IO() PRInt32 -_PR_MD_SOCKET(int af, int type, int flags) +_PR_MD_SOCKET(int domain, int type, int flags) { - int sock; - PRUint32 one = 1; - PRInt32 rv; - PRInt32 err; + PRInt32 osfd, err; - sock = socket(af, type, flags); - - if (sock == -1 ) - { - int rv = sock_errno(); - soclose(sock); - _PR_MD_MAP_SOCKET_ERROR(rv); - return (PRInt32) -1; - } + osfd = socket(domain, type, flags); - /* - ** Make the socket Non-Blocking - */ - rv = ioctl( sock, FIONBIO, (char *) &one, sizeof(one)); - if ( rv != 0 ) + if (osfd == -1) { err = sock_errno(); - return -1; + _PR_MD_MAP_SOCKET_ERROR(err); } - return (PRInt32)sock; + return(osfd); } /* @@ -96,12 +85,13 @@ _PR_MD_SOCKET(int af, int type, int flags) PRInt32 _MD_CloseSocket(PRInt32 osfd) { - PRInt32 rv = -1; - - rv = soclose((int) osfd ); - if (rv < 0) - _PR_MD_MAP_SOCKET_ERROR(sock_errno()); + PRInt32 rv, err; + rv = soclose(osfd); + if (rv == -1) { + err = sock_errno(); + _PR_MD_MAP_CLOSE_ERROR(err); + } return rv; } @@ -117,256 +107,276 @@ _MD_SocketAvailable(PRFileDesc *fd) return result; } -PRInt32 -_MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, - PRIntervalTime timeout ) +static PRInt32 +socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout ) { - PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv, err; + PRInt32 rv = -1; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; #ifdef BSD_SELECT - fd_set rd; - struct timeval tv, *tvp; - - FD_ZERO(&rd); - FD_SET(osfd, &rd); + struct timeval tv; + fd_set rd_wr; #else int socks[1]; - socks[0] = osfd; + long lTimeout; #endif - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - while ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1) - { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { + + 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. + */ #ifdef BSD_SELECT - if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL,NULL)) == -1) { + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + do { + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); #else - if ((rv = _MD_SELECT(socks, 1, 0, 0, -1)) == -1) { -#endif - _PR_MD_MAP_SELECT_ERROR(sock_errno()); + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + do { + socks[0] = osfd; + if (fd_type == READ_FD) + rv = _MD_SELECT(socks, 1, 0, 0, lTimeout); + else + rv = _MD_SELECT(socks, 0, 1, 0, lTimeout); +#endif + if (rv == -1 && (syserror = sock_errno()) != SOCEINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); break; - } - } - else { - _PR_MD_MAP_ACCEPT_ERROR(err); - break; - } - } - return(rv); - } - else if (timeout == PR_INTERVAL_NO_WAIT) - { - if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1) - { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - } - else - { - _PR_MD_MAP_ACCEPT_ERROR(err); - } - } - return(rv); - } - else - { -retry: - if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1) - { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; #ifdef BSD_SELECT - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp); + FD_ZERO(&rd_wr); +#endif + 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. + */ +#ifdef BSD_SELECT + 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); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); #else - long lTimeout = PR_IntervalToMilliseconds(timeout); - rv = _MD_SELECT(socks, 1, 0, 0, lTimeout); + wait_for_remaining = PR_TRUE; + lTimeout = PR_IntervalToMilliseconds(remaining); + if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + wait_for_remaining = PR_FALSE; + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + } + socks[0] = osfd; + if (fd_type == READ_FD) + rv = _MD_SELECT(socks, 1, 0, 0, lTimeout); + else + rv = _MD_SELECT(socks, 0, 1, 0, lTimeout); #endif - if (rv > 0) { - goto retry; - } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = sock_errno()) != SOCEINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; - } else { - _PR_MD_MAP_SELECT_ERROR(sock_errno()); + break; } - } else { - _PR_MD_MAP_ACCEPT_ERROR(err); - } + /* + * We loop again if _MD_SELECT timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == SOCEINTR)) { + /* + * If _MD_SELECT timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { +#ifdef BSD_SELECT + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); +#else + now += PR_MillisecondsToInterval(lTimeout); +#endif + } + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == SOCEINTR)); + break; } - } return(rv); -} /* end _MD_Accept() */ +} +PRInt32 +_MD_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1) + { + err = sock_errno(); + if ((err == SOCEWOULDBLOCK) || (err == SOCECONNABORTED)) + { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } +done: + return(rv); +} PRInt32 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 osfd = fd->secret->md.osfd; - PRInt32 rv; - int err, len; -#ifdef BSD_SELECT -#ifdef XP_OS2//_VACPP - fd_set wd; -#else - fd_set wd, ex; -#endif #vacpp - struct timeval tv, *tvp; -#else - int socks[1]; - long lTimeout = -1; -#endif - if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) + /* + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { err = sock_errno(); - if ((!fd->secret->nonblocking) && ((err == EINPROGRESS) || (err == EWOULDBLOCK))) - { -#ifdef BSD_SELECT - if (timeout == PR_INTERVAL_NO_TIMEOUT) - tvp = NULL; - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds(timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; + + if (err == SOCEINTR) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; } + goto retry; + } - FD_ZERO(&wd); - FD_SET(osfd, &wd); -#ifdef XP_OS2//_VACPP - rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, tvp); -#else - FD_ZERO(&ex); - FD_SET(osfd, &ex); - rv = _MD_SELECT(osfd + 1, NULL, &wd, &ex, tvp); -#endif #vacpp -#else #!bsd_select - if (timeout == PR_INTERVAL_NO_TIMEOUT) - lTimeout = -1; - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); + if (!fd->secret->nonblocking && (err == SOCEINPROGRESS)) + { + /* + * socket_io_wait() may return -1 or 1. + */ + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; } - - socks[0] = osfd; -#ifdef XP_OS2//_VACPP - rv = _MD_SELECT(socks, 0, 1, 0, lTimeout); -#else - rv = _MD_SELECT(socks, 0, 1, 1, lTimeout); -#endif #vacpp -#endif - if (rv > 0) - { -#ifdef BSD_SELECT -#ifdef XP_OS2//_VACPP - if (FD_ISSET(osfd, &wd)) - { - //DosSleep(0); - len = sizeof(err); - if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, - (char *) &err, &len) < 0) - { - _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); - return -1; - } - if (err != 0) - { - _PR_MD_MAP_CONNECT_ERROR(err); - return -1; - } - else - return 0; /* it's connected */ - } - else - return -1; -#else - if (FD_ISSET(osfd, &ex)) - { - DosSleep(0); - len = sizeof(err); - if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, - (char *) &err, &len) < 0) - { - _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); - return -1; - } - if (err != 0) - _PR_MD_MAP_CONNECT_ERROR(err); - else - PR_SetError(PR_UNKNOWN_ERROR, 0); - return -1; - } - if (FD_ISSET(osfd, &wd)) - { - /* it's connected */ - return 0; - } -#endif #vacpp -#else #!bsd_select - if (socks[0] == osfd) - { - len = sizeof(err); - if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, - (char *) &err, &len) < 0) - { - _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); - return -1; - } - - if (err != 0) - { - _PR_MD_MAP_CONNECT_ERROR(err); - return -1; - } - else - return 0; /* it's connected */ - } - else - return -1; -#endif + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return(-1); - } else if (rv < 0) - { - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - return(-1); + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; } - } + return 0; + } + _PR_MD_MAP_CONNECT_ERROR(err); } - return rv; -} + return rv; +} /* _MD_connect */ PRInt32 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) { - PRInt32 rv; - - rv = bind(fd->secret->md.osfd, (struct sockaddr*) &(addr->inet), addrlen); + PRInt32 rv, err; + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_BIND_ERROR(err); + } + return(rv); +} - if (rv == -1) { - _PR_MD_MAP_BIND_ERROR(sock_errno()); - return -1; - } - return 0; +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_DEFAULT_ERROR(err); + } + return(rv); } @@ -376,70 +386,27 @@ _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; -#ifdef BSD_SELECT - struct timeval tv, *tvp; - fd_set rd; -#else - int socks[1]; - long lTimeout = -1; -#endif - int osflags; + PRThread *me = _PR_MD_CURRENT_THREAD(); - if (0 == flags) { - osflags = 0; - } else { - PR_ASSERT(PR_MSG_PEEK == flags); - osflags = MSG_PEEK; - } - while ((rv = recv( osfd, buf, amount, osflags)) == -1) + while ((rv = recv(osfd,buf,amount,flags)) == -1) { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { -#ifdef BSD_SELECT - FD_ZERO(&rd); - FD_SET(osfd, &rd); - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp)) == -1) -#else - socks[0] = osfd; - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - if ((rv = _MD_SELECT(socks, 1, 0, 0, lTimeout)) == -1) -#endif - { - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - return -1; - } - else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; + err = sock_errno(); + if ((err == SOCEWOULDBLOCK)) { + if (fd->secret->nonblocking) { break; } - } - else - { - _PR_MD_MAP_RECV_ERROR(err); + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { break; } - } /* end while() */ + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } +done: return(rv); } @@ -449,108 +416,42 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; -#ifdef BSD_SELECT - struct timeval tv, *tvp; - fd_set wd; -#else - int socks[1]; - long lTimeout = -1; -#endif - PRInt32 bytesSent = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); - while(bytesSent < amount ) + while ((rv = send(osfd,buf,amount,flags)) == -1) { - while ((rv = send( osfd, (char *) buf, amount, 0 )) == -1) - { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { -#ifdef BSD_SELECT - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET(osfd, &wd); - if ((rv = _MD_SELECT( osfd + 1, NULL, &wd, NULL,tvp)) == -1) { -#else - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - socks[0] = osfd; - if ((rv = _MD_SELECT( socks, 0, 1, 0, lTimeout)) == -1) { -#endif - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - break; - } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; - } - } - else { - _PR_MD_MAP_SEND_ERROR(err); - return -1; + err = sock_errno(); + if ((err == SOCEWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; } - } - bytesSent += rv; - if (fd->secret->nonblocking) - { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) + goto done; + } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { break; } - if ((rv >= 0) && (bytesSent < amount )) - { -#ifdef BSD_SELECT - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET(osfd, &wd); - if ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL,tvp)) == -1) { -#else - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - socks[0] = osfd; - if ((rv = _MD_SELECT(socks, 0, 1, 0,lTimeout)) == -1) { -#endif - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - break; - } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; - } + } + + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next send() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) + { + if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { + rv = -1; + goto done; } } - return bytesSent; + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return(rv); } PRInt32 @@ -559,109 +460,29 @@ _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - PRInt32 bytesSent = 0; -#ifdef BSD_SELECT - struct timeval tv, *tvp; - fd_set wd; -#else - int socks[1]; - long lTimeout = -1; -#endif - - while(bytesSent < amount) + PRThread *me = _PR_MD_CURRENT_THREAD(); + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { - while ((rv = sendto( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr, - addrlen)) == -1) - { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { -#ifdef BSD_SELECT - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET(osfd, &wd); - if ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, tvp)) == -1) { -#else - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - socks[0] = osfd; - if ((rv = _MD_SELECT(socks, 0, 1, 0, lTimeout)) == -1) { -#endif - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - break; - } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; - } - } - else { - _PR_MD_MAP_SENDTO_ERROR(err); - return -1; - } - } - bytesSent += rv; - if (fd->secret->nonblocking) - { - break; - } - if ((rv >= 0) && (bytesSent < amount )) + err = sock_errno(); + if ((err == SOCEWOULDBLOCK)) { -#ifdef BSD_SELECT - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&wd); - FD_SET(osfd, &wd); - if ((rv = _MD_SELECT( osfd + 1, NULL, &wd, NULL, tvp)) == -1) { -#else - if ( timeout == PR_INTERVAL_NO_TIMEOUT ) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - socks[0] = osfd; - if ((rv = _MD_SELECT( socks, 0, 1, 0, lTimeout)) == -1) { -#endif - _PR_MD_MAP_SELECT_ERROR(sock_errno()); + if (fd->secret->nonblocking) { break; } - if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - return -1; - } + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; } } - return bytesSent; + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return(rv); } PRInt32 @@ -670,103 +491,86 @@ _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, { PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; - PRUint32 addrlen_temp = *addrlen; -#ifdef BSD_SELECT - struct timeval tv, *tvp; - fd_set rd; -#else - int socks[1]; - long lTimeout = -1; -#endif + PRThread *me = _PR_MD_CURRENT_THREAD(); - while ((rv = recvfrom( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr, - (int *) addrlen)) == -1) + while( (*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr *) addr, (int *)addrlen)) == -1)) { - if (((err = sock_errno()) == EWOULDBLOCK) - && (!fd->secret->nonblocking)) - { -#ifdef BSD_SELECT - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - tvp = NULL; - } - else - { - tv.tv_sec = PR_IntervalToSeconds(timeout); - tv.tv_usec = PR_IntervalToMicroseconds( - timeout - PR_SecondsToInterval(tv.tv_sec)); - tvp = &tv; - } - FD_ZERO(&rd); - FD_SET(osfd, &rd); - if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp)) == -1) -#else - if (timeout == PR_INTERVAL_NO_TIMEOUT) - { - lTimeout = -1; - } - else - { - lTimeout = PR_IntervalToMilliseconds(timeout); - } - socks[0] = osfd; - if ((rv = _MD_SELECT(socks, 1, 0, 0, lTimeout)) == -1) -#endif - { - _PR_MD_MAP_SELECT_ERROR(sock_errno()); - return -1; - } else if (rv == 0) - { - PR_SetError(PR_IO_TIMEOUT_ERROR, 0); - rv = -1; + err = sock_errno(); + if ((err == SOCEWOULDBLOCK)) { + if (fd->secret->nonblocking) { break; } - - /* recvfrom blows this value away if it fails first time */ - *addrlen = addrlen_temp; - } - else - { - _PR_MD_MAP_RECVFROM_ERROR(err); + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { break; } } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } +done: return(rv); } PRInt32 -_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout) { - int index; - int sent = 0; - int rv; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 index, amount = 0; + PRInt32 osfd = fd->secret->md.osfd; - for (index=0; index < iov_size; index++) - { - rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout); - if (rv > 0) - sent += rv; - if ( rv != iov[index].iov_len ) - { - if (rv < 0) - { - if (fd->secret->nonblocking - && (PR_GetError() == PR_WOULD_BLOCK_ERROR) - && (sent > 0)) - { - return sent; - } - else - { - return -1; - } + /* + * Calculate the total number of bytes to be sent; needed for + * optimization later. + * We could avoid this if this number was passed in; but it is + * probably not a big deal because iov_size is usually small (less than + * 3) + */ + if (!fd->secret->nonblocking) { + for (index=0; index<iov_size; index++) { + amount += iov[index].iov_len; + } + } + + while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) { + err = sock_errno(); + if ((err == SOCEWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; } - /* Only a nonblocking socket can have partial sends */ - PR_ASSERT(fd->secret->nonblocking); - return sent; + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; } } - return sent; + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); } PRInt32 @@ -781,63 +585,77 @@ _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) } PRStatus -_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) { - PRInt32 rv; + PRInt32 rv, err; - rv = getsockname((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETSOCKNAME_ERROR(sock_errno()); - return PR_FAILURE; + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); } + return rv==0?PR_SUCCESS:PR_FAILURE; } PRStatus -_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) { - PRInt32 rv; + PRInt32 rv, err; - rv = getpeername((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETPEERNAME_ERROR(sock_errno()); - return PR_FAILURE; + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); } + return rv==0?PR_SUCCESS:PR_FAILURE; } PRStatus -_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + char* optval, PRInt32* optlen) { - PRInt32 rv; + PRInt32 rv, err; - rv = getsockopt((int)fd->secret->md.osfd, level, optname, optval, optlen); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); - return PR_FAILURE; + rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); } + return rv==0?PR_SUCCESS:PR_FAILURE; } PRStatus -_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + const char* optval, PRInt32 optlen) { - PRInt32 rv; + PRInt32 rv, err; - rv = setsockopt((int)fd->secret->md.osfd, level, optname, (char *) optval, optlen); - if (rv==0) - return PR_SUCCESS; - else { - _PR_MD_MAP_SETSOCKOPT_ERROR(sock_errno()); - return PR_FAILURE; + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); } + return rv==0?PR_SUCCESS:PR_FAILURE; } void -_MD_MakeNonblock(PRFileDesc *f) +_MD_MakeNonblock(PRFileDesc *fd) { - return; /* do nothing! */ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 err; + PRUint32 one = 1; + + if (osfd <= 2) { + /* Don't mess around with stdin, stdout or stderr */ + return; + } + + err = ioctl( osfd, FIONBIO, (char *) &one, sizeof(one)); + if ( err != 0 ) + { + err = sock_errno(); + _PR_MD_MAP_SOCKET_ERROR(err); + } } |