diff options
Diffstat (limited to 'pr/src/md/os2/os2sock.c')
-rw-r--r-- | pr/src/md/os2/os2sock.c | 770 |
1 files changed, 770 insertions, 0 deletions
diff --git a/pr/src/md/os2/os2sock.c b/pr/src/md/os2/os2sock.c new file mode 100644 index 00000000..3eb26d35 --- /dev/null +++ b/pr/src/md/os2/os2sock.c @@ -0,0 +1,770 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* OS/2 Sockets module + * + */ + +/*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */ +/*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */ +/*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */ +/*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */ +/*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */ + +#include "primpl.h" + +void +_PR_MD_INIT_IO() +{ + sock_init(); +} + +/* --- SOCKET IO --------------------------------------------------------- */ + + +PRInt32 +_PR_MD_SOCKET(int af, int type, int flags) +{ + int sock; + PRUint32 one = 1; + PRInt32 rv; + PRInt32 err; + + sock = socket(af, type, flags); + + if (sock == -1 ) + { + int rv = sock_errno(); + soclose(sock); + _PR_MD_MAP_SOCKET_ERROR(rv); + return (PRInt32) -1; + } + + /* + ** Make the socket Non-Blocking + */ + rv = ioctl( sock, FIONBIO, (char *) &one, sizeof(one)); + if ( rv != 0 ) + { + err = sock_errno(); + return -1; + } + + return (PRInt32)sock; +} + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_MD_CloseSocket(PRInt32 osfd) +{ + PRInt32 rv = -1; + + rv = soclose((int) osfd ); + if (rv < 0) + _PR_MD_MAP_SOCKET_ERROR(sock_errno()); + + return rv; +} + +PRInt32 +_MD_SocketAvailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctl(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno()); + return -1; + } + return result; +} + +PRInt32 +_MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout ) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; +#ifdef BSD_SELECT + fd_set rd; + struct timeval tv, *tvp; + + FD_ZERO(&rd); + FD_SET(osfd, &rd); +#else + int socks[1]; + socks[0] = osfd; +#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)) + { +#ifdef BSD_SELECT + if ((rv = select(osfd + 1, &rd, NULL, NULL,NULL)) == -1) { +#else + if ((rv = select(socks, 1, 0, 0, -1)) == -1) { +#endif + _PR_MD_MAP_SELECT_ERROR(sock_errno()); + 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)) + { +#ifdef BSD_SELECT + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + rv = select(osfd + 1, &rd, NULL, NULL, tvp); +#else + long lTimeout = PR_IntervalToMilliseconds(timeout); + rv = select(socks, 1, 0, 0, lTimeout); +#endif + if (rv > 0) { + goto retry; + } + else if (rv == 0) + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + } else { + _PR_MD_MAP_SELECT_ERROR(sock_errno()); + } + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + } + } + } + return(rv); +} /* end _MD_Accept() */ + + + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv; + int err, len; +#ifdef BSD_SELECT + fd_set wd, ex; + struct timeval tv, *tvp; +#else + int socks[1]; + long lTimeout = -1; +#endif + + 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; + } + + FD_ZERO(&wd); + FD_SET(osfd, &wd); + FD_ZERO(&ex); + FD_SET(osfd, &ex); + rv = select(osfd + 1, NULL, &wd, &ex, tvp); +#else + if (timeout == PR_INTERVAL_NO_TIMEOUT) + lTimeout = -1; + else + { + lTimeout = PR_IntervalToMilliseconds(timeout); + } + + socks[0] = osfd; + rv = select(socks, 0, 1, 1, lTimeout); +#endif + if (rv > 0) + { +#ifdef BSD_SELECT + 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; + } +#else + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) < 0) + { + _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno()); + return -1; + } + else + return 0; /* It's connected ! */ +#endif + } + 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); + } + } + _PR_MD_MAP_CONNECT_ERROR(err); + } + return rv; +} + + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; + int one = 1; + + 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 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + 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 + + while ((rv = recv( osfd, buf, amount, 0)) == -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 = 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 = 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; + break; + } + } + else + { + _PR_MD_MAP_RECV_ERROR(err); + break; + } + } /* end while() */ + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + 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; + + while(bytesSent < amount ) + { + 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 = 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 = 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; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) + { + 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 = 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 = 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; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + 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) + { + 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 = 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 = 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 )) + { +#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 = 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 = 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; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + 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 + + while ((rv = recvfrom( osfd, (char *) buf, amount, 0, (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 = 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 = 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; + break; + } + + /* recvfrom blows this value away if it fails first time */ + *addrlen = addrlen_temp; + } + else + { + _PR_MD_MAP_RECVFROM_ERROR(err); + break; + } + } + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + 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; + } + } + /* Only a nonblocking socket can have partial sends */ + PR_ASSERT(fd->secret->nonblocking); + return sent; + } + } + return sent; +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ +PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno()); + return rv; +} + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + 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; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + 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; + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv; + + 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; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv; + + 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; + } +} + +void +_MD_MakeNonblock(PRFileDesc *f) +{ + return; /* do nothing! */ +} |