diff options
author | wtc%netscape.com <devnull@localhost> | 2002-01-22 21:57:42 +0000 |
---|---|---|
committer | wtc%netscape.com <devnull@localhost> | 2002-01-22 21:57:42 +0000 |
commit | 60337c066e1a88545f04efb2e55f18d320c79cb0 (patch) | |
tree | aa8447fdcd1772c7891ddea02c51a01acfa4b532 | |
parent | b5907e7dcb74c70fe2aa413cc6bec773b93a917c (diff) | |
download | nspr-hg-60337c066e1a88545f04efb2e55f18d320c79cb0.tar.gz |
Bugzilla bug 100776: Merged the fix onto the NSPRPUB_PRE_4_2_CLIENT_BRANCH.
Modified files: configure configure.in _os2.h _os2_errors.h prsocket.c
os2_errors.c os2poll.c os2sock.c
-rwxr-xr-x | configure | 10 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | pr/include/md/_os2.h | 2 | ||||
-rw-r--r-- | pr/include/md/_os2_errors.h | 7 | ||||
-rw-r--r-- | pr/src/io/prsocket.c | 17 | ||||
-rw-r--r-- | pr/src/md/os2/os2_errors.c | 125 | ||||
-rw-r--r-- | pr/src/md/os2/os2poll.c | 266 | ||||
-rw-r--r-- | pr/src/md/os2/os2sock.c | 1001 |
8 files changed, 657 insertions, 773 deletions
@@ -4541,10 +4541,6 @@ EOF EOF cat >> confdefs.h <<\EOF -#define BSD_SELECT 1 -EOF - - cat >> confdefs.h <<\EOF #define XP_PC 1 EOF @@ -4571,6 +4567,10 @@ EOF EOF cat >> confdefs.h <<\EOF +#define BSD_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF #define OS2 1 EOF @@ -5573,7 +5573,7 @@ s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF -DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' ' | tr '\015' ' '` rm -f conftest.defs diff --git a/configure.in b/configure.in index 32da0f4c..978c6266 100644 --- a/configure.in +++ b/configure.in @@ -1674,7 +1674,6 @@ mips-sony-newsos*) *-os2*) AC_DEFINE(XP_OS2) - AC_DEFINE(BSD_SELECT) AC_DEFINE(XP_PC) AC_DEFINE(_PR_GLOBAL_THREADS_ONLY) OBJ_SUFFIX=obj @@ -1692,6 +1691,7 @@ mips-sony-newsos*) # EMX/GCC build if test "$GNU_CC"; then AC_DEFINE(XP_OS2_EMX) + AC_DEFINE(BSD_SELECT) AC_DEFINE(OS2) AR=emxomfar AR_FLAGS='-p256 r $@' diff --git a/pr/include/md/_os2.h b/pr/include/md/_os2.h index d98262d1..9f2e6dcf 100644 --- a/pr/include/md/_os2.h +++ b/pr/include/md/_os2.h @@ -537,4 +537,6 @@ unsigned long _System _DLL_InitTerm( unsigned long mod_handle, unsigned long fla #define FreeLibrary(x) DosFreeModule((HMODULE)x) #define OutputDebugString(x) +extern int _MD_os2_get_nonblocking_connect_error(int osfd); + #endif /* nspr_os2_defs_h___ */ diff --git a/pr/include/md/_os2_errors.h b/pr/include/md/_os2_errors.h index f77e8f6e..6f742be8 100644 --- a/pr/include/md/_os2_errors.h +++ b/pr/include/md/_os2_errors.h @@ -46,8 +46,8 @@ NSPR_API(void) _MD_os2_map_opendir_error(PRInt32 err); NSPR_API(void) _MD_os2_map_closedir_error(PRInt32 err); #define _PR_MD_MAP_CLOSEDIR_ERROR _MD_os2_map_closedir_error -NSPR_API(void) _MD_unix_readdir_error(PRInt32 err); -#define _PR_MD_MAP_READDIR_ERROR _MD_unix_readdir_error +NSPR_API(void) _MD_os2_readdir_error(PRInt32 err); +#define _PR_MD_MAP_READDIR_ERROR _MD_os2_readdir_error NSPR_API(void) _MD_os2_map_delete_error(PRInt32 err); #define _PR_MD_MAP_DELETE_ERROR _MD_os2_map_delete_error @@ -103,6 +103,9 @@ NSPR_API(void) _MD_os2_map_send_error(PRInt32 err); NSPR_API(void) _MD_os2_map_sendto_error(PRInt32 err); #define _PR_MD_MAP_SENDTO_ERROR _MD_os2_map_sendto_error +NSPR_API(void) _MD_os2_map_writev_error(int err); +#define _PR_MD_MAP_WRITEV_ERROR _MD_os2_map_writev_error + NSPR_API(void) _MD_os2_map_accept_error(PRInt32 err); #define _PR_MD_MAP_ACCEPT_ERROR _MD_os2_map_accept_error diff --git a/pr/src/io/prsocket.c b/pr/src/io/prsocket.c index e6eacaa1..217b6fd0 100644 --- a/pr/src/io/prsocket.c +++ b/pr/src/io/prsocket.c @@ -338,22 +338,11 @@ static PRStatus PR_CALLBACK SocketConnectContinue( #elif defined(XP_OS2) - if (out_flags & PR_POLL_EXCEPT) { - int 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); - } + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); return PR_FAILURE; } - - PR_ASSERT(out_flags & PR_POLL_WRITE); return PR_SUCCESS; #elif defined(XP_MAC) diff --git a/pr/src/md/os2/os2_errors.c b/pr/src/md/os2/os2_errors.c index f5be8391..5efd2c16 100644 --- a/pr/src/md/os2/os2_errors.c +++ b/pr/src/md/os2/os2_errors.c @@ -35,6 +35,44 @@ #include "prerror.h" #include "primpl.h" +void _MD_os2_map_default_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} void _MD_os2_map_opendir_error(PRInt32 err) { switch (err) { @@ -92,7 +130,7 @@ void _MD_os2_map_closedir_error(PRInt32 err) } } -void _MD_unix_readdir_error(PRInt32 err) +void _MD_os2_readdir_error(PRInt32 err) { switch (err) { @@ -671,73 +709,17 @@ void _MD_os2_map_send_error(PRInt32 err) void _MD_os2_map_sendto_error(PRInt32 err) { - switch (err) { - case EWOULDBLOCK: - PR_SetError(PR_WOULD_BLOCK_ERROR, err); - break; - case EBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case ENOTSOCK: - PR_SetError(PR_NOT_SOCKET_ERROR, err); - break; - case EMSGSIZE: - case EINVAL: - PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); - break; - case ENOBUFS: - PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); - break; - case ECONNREFUSED: - PR_SetError(PR_CONNECT_REFUSED_ERROR, err); - break; - case EISCONN: - PR_SetError(PR_IS_CONNECTED_ERROR, err); - break; -#ifdef SOCEFAULT - case SOCEFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; -#endif - case ERROR_NETNAME_DELETED: - PR_SetError(PR_CONNECT_RESET_ERROR, err); - break; - default: - PR_SetError(PR_UNKNOWN_ERROR, err); - break; - } + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_writev_error(int err) +{ + _MD_os2_map_default_error(err); } void _MD_os2_map_accept_error(PRInt32 err) { - switch (err) { - case EWOULDBLOCK: - PR_SetError(PR_WOULD_BLOCK_ERROR, err); - break; - case EBADF: - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); - break; - case ENOTSOCK: - PR_SetError(PR_NOT_SOCKET_ERROR, err); - break; - case EOPNOTSUPP: - PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); - break; -#ifdef SOCEFAULT - case SOCEFAULT: - PR_SetError(PR_ACCESS_FAULT_ERROR, err); - break; -#endif - case EMFILE: - PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); - break; - case ENOBUFS: - PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); - break; - default: - PR_SetError(PR_UNKNOWN_ERROR, err); - break; - } + _MD_os2_map_default_error(err); } void _MD_os2_map_acceptex_error(PRInt32 err) @@ -759,6 +741,21 @@ void _MD_os2_map_acceptex_error(PRInt32 err) } } +/* + * An error code of 0 means that the nonblocking connect succeeded. + */ + +int _MD_os2_get_nonblocking_connect_error(int osfd) +{ + int err; + int len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) { + return sock_errno(); + } else { + return err; + } +} + void _MD_os2_map_connect_error(PRInt32 err) { switch (err) { diff --git a/pr/src/md/os2/os2poll.c b/pr/src/md/os2/os2poll.c index 12f199f6..da477b1b 100644 --- a/pr/src/md/os2/os2poll.c +++ b/pr/src/md/os2/os2poll.c @@ -37,54 +37,64 @@ */ #ifdef XP_OS2_EMX - #include <sys/time.h> /* For timeval. */ + #include <sys/time.h> /* For timeval. */ #endif #include "primpl.h" -PRInt32 _PR_MD_PR_POLL( - PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +#ifndef BSD_SELECT +/* Utility functions called when using OS/2 select */ + +PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count ) +{ + int i; + PRBool isSet = PR_FALSE; + + for( i = start; i < start+count; i++ ) + { + if( socks[i] == osfd ) + isSet = PR_TRUE; + } + + return isSet; +} +#endif + +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { - PRInt32 osfd; - int maxfd = -1; +#ifdef BSD_SELECT fd_set rd, wt, ex; +#else + int rd, wt, ex; + int* socks; + unsigned long msecs; + int i, j; +#endif PRFileDesc *bottom; PRPollDesc *pd, *epd; - PRInt32 ready, err; - PRThread *me = _PR_MD_CURRENT_THREAD(); - struct timeval tv, *tvp = NULL; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; - /* - * For restarting _MD_SELECT() if it is interrupted by a signal. - * We use these variables to figure out how much time has elapsed - * and how much of the timeout still remains. - */ - PRIntervalTime start, elapsed, remaining; +#ifdef BSD_SELECT + struct timeval tv, *tvp = NULL; - if (_PR_PENDING_INTERRUPT(me)) + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); +#else + rd = 0; + wt = 0; + ex = 0; + socks = (int) PR_MALLOC( npds * 3 * sizeof(int) ); + + if (!socks) { - me->flags &= ~_PR_INTERRUPT; - PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } +#endif - /* - ** Is it an empty set? If so, just sleep for the timeout and return - */ - if (0 == npds) - { - PR_Sleep(timeout); - return 0; - } - - remaining = timeout; - start = PR_IntervalNow(); - - FD_ZERO(&rd); - FD_ZERO(&wt); - FD_ZERO(&ex); - - ready = 0; + ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { PRInt16 in_flags_read = 0, in_flags_write = 0; @@ -95,19 +105,17 @@ PRInt32 _PR_MD_PR_POLL( if (pd->in_flags & PR_POLL_READ) { in_flags_read = (pd->fd->methods->poll)( - pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE), - &out_flags_read); + pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); } if (pd->in_flags & PR_POLL_WRITE) { in_flags_write = (pd->fd->methods->poll)( - pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ), - &out_flags_write); + pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); } - if ((0 != (in_flags_read & out_flags_read)) - || (0 != (in_flags_write & out_flags_write))) + if ((0 != (in_flags_read & out_flags_read)) || + (0 != (in_flags_write & out_flags_write))) { - /* this one's ready right now (buffered input) */ + /* this one's ready right now */ if (0 == ready) { /* @@ -128,37 +136,67 @@ PRInt32 _PR_MD_PR_POLL( else { pd->out_flags = 0; /* pre-condition */ + /* make sure this is an NSPR supported stack */ bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); /* what to do about that? */ - if ((NULL != bottom) - && (_PR_FILEDESC_OPEN == bottom->secret->state)) + if ((NULL != bottom) && + (_PR_FILEDESC_OPEN == bottom->secret->state)) { if (0 == ready) { - osfd = bottom->secret->md.osfd; - if (osfd > maxfd) maxfd = osfd; + PRInt32 osfd = bottom->secret->md.osfd; + if (osfd > maxfd) + maxfd = osfd; if (in_flags_read & PR_POLL_READ) { pd->out_flags |= _PR_POLL_READ_SYS_READ; +#ifdef BSD_SELECT FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif } if (in_flags_read & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_READ_SYS_WRITE; +#ifdef BSD_SELECT FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif } if (in_flags_write & PR_POLL_READ) { pd->out_flags |= _PR_POLL_WRITE_SYS_READ; +#ifdef BSD_SELECT FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif } if (in_flags_write & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; +#ifdef BSD_SELECT FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif + } + if (pd->in_flags & PR_POLL_EXCEPT) + { +#ifdef BSD_SELECT + FD_SET(osfd, &ex); +#else + socks[npds*2+ex] = osfd; + ex++; +#endif } - if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); } } else @@ -178,9 +216,19 @@ PRInt32 _PR_MD_PR_POLL( } } - if (0 != ready) return ready; /* no need to block */ + if (0 != ready) + { +#ifndef BSD_SELECT + free(socks); +#endif + return ready; /* no need to block */ + } + + remaining = timeout; + start = PR_IntervalNow(); retry: +#ifdef BSD_SELECT if (timeout != PR_INTERVAL_NO_TIMEOUT) { PRInt32 ticksPerSecond = PR_TicksPerSecond(); @@ -191,21 +239,50 @@ retry: } ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); - if (ready == -1 && errno == EINTR) +#else + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: + msecs = 0; + break; + case PR_INTERVAL_NO_TIMEOUT: + msecs = -1; + break; + default: + msecs = PR_IntervalToMilliseconds(remaining); + } + + /* compact array */ + for( i = rd, j = npds; j < npds+wt; i++,j++ ) + socks[i] = socks[j]; + for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) + socks[i] = socks[j]; + + ready = _MD_SELECT(socks, rd, wt, ex, msecs); +#endif + + if (ready == -1 && errno == SOCEINTR) { - if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; - else + if (timeout == PR_INTERVAL_NO_TIMEOUT) + goto retry; + else { - elapsed = (PRIntervalTime) (PR_IntervalNow() - start); - if (elapsed > timeout) ready = 0; /* timed out */ - else + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) + ready = 0; /* timed out */ + else { - remaining = timeout - elapsed; - goto retry; + remaining = timeout - elapsed; + goto retry; } - } + } } + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ if (ready > 0) { ready = 0; @@ -214,26 +291,44 @@ retry: PRInt16 out_flags = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { + PRInt32 osfd; bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); osfd = bottom->secret->md.osfd; +#ifdef BSD_SELECT if (FD_ISSET(osfd, &rd)) +#else + if( IsSocketSet(osfd, socks, 0, rd) ) +#endif { if (pd->out_flags & _PR_POLL_READ_SYS_READ) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) out_flags |= PR_POLL_WRITE; - } + } + +#ifdef BSD_SELECT if (FD_ISSET(osfd, &wt)) +#else + if( IsSocketSet(osfd, socks, rd, wt) ) +#endif { if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) out_flags |= PR_POLL_WRITE; + } + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &ex)) +#else + if( IsSocketSet(osfd, socks, rd+wt, ex) ) +#endif + { + out_flags |= PR_POLL_EXCEPT; } - if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; } pd->out_flags = out_flags; if (out_flags) ready++; @@ -242,39 +337,42 @@ retry: } else if (ready < 0) { - err = _MD_ERRNO(); - if (err == EBADF) + err = _MD_ERRNO(); + if (err == EBADF) { - /* Find the bad fds */ - ready = 0; - for (pd = pds, epd = pd + npds; pd < epd; pd++) + /* Find the bad fds */ + int optval; + int optlen = sizeof(optval); + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) { - int optval; - int optlen = sizeof(optval); - pd->out_flags = 0; - if ((NULL == pd->fd) || (pd->in_flags == 0)) continue; - bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); - if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, - SO_TYPE, (char *) &optval, &optlen) == -1) + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) { - PR_ASSERT(_MD_ERRNO() == ENOTSOCK); - if (_MD_ERRNO() == ENOTSOCK) + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) { - pd->out_flags = PR_POLL_NVAL; - ready++; + PR_ASSERT(sock_errno() == SOCENOTSOCK); + if (sock_errno() == SOCENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } } } - } - PR_ASSERT(ready > 0); - } - else - { - PR_ASSERT(err != EINTR); /* should have been handled above */ - _PR_MD_MAP_SELECT_ERROR(err); + } + PR_ASSERT(ready > 0); } - } - return ready; - } + else + _PR_MD_MAP_SELECT_ERROR(err); + } + +#ifndef BSD_SELECT + free(socks); +#endif + return ready; +} #ifdef XP_OS2_EMX HMTX thread_select_mutex = 0; /* because EMX's select is not thread safe - duh! */ diff --git a/pr/src/md/os2/os2sock.c b/pr/src/md/os2/os2sock.c index 529e0e5a..36ebd46b 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,253 @@ _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; + 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 + 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 - 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); + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + 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); + lTimeout = PR_IntervalToMilliseconds(remaining); + if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) + 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) { +#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); - - if (rv == -1) { - _PR_MD_MAP_BIND_ERROR(sock_errno()); - return -1; - } - - return 0; + 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); } @@ -376,70 +363,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 +393,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 +437,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 +468,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; } } - return sent; + + /* + * 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; + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); } PRInt32 @@ -781,63 +562,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); + } } |