📄 bnet.c
字号:
/* -*- Mode: C++; c-basic-offset: 4 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "primpl.h"#include <signal.h>#include <unistd.h>#include <memory.h>#include <fcntl.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/ioctl.h>/* * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or * PRInt32* pointer to a _PRSockLen_t* pointer. */#define _PRSockLen_t int/*** Global lock variable used to bracket calls into rusty libraries that** aren't thread safe (like libc, libX, etc).*/static PRLock *_pr_rename_lock = NULL;static PRMonitor *_pr_Xfe_mon = NULL;#define READ_FD 1#define WRITE_FD 2/*** This is a support routine to handle "deferred" i/o on sockets. ** It uses "select", so it is subject to all of the BeOS limitations** (only READ notification, only sockets)*//* * socket_io_wait -- * * wait for socket i/o, periodically checking for interrupt * */static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout){ PRInt32 rv = -1; struct timeval tv; PRThread *me = _PR_MD_CURRENT_THREAD(); PRIntervalTime epoch, now, elapsed, remaining; PRBool wait_for_remaining; PRInt32 syserror; fd_set rd_wr; 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. */ 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); if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {#ifdef BONE_VERSION _PR_MD_MAP_SELECT_ERROR(syserror);#else if (syserror == EBADF) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); } else { PR_SetError(PR_UNKNOWN_ERROR, syserror); }#endif break; } 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; FD_ZERO(&rd_wr); 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. */ wait_for_remaining = PR_TRUE; tv.tv_sec = PR_IntervalToSeconds(remaining); if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { wait_for_remaining = PR_FALSE; tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; } else { tv.tv_usec = PR_IntervalToMicroseconds( remaining - PR_SecondsToInterval(tv.tv_sec)); } FD_SET(osfd, &rd_wr); if (fd_type == READ_FD) rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); else rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); /* * we don't consider EINTR a real error */ if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {#ifdef BONE_VERSION _PR_MD_MAP_SELECT_ERROR(syserror);#else if (syserror == EBADF) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); } else { PR_SetError(PR_UNKNOWN_ERROR, syserror); }#endif break; } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } /* * 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 == EINTR)) { /* * If _MD_SELECT timed out, we know how much time * we spent in blocking, so we can avoid a * PR_IntervalNow() call. */ if (rv == 0) { if (wait_for_remaining) { now += remaining; } else { now += PR_SecondsToInterval(tv.tv_sec) + PR_MicrosecondsToInterval(tv.tv_usec); } } 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 == EINTR)); break; } return(rv);}PRInt32_MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags, PRIntervalTime timeout){ PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; PRThread *me = _PR_MD_CURRENT_THREAD();#ifndef BONE_VERSION if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) { _PR_MD_MAP_RECV_ERROR(EPIPE); return -1; }#endif#ifdef BONE_VERSION /* ** Gah, stupid hack. If reading a zero amount, instantly return success. ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of ** mozilla use to check for socket availability. */ if( 0 == amount ) return(0);#endif while ((rv = recv(osfd, buf, amount, flags)) == -1) { err = _MD_ERRNO(); if ((err == EAGAIN) || (err == EWOULDBLOCK)) { if (fd->secret->nonblocking) { break; } /* If socket was supposed to be blocking, wait a while for the condition to be satisfied. */ if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) goto done; } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ continue; } else break; } if (rv < 0) { _PR_MD_MAP_RECV_ERROR(err); }done: return(rv);}PRInt32_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; PRThread *me = _PR_MD_CURRENT_THREAD(); while ((*addrlen = PR_NETADDR_SIZE(addr)), ((rv = recvfrom(osfd, buf, amount, flags, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) { err = _MD_ERRNO(); if ((err == EAGAIN) || (err == EWOULDBLOCK)) { if (fd->secret->nonblocking) { break; } if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) goto done; } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { continue; } else { break; } } if (rv < 0) { _PR_MD_MAP_RECVFROM_ERROR(err); }done:#ifdef _PR_HAVE_SOCKADDR_LEN if (rv != -1) { /* ignore the sa_len field of struct sockaddr */ if (addr) { addr->raw.family = ((struct sockaddr *) addr)->sa_family; } }#endif /* _PR_HAVE_SOCKADDR_LEN */ return(rv);}PRInt32_MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags, PRIntervalTime timeout){ PRInt32 osfd = fd->secret->md.osfd; PRInt32 rv, err; PRThread *me = _PR_MD_CURRENT_THREAD();#ifndef BONE_VERSION if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE) { _PR_MD_MAP_SEND_ERROR(EPIPE); return -1; }#endif while ((rv = send(osfd, buf, amount, flags)) == -1) { err = _MD_ERRNO(); if ((err == EAGAIN) || (err == EWOULDBLOCK)) { if (fd->secret->nonblocking) { break; }#ifndef BONE_VERSION if( _PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); return -1; } /* in UNIX implementations, you could do a socket_io_wait here. * but since BeOS doesn't yet support WRITE notification in select, * you're spanked. */ snooze( 10000L ); continue;#else /* BONE_VERSION */ if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) goto done;#endif } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { continue; } else { break; } } if (rv < 0) { _PR_MD_MAP_SEND_ERROR(err); }#ifdef BONE_VERSIONdone:#endif return(rv);}PRInt32_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; PRThread *me = _PR_MD_CURRENT_THREAD();#ifdef _PR_HAVE_SOCKADDR_LEN PRNetAddr addrCopy; addrCopy = *addr; ((struct sockaddr *) &addrCopy)->sa_len = addrlen; ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; while ((rv = sendto(osfd, buf, amount, flags, (struct sockaddr *) &addrCopy, addrlen)) == -1) {#else while ((rv = sendto(osfd, buf, amount, flags, (struct sockaddr *) addr, addrlen)) == -1) {#endif err = _MD_ERRNO(); if ((err == EAGAIN) || (err == EWOULDBLOCK)) { if (fd->secret->nonblocking) { break; }#ifdef BONE_VERSION if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) goto done;#endif } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { continue; } else { break; } } if (rv < 0) { _PR_MD_MAP_SENDTO_ERROR(err); }#ifdef BONE_VERSIONdone:#endif return(rv);}#ifdef BONE_VERSIONPRInt32 _MD_writev( PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout){ PRInt32 rv, err; PRThread *me = _PR_MD_CURRENT_THREAD(); PRInt32 index, amount = 0; PRInt32 osfd = fd->secret->md.osfd; /* * 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 = _MD_ERRNO(); if ((err == EAGAIN) || (err == EWOULDBLOCK)) { if (fd->secret->nonblocking) { break; } if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) goto done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -