michael@0: /* -*- Mode: C++; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "primpl.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: /* michael@0: * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or michael@0: * PRInt32* pointer to a _PRSockLen_t* pointer. michael@0: */ michael@0: #define _PRSockLen_t int michael@0: michael@0: michael@0: /* michael@0: ** Global lock variable used to bracket calls into rusty libraries that michael@0: ** aren't thread safe (like libc, libX, etc). michael@0: */ michael@0: static PRLock *_pr_rename_lock = NULL; michael@0: static PRMonitor *_pr_Xfe_mon = NULL; michael@0: michael@0: #define READ_FD 1 michael@0: #define WRITE_FD 2 michael@0: michael@0: /* michael@0: ** This is a support routine to handle "deferred" i/o on sockets. michael@0: ** It uses "select", so it is subject to all of the BeOS limitations michael@0: ** (only READ notification, only sockets) michael@0: */ michael@0: michael@0: /* michael@0: * socket_io_wait -- michael@0: * michael@0: * wait for socket i/o, periodically checking for interrupt michael@0: * michael@0: */ michael@0: michael@0: static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, michael@0: PRIntervalTime timeout) michael@0: { michael@0: PRInt32 rv = -1; michael@0: struct timeval tv; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: PRIntervalTime epoch, now, elapsed, remaining; michael@0: PRBool wait_for_remaining; michael@0: PRInt32 syserror; michael@0: fd_set rd_wr; michael@0: michael@0: switch (timeout) { michael@0: case PR_INTERVAL_NO_WAIT: michael@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); michael@0: break; michael@0: case PR_INTERVAL_NO_TIMEOUT: michael@0: /* michael@0: * This is a special case of the 'default' case below. michael@0: * Please see the comments there. michael@0: */ michael@0: tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; michael@0: tv.tv_usec = 0; michael@0: FD_ZERO(&rd_wr); michael@0: do { michael@0: FD_SET(osfd, &rd_wr); michael@0: if (fd_type == READ_FD) michael@0: rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); michael@0: else michael@0: rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); michael@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { michael@0: #ifdef BONE_VERSION michael@0: _PR_MD_MAP_SELECT_ERROR(syserror); michael@0: #else michael@0: if (syserror == EBADF) { michael@0: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); michael@0: } else { michael@0: PR_SetError(PR_UNKNOWN_ERROR, syserror); michael@0: } michael@0: #endif michael@0: break; michael@0: } michael@0: if (_PR_PENDING_INTERRUPT(me)) { michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); michael@0: rv = -1; michael@0: break; michael@0: } michael@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); michael@0: break; michael@0: default: michael@0: now = epoch = PR_IntervalNow(); michael@0: remaining = timeout; michael@0: FD_ZERO(&rd_wr); michael@0: do { michael@0: /* michael@0: * We block in _MD_SELECT for at most michael@0: * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, michael@0: * so that there is an upper limit on the delay michael@0: * before the interrupt bit is checked. michael@0: */ michael@0: wait_for_remaining = PR_TRUE; michael@0: tv.tv_sec = PR_IntervalToSeconds(remaining); michael@0: if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { michael@0: wait_for_remaining = PR_FALSE; michael@0: tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; michael@0: tv.tv_usec = 0; michael@0: } else { michael@0: tv.tv_usec = PR_IntervalToMicroseconds( michael@0: remaining - michael@0: PR_SecondsToInterval(tv.tv_sec)); michael@0: } michael@0: FD_SET(osfd, &rd_wr); michael@0: if (fd_type == READ_FD) michael@0: rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); michael@0: else michael@0: rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); michael@0: /* michael@0: * we don't consider EINTR a real error michael@0: */ michael@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { michael@0: #ifdef BONE_VERSION michael@0: _PR_MD_MAP_SELECT_ERROR(syserror); michael@0: #else michael@0: if (syserror == EBADF) { michael@0: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); michael@0: } else { michael@0: PR_SetError(PR_UNKNOWN_ERROR, syserror); michael@0: } michael@0: #endif michael@0: break; michael@0: } michael@0: if (_PR_PENDING_INTERRUPT(me)) { michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); michael@0: rv = -1; michael@0: break; michael@0: } michael@0: /* michael@0: * We loop again if _MD_SELECT timed out or got interrupted michael@0: * by a signal, and the timeout deadline has not passed yet. michael@0: */ michael@0: if (rv == 0 || (rv == -1 && syserror == EINTR)) { michael@0: /* michael@0: * If _MD_SELECT timed out, we know how much time michael@0: * we spent in blocking, so we can avoid a michael@0: * PR_IntervalNow() call. michael@0: */ michael@0: if (rv == 0) { michael@0: if (wait_for_remaining) { michael@0: now += remaining; michael@0: } else { michael@0: now += PR_SecondsToInterval(tv.tv_sec) michael@0: + PR_MicrosecondsToInterval(tv.tv_usec); michael@0: } michael@0: } else { michael@0: now = PR_IntervalNow(); michael@0: } michael@0: elapsed = (PRIntervalTime) (now - epoch); michael@0: if (elapsed >= timeout) { michael@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); michael@0: rv = -1; michael@0: break; michael@0: } else { michael@0: remaining = timeout - elapsed; michael@0: } michael@0: } michael@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); michael@0: break; michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags, michael@0: PRIntervalTime timeout) michael@0: { michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: michael@0: #ifndef BONE_VERSION michael@0: if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) { michael@0: _PR_MD_MAP_RECV_ERROR(EPIPE); michael@0: return -1; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef BONE_VERSION michael@0: /* michael@0: ** Gah, stupid hack. If reading a zero amount, instantly return success. michael@0: ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of michael@0: ** mozilla use to check for socket availability. michael@0: */ michael@0: michael@0: if( 0 == amount ) return(0); michael@0: #endif michael@0: michael@0: while ((rv = recv(osfd, buf, amount, flags)) == -1) { michael@0: err = _MD_ERRNO(); michael@0: michael@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { michael@0: if (fd->secret->nonblocking) { michael@0: break; michael@0: } michael@0: /* If socket was supposed to be blocking, michael@0: wait a while for the condition to be michael@0: satisfied. */ michael@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) michael@0: goto done; michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ michael@0: continue; michael@0: michael@0: } else michael@0: break; michael@0: } michael@0: michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_RECV_ERROR(err); michael@0: } michael@0: michael@0: done: michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, michael@0: PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) michael@0: { michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: michael@0: while ((*addrlen = PR_NETADDR_SIZE(addr)), michael@0: ((rv = recvfrom(osfd, buf, amount, flags, michael@0: (struct sockaddr *) addr, michael@0: (_PRSockLen_t *)addrlen)) == -1)) { michael@0: err = _MD_ERRNO(); michael@0: michael@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { michael@0: if (fd->secret->nonblocking) { michael@0: break; michael@0: } michael@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) michael@0: goto done; michael@0: michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { michael@0: continue; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_RECVFROM_ERROR(err); michael@0: } michael@0: michael@0: done: michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: if (rv != -1) { michael@0: /* ignore the sa_len field of struct sockaddr */ michael@0: if (addr) { michael@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; michael@0: } michael@0: } michael@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags, michael@0: PRIntervalTime timeout) michael@0: { michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: michael@0: #ifndef BONE_VERSION michael@0: if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE) michael@0: { michael@0: _PR_MD_MAP_SEND_ERROR(EPIPE); michael@0: return -1; michael@0: } michael@0: #endif michael@0: michael@0: while ((rv = send(osfd, buf, amount, flags)) == -1) { michael@0: err = _MD_ERRNO(); michael@0: michael@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { michael@0: if (fd->secret->nonblocking) { michael@0: break; michael@0: } michael@0: michael@0: #ifndef BONE_VERSION michael@0: if( _PR_PENDING_INTERRUPT(me)) { michael@0: michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: michael@0: /* in UNIX implementations, you could do a socket_io_wait here. michael@0: * but since BeOS doesn't yet support WRITE notification in select, michael@0: * you're spanked. michael@0: */ michael@0: snooze( 10000L ); michael@0: continue; michael@0: #else /* BONE_VERSION */ michael@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) michael@0: goto done; michael@0: #endif michael@0: michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { michael@0: continue; michael@0: michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: #ifdef BONE_VERSION michael@0: /* michael@0: * optimization; if bytes sent is less than "amount" call michael@0: * select before returning. This is because it is likely that michael@0: * the next writev() call will return EWOULDBLOCK. michael@0: */ michael@0: if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) michael@0: && (timeout != PR_INTERVAL_NO_WAIT)) { michael@0: if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { michael@0: rv = -1; michael@0: goto done; michael@0: } michael@0: } michael@0: #endif /* BONE_VERSION */ michael@0: michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_SEND_ERROR(err); michael@0: } michael@0: michael@0: #ifdef BONE_VERSION michael@0: done: michael@0: #endif michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, michael@0: const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) michael@0: { michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: PRNetAddr addrCopy; michael@0: michael@0: addrCopy = *addr; michael@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; michael@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; michael@0: michael@0: while ((rv = sendto(osfd, buf, amount, flags, michael@0: (struct sockaddr *) &addrCopy, addrlen)) == -1) { michael@0: #else michael@0: while ((rv = sendto(osfd, buf, amount, flags, michael@0: (struct sockaddr *) addr, addrlen)) == -1) { michael@0: #endif michael@0: err = _MD_ERRNO(); michael@0: michael@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { michael@0: if (fd->secret->nonblocking) { michael@0: break; michael@0: } michael@0: michael@0: #ifdef BONE_VERSION michael@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) michael@0: goto done; michael@0: #endif michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { michael@0: continue; michael@0: michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_SENDTO_ERROR(err); michael@0: } michael@0: michael@0: #ifdef BONE_VERSION michael@0: done: michael@0: #endif michael@0: return(rv); michael@0: } michael@0: michael@0: #ifdef BONE_VERSION michael@0: michael@0: PRInt32 _MD_writev( michael@0: PRFileDesc *fd, const PRIOVec *iov, michael@0: PRInt32 iov_size, PRIntervalTime timeout) michael@0: { michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: PRInt32 index, amount = 0; michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: struct iovec osiov[PR_MAX_IOVECTOR_SIZE]; michael@0: michael@0: /* Ensured by PR_Writev */ michael@0: PR_ASSERT(iov_size <= PR_MAX_IOVECTOR_SIZE); michael@0: michael@0: /* michael@0: * We can't pass iov to writev because PRIOVec and struct iovec michael@0: * may not be binary compatible. Make osiov a copy of iov and michael@0: * pass osiov to writev. michael@0: */ michael@0: for (index = 0; index < iov_size; index++) { michael@0: osiov[index].iov_base = iov[index].iov_base; michael@0: osiov[index].iov_len = iov[index].iov_len; michael@0: } michael@0: michael@0: /* michael@0: * Calculate the total number of bytes to be sent; needed for michael@0: * optimization later. michael@0: * We could avoid this if this number was passed in; but it is michael@0: * probably not a big deal because iov_size is usually small (less than michael@0: * 3) michael@0: */ michael@0: if (!fd->secret->nonblocking) { michael@0: for (index=0; indexsecret->nonblocking) { michael@0: break; michael@0: } michael@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) michael@0: goto done; michael@0: michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ michael@0: continue; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * optimization; if bytes sent is less than "amount" call michael@0: * select before returning. This is because it is likely that michael@0: * the next writev() call will return EWOULDBLOCK. michael@0: */ michael@0: if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) michael@0: && (timeout != PR_INTERVAL_NO_WAIT)) { michael@0: if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { michael@0: rv = -1; michael@0: goto done; michael@0: } michael@0: } michael@0: michael@0: michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_WRITEV_ERROR(err); michael@0: } michael@0: done: michael@0: return(rv); michael@0: } michael@0: michael@0: #endif /* BONE_VERSION */ michael@0: michael@0: PRInt32 michael@0: _MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, michael@0: PRIntervalTime timeout) michael@0: { michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: michael@0: while ((rv = accept(osfd, (struct sockaddr *) addr, michael@0: (_PRSockLen_t *)addrlen)) == -1) { michael@0: err = _MD_ERRNO(); michael@0: michael@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { michael@0: if (fd->secret->nonblocking) { michael@0: break; michael@0: } michael@0: /* If it's SUPPOSED to be a blocking thread, wait michael@0: * a while to see if the triggering condition gets michael@0: * satisfied. michael@0: */ michael@0: /* Assume that we're always using a native thread */ michael@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) michael@0: goto done; michael@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { michael@0: continue; michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: if (rv < 0) { michael@0: _PR_MD_MAP_ACCEPT_ERROR(err); michael@0: } else if (addr != NULL) { michael@0: /* bug 134099 */ michael@0: err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); michael@0: } michael@0: done: michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: if (rv != -1) { michael@0: /* Mask off the first byte of struct sockaddr (the length field) */ michael@0: if (addr) { michael@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; michael@0: } michael@0: } michael@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, michael@0: PRIntervalTime timeout) michael@0: { michael@0: PRInt32 rv, err; michael@0: PRThread *me = _PR_MD_CURRENT_THREAD(); michael@0: PRInt32 osfd = fd->secret->md.osfd; michael@0: michael@0: #ifndef BONE_VERSION michael@0: fd->secret->md.connectValueValid = PR_FALSE; michael@0: #endif michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: PRNetAddr addrCopy; michael@0: michael@0: addrCopy = *addr; michael@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; michael@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; michael@0: #endif michael@0: michael@0: /* (Copied from unix.c) michael@0: * We initiate the connection setup by making a nonblocking connect() michael@0: * call. If the connect() call fails, there are two cases we handle michael@0: * specially: michael@0: * 1. The connect() call was interrupted by a signal. In this case michael@0: * we simply retry connect(). michael@0: * 2. The NSPR socket is nonblocking and connect() fails with michael@0: * EINPROGRESS. We first wait until the socket becomes writable. michael@0: * Then we try to find out whether the connection setup succeeded michael@0: * or failed. michael@0: */ michael@0: michael@0: retry: michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { michael@0: #else michael@0: if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { michael@0: #endif michael@0: err = _MD_ERRNO(); michael@0: #ifndef BONE_VERSION michael@0: fd->secret->md.connectReturnValue = rv; michael@0: fd->secret->md.connectReturnError = err; michael@0: fd->secret->md.connectValueValid = PR_TRUE; michael@0: #endif michael@0: if( err == EINTR ) { michael@0: michael@0: if( _PR_PENDING_INTERRUPT(me)) { michael@0: michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: #ifndef BONE_VERSION michael@0: snooze( 100000L ); michael@0: #endif michael@0: goto retry; michael@0: } michael@0: michael@0: #ifndef BONE_VERSION michael@0: if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) { michael@0: michael@0: /* michael@0: ** There's no timeout on this connect, but that's not michael@0: ** a big deal, since the connect times out anyways michael@0: ** after 30 seconds. Just sleep for 1/10th of a second michael@0: ** and retry until we go through or die. michael@0: */ michael@0: michael@0: if( _PR_PENDING_INTERRUPT(me)) { michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: michael@0: goto retry; michael@0: } michael@0: michael@0: if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) { michael@0: PR_Lock(_connectLock); michael@0: if (connectCount < sizeof(connectList)/sizeof(connectList[0])) { michael@0: connectList[connectCount].osfd = osfd; michael@0: memcpy(&connectList[connectCount].addr, addr, addrlen); michael@0: connectList[connectCount].addrlen = addrlen; michael@0: connectList[connectCount].timeout = timeout; michael@0: connectCount++; michael@0: PR_Unlock(_connectLock); michael@0: _PR_MD_MAP_CONNECT_ERROR(err); michael@0: } else { michael@0: PR_Unlock(_connectLock); michael@0: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); michael@0: } michael@0: return rv; michael@0: } michael@0: #else /* BONE_VERSION */ michael@0: if(!fd->secret->nonblocking && (err == EINTR)) { michael@0: michael@0: rv = socket_io_wait(osfd, WRITE_FD, timeout); michael@0: if (rv == -1) { michael@0: return -1; michael@0: } michael@0: michael@0: PR_ASSERT(rv == 1); michael@0: if (_PR_PENDING_INTERRUPT(me)) { michael@0: me->flags &= ~_PR_INTERRUPT; michael@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: err = _MD_beos_get_nonblocking_connect_error(osfd); michael@0: if (err != 0) { michael@0: _PR_MD_MAP_CONNECT_ERROR(err); michael@0: return -1; michael@0: } michael@0: return 0; michael@0: } michael@0: #endif michael@0: michael@0: _PR_MD_MAP_CONNECT_ERROR(err); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) michael@0: { michael@0: PRInt32 rv, err; michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: PRNetAddr addrCopy; michael@0: michael@0: addrCopy = *addr; michael@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; michael@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; michael@0: rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); michael@0: #else michael@0: rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); michael@0: #endif michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_BIND_ERROR(err); michael@0: } michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_listen (PRFileDesc *fd, PRIntn backlog) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: #ifndef BONE_VERSION michael@0: /* Bug workaround! Setting listen to 0 on Be accepts no connections. michael@0: ** On most UN*Xes this sets the default. michael@0: */ michael@0: michael@0: if( backlog == 0 ) backlog = 5; michael@0: #endif michael@0: michael@0: rv = listen(fd->secret->md.osfd, backlog); michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_LISTEN_ERROR(err); michael@0: } michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_shutdown (PRFileDesc *fd, PRIntn how) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: #ifndef BONE_VERSION michael@0: if (how == PR_SHUTDOWN_SEND) michael@0: fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE; michael@0: else if (how == PR_SHUTDOWN_RCV) michael@0: fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ; michael@0: else if (how == PR_SHUTDOWN_BOTH) { michael@0: fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ); michael@0: } michael@0: michael@0: return 0; michael@0: #else /* BONE_VERSION */ michael@0: rv = shutdown(fd->secret->md.osfd, how); michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_SHUTDOWN_ERROR(err); michael@0: } michael@0: return(rv); michael@0: #endif michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_socketpair (int af, int type, int flags, PRInt32 *osfd) michael@0: { michael@0: return PR_NOT_IMPLEMENTED_ERROR; michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_close_socket (PRInt32 osfd) michael@0: { michael@0: #ifdef BONE_VERSION michael@0: close( osfd ); michael@0: #else michael@0: closesocket( osfd ); michael@0: #endif michael@0: } michael@0: michael@0: PRStatus michael@0: _MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: rv = getsockname(fd->secret->md.osfd, michael@0: (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: if (rv == 0) { michael@0: /* ignore the sa_len field of struct sockaddr */ michael@0: if (addr) { michael@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; michael@0: } michael@0: } michael@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_GETSOCKNAME_ERROR(err); michael@0: } michael@0: michael@0: return rv==0?PR_SUCCESS:PR_FAILURE; michael@0: } michael@0: michael@0: PRStatus michael@0: _MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: rv = getpeername(fd->secret->md.osfd, michael@0: (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); michael@0: michael@0: #ifdef _PR_HAVE_SOCKADDR_LEN michael@0: if (rv == 0) { michael@0: /* ignore the sa_len field of struct sockaddr */ michael@0: if (addr) { michael@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; michael@0: } michael@0: } michael@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ michael@0: michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_GETPEERNAME_ERROR(err); michael@0: } michael@0: return rv==0?PR_SUCCESS:PR_FAILURE; michael@0: } michael@0: michael@0: PRStatus michael@0: _MD_getsockopt (PRFileDesc *fd, PRInt32 level, michael@0: PRInt32 optname, char* optval, PRInt32* optlen) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: rv = getsockopt(fd->secret->md.osfd, level, optname, michael@0: optval, (_PRSockLen_t *)optlen); michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_GETSOCKOPT_ERROR(err); michael@0: } michael@0: michael@0: return rv==0?PR_SUCCESS:PR_FAILURE; michael@0: } michael@0: michael@0: PRStatus michael@0: _MD_setsockopt (PRFileDesc *fd, PRInt32 level, michael@0: PRInt32 optname, const char* optval, PRInt32 optlen) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); michael@0: if (rv < 0) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_SETSOCKOPT_ERROR(err); michael@0: } michael@0: return rv==0?PR_SUCCESS:PR_FAILURE; michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, michael@0: void *buf, PRInt32 amount, PRIntervalTime timeout) michael@0: { michael@0: return PR_NOT_IMPLEMENTED_ERROR; michael@0: } michael@0: michael@0: #ifndef BONE_VERSION michael@0: PRInt32 michael@0: _MD_socket (int af, int type, int flags) michael@0: { michael@0: PRInt32 osfd, err; michael@0: michael@0: osfd = socket( af, type, 0 ); michael@0: michael@0: if( -1 == osfd ) { michael@0: michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_SOCKET_ERROR( err ); michael@0: } michael@0: michael@0: return( osfd ); michael@0: } michael@0: #else michael@0: PRInt32 michael@0: _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) michael@0: { michael@0: PRInt32 osfd, err; michael@0: michael@0: osfd = socket(domain, type, proto); michael@0: michael@0: if (osfd == -1) { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_SOCKET_ERROR(err); michael@0: } michael@0: michael@0: return(osfd); michael@0: } michael@0: #endif michael@0: michael@0: PRInt32 michael@0: _MD_socketavailable (PRFileDesc *fd) michael@0: { michael@0: #ifdef BONE_VERSION michael@0: PRInt32 result; michael@0: michael@0: if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { michael@0: _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); michael@0: return -1; michael@0: } michael@0: return result; michael@0: #else michael@0: return PR_NOT_IMPLEMENTED_ERROR; michael@0: #endif michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_get_socket_error (void) michael@0: { michael@0: return PR_NOT_IMPLEMENTED_ERROR; michael@0: } michael@0: michael@0: PRStatus michael@0: _MD_gethostname (char *name, PRUint32 namelen) michael@0: { michael@0: PRInt32 rv, err; michael@0: michael@0: rv = gethostname(name, namelen); michael@0: if (rv == 0) michael@0: { michael@0: err = _MD_ERRNO(); michael@0: _PR_MD_MAP_GETHOSTNAME_ERROR(err); michael@0: return PR_FAILURE; michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: #ifndef BONE_VERSION michael@0: PRInt32 michael@0: _MD_beos_get_nonblocking_connect_error(PRFileDesc *fd) michael@0: { michael@0: int rv; michael@0: int flags = 0; michael@0: michael@0: rv = recv(fd->secret->md.osfd, NULL, 0, flags); michael@0: PR_ASSERT(-1 == rv || 0 == rv); michael@0: if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { michael@0: return errno; michael@0: } michael@0: return 0; /* no error */ michael@0: } michael@0: #else michael@0: PRInt32 michael@0: _MD_beos_get_nonblocking_connect_error(int osfd) michael@0: { michael@0: return PR_NOT_IMPLEMENTED_ERROR; michael@0: // int err; michael@0: // _PRSockLen_t optlen = sizeof(err); michael@0: // if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { michael@0: // return errno; michael@0: // } else { michael@0: // return err; michael@0: // } michael@0: } michael@0: #endif /* BONE_VERSION */