/* -*- 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! */
}
syntax highlighted by Code2HTML, v. 0.9.1