tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ptio.c (130033B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 ** File:   ptio.c
      8 ** Descritpion:  Implemenation of I/O methods for pthreads
      9 */
     10 
     11 #if defined(_PR_PTHREADS)
     12 
     13 
     14 #  include <pthread.h>
     15 #  include <string.h> /* for memset() */
     16 #  include <sys/types.h>
     17 #  include <dirent.h>
     18 #  include <fcntl.h>
     19 #  include <unistd.h>
     20 #  include <sys/socket.h>
     21 #  include <sys/stat.h>
     22 #  include <sys/uio.h>
     23 #  include <sys/file.h>
     24 #  include <sys/ioctl.h>
     25 #  if defined(DARWIN)
     26 #    include <sys/utsname.h> /* for uname */
     27 #  endif
     28 #  if defined(SOLARIS)
     29 #    include <sys/filio.h> /* to pick up FIONREAD */
     30 #  endif
     31 #  ifdef _PR_POLL_AVAILABLE
     32 #    include <poll.h>
     33 #  endif
     34 #  ifdef AIX
     35 /* To pick up sysconf() */
     36 #    include <unistd.h>
     37 #    include <dlfcn.h> /* for dlopen */
     38 #  else
     39 /* To pick up getrlimit() etc. */
     40 #    include <sys/time.h>
     41 #    include <sys/resource.h>
     42 #  endif
     43 
     44 #  ifdef SOLARIS
     45 /*
     46 * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
     47 * Code built this way won't run on a system without sendfilev().
     48 * We can define HAVE_SENDFILEV by default when the minimum release
     49 * of Solaris that NSPR supports has sendfilev().
     50 */
     51 #    ifdef HAVE_SENDFILEV
     52 
     53 #      include <sys/sendfile.h>
     54 
     55 #      define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
     56 
     57 #    else
     58 
     59 #      include <dlfcn.h> /* for dlopen */
     60 
     61 /*
     62 * Match the definitions in <sys/sendfile.h>.
     63 */
     64 typedef struct sendfilevec {
     65  int sfv_fd;      /* input fd */
     66  uint_t sfv_flag; /* flags */
     67  off_t sfv_off;   /* offset to start reading from */
     68  size_t sfv_len;  /* amount of data */
     69 } sendfilevec_t;
     70 
     71 #      define SFV_FD_SELF (-2)
     72 
     73 /*
     74 * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
     75 */
     76 static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
     77 
     78 #      define SOLARIS_SENDFILEV(a, b, c, d) \
     79        (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
     80 
     81 #    endif /* HAVE_SENDFILEV */
     82 #  endif   /* SOLARIS */
     83 
     84 /*
     85 * The send_file() system call is available in AIX 4.3.2 or later.
     86 * If this file is compiled on an older AIX system, it attempts to
     87 * look up the send_file symbol at run time to determine whether
     88 * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
     89 * send_file().  On AIX 4.3.2 or later, we can safely skip this
     90 * runtime function dispatching and just use the send_file based
     91 * implementation.
     92 */
     93 #  ifdef AIX
     94 #    ifdef SF_CLOSE
     95 #      define HAVE_SEND_FILE
     96 #    endif
     97 
     98 #    ifdef HAVE_SEND_FILE
     99 
    100 #      define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
    101 
    102 #    else                              /* HAVE_SEND_FILE */
    103 
    104 /*
    105 * The following definitions match those in <sys/socket.h>
    106 * on AIX 4.3.2.
    107 */
    108 
    109 /*
    110 * Structure for the send_file() system call
    111 */
    112 struct sf_parms {
    113  /* --------- header parms ---------- */
    114  void* header_data;    /* Input/Output. Points to header buf */
    115  uint_t header_length; /* Input/Output. Length of the header */
    116  /* --------- file parms ------------ */
    117  int file_descriptor;            /* Input. File descriptor of the file */
    118  unsigned long long file_size;   /* Output. Size of the file */
    119  unsigned long long file_offset; /* Input/Output. Starting offset */
    120  long long file_bytes;           /* Input/Output. no. of bytes to send */
    121  /* --------- trailer parms --------- */
    122  void* trailer_data;    /* Input/Output. Points to trailer buf */
    123  uint_t trailer_length; /* Input/Output. Length of the trailer */
    124  /* --------- return info ----------- */
    125  unsigned long long bytes_sent; /* Output. no. of bytes sent */
    126 };
    127 
    128 /*
    129 * Flags for the send_file() system call
    130 */
    131 #      define SF_CLOSE 0x00000001      /* close the socket after completion */
    132 #      define SF_REUSE 0x00000002      /* reuse socket. not supported */
    133 #      define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */
    134 #      define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */
    135 
    136 /*
    137 * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
    138 */
    139 static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
    140 
    141 #      define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
    142 
    143 #    endif /* HAVE_SEND_FILE */
    144 #  endif   /* AIX */
    145 
    146 #  ifdef LINUX
    147 #    include <sys/sendfile.h>
    148 #  endif
    149 
    150 #  include "primpl.h"
    151 
    152 #  if defined(LINUX) || defined(ANDROID)
    153 #    include <netinet/in.h>
    154 #  endif
    155 
    156 #  ifdef DARWIN
    157 #    include <netinet/in.h>
    158 #    include <netinet/ip.h>
    159 #  endif
    160 
    161 #  ifdef HAVE_NETINET_TCP_H
    162 #    include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
    163 #  endif
    164 
    165 #  ifdef LINUX
    166 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
    167 #    ifndef TCP_CORK
    168 #      define TCP_CORK 3
    169 #    endif
    170 #    ifndef MSG_FASTOPEN
    171 #      define MSG_FASTOPEN 0x20000000
    172 #    endif
    173 #  endif
    174 
    175 #  ifdef _PR_IPV6_V6ONLY_PROBE
    176 static PRBool _pr_ipv6_v6only_on_by_default;
    177 #  endif
    178 
    179 #  if   defined(AIX4_1)
    180 #    define _PRSelectFdSetArg_t void*
    181 #  elif (defined(AIX) && !defined(AIX4_1)) || defined(SOLARIS) ||   \
    182      defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) ||    \
    183      defined(__GNU__) || defined(__GLIBC__) || defined(FREEBSD) || \
    184      defined(NETBSD) || defined(OPENBSD) || defined(NTO) ||        \
    185      defined(DARWIN) || defined(RISCOS)
    186 #    define _PRSelectFdSetArg_t fd_set*
    187 #  else
    188 #    error "Cannot determine architecture"
    189 #  endif
    190 
    191 #  if defined(SOLARIS)
    192 #    ifndef PROTO_SDP
    193 /* on solaris, SDP is a new type of protocol */
    194 #      define PROTO_SDP 257
    195 #    endif
    196 #    define _PR_HAVE_SDP
    197 #  elif defined(LINUX)
    198 #    ifndef AF_INET_SDP
    199 /* on linux, SDP is a new type of address family */
    200 #      define AF_INET_SDP 27
    201 #    endif
    202 #    define _PR_HAVE_SDP
    203 #  endif /* LINUX */
    204 
    205 static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type,
    206                                 PRBool isAcceptedSocket, PRBool imported);
    207 
    208 static PRLock* _pr_flock_lock;  /* For PR_LockFile() etc. */
    209 static PRCondVar* _pr_flock_cv; /* For PR_LockFile() etc. */
    210 static PRLock* _pr_rename_lock; /* For PR_Rename() */
    211 
    212 /**************************************************************************/
    213 
    214 /* These two functions are only used in assertions. */
    215 #  if defined(DEBUG)
    216 
    217 PRBool IsValidNetAddr(const PRNetAddr* addr) {
    218  if ((addr != NULL) && (addr->raw.family != AF_UNIX) &&
    219      (addr->raw.family != PR_AF_INET6) && (addr->raw.family != AF_INET)) {
    220    return PR_FALSE;
    221  }
    222  return PR_TRUE;
    223 }
    224 
    225 static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) {
    226  /*
    227   * The definition of the length of a Unix domain socket address
    228   * is not uniform, so we don't check it.
    229   */
    230  if ((addr != NULL) && (addr->raw.family != AF_UNIX) &&
    231      (PR_NETADDR_SIZE(addr) != addr_len)) {
    232 #    if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
    233    /*
    234     * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
    235     * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
    236     * field and is 28 bytes.  It is possible for socket functions
    237     * to return an addr_len greater than sizeof(struct sockaddr_in6).
    238     * We need to allow that.  (Bugzilla bug #77264)
    239     */
    240    if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) {
    241      return PR_TRUE;
    242    }
    243 #    endif
    244    return PR_FALSE;
    245  }
    246  return PR_TRUE;
    247 }
    248 
    249 #  endif /* DEBUG */
    250 
    251 /*****************************************************************************/
    252 /************************* I/O Continuation machinery ************************/
    253 /*****************************************************************************/
    254 
    255 /*
    256 * The polling interval defines the maximum amount of time that a thread
    257 * might hang up before an interrupt is noticed.
    258 */
    259 #  define PT_DEFAULT_POLL_MSEC 5000
    260 
    261 /*
    262 * pt_SockLen is the type for the length of a socket address
    263 * structure, used in the address length argument to bind,
    264 * connect, accept, getsockname, getpeername, etc.  Posix.1g
    265 * defines this type as socklen_t.  It is size_t or int on
    266 * most current systems.
    267 */
    268 #  if defined(HAVE_SOCKLEN_T) || (defined(__GLIBC__) && __GLIBC__ >= 2)
    269 typedef socklen_t pt_SockLen;
    270 #  elif (defined(AIX) && !defined(AIX4_1))
    271 typedef PRSize pt_SockLen;
    272 #  else
    273 typedef PRIntn pt_SockLen;
    274 #  endif
    275 
    276 typedef struct pt_Continuation pt_Continuation;
    277 typedef PRBool (*ContinuationFn)(pt_Continuation* op, PRInt16 revents);
    278 
    279 typedef enum pr_ContuationStatus {
    280  pt_continuation_pending,
    281  pt_continuation_done
    282 } pr_ContuationStatus;
    283 
    284 struct pt_Continuation {
    285  /* The building of the continuation operation */
    286  ContinuationFn function; /* what function to continue */
    287  union {
    288    PRIntn osfd;
    289  } arg1; /* #1 - the op's fd */
    290  union {
    291    void* buffer;
    292  } arg2; /* #2 - primary transfer buffer */
    293  union {
    294    PRSize amount;        /* #3 - size of 'buffer', or */
    295    pt_SockLen* addr_len; /*    - length of address */
    296 #  ifdef HPUX11
    297    /*
    298     * For sendfile()
    299     */
    300    struct file_spec {
    301      off_t offset;   /* offset in file to send */
    302      size_t nbytes;  /* length of file data to send */
    303      size_t st_size; /* file size */
    304    } file_spec;
    305 #  endif
    306  } arg3;
    307  union {
    308    PRIntn flags;
    309  } arg4; /* #4 - read/write flags */
    310  union {
    311    PRNetAddr* addr;
    312  } arg5; /* #5 - send/recv address */
    313 
    314 #  ifdef HPUX11
    315  /*
    316   * For sendfile()
    317   */
    318  int filedesc;       /* descriptor of file to send */
    319  int nbytes_to_send; /* size of header and file */
    320 #  endif              /* HPUX11 */
    321 
    322 #  ifdef SOLARIS
    323  /*
    324   * For sendfilev()
    325   */
    326  int nbytes_to_send; /* size of header and file */
    327 #  endif              /* SOLARIS */
    328 
    329 #  ifdef LINUX
    330  /*
    331   * For sendfile()
    332   */
    333  int in_fd; /* descriptor of file to send */
    334  off_t offset;
    335  size_t count;
    336 #  endif /* LINUX */
    337 
    338  PRIntervalTime timeout; /* client (relative) timeout */
    339 
    340  PRInt16 event; /* flags for poll()'s events */
    341 
    342  /*
    343  ** The representation and notification of the results of the operation.
    344  ** These function can either return an int return code or a pointer to
    345  ** some object.
    346  */
    347  union {
    348    PRSize code;
    349    void* object;
    350  } result;
    351 
    352  PRIntn syserrno;            /* in case it failed, why (errno) */
    353  pr_ContuationStatus status; /* the status of the operation */
    354 };
    355 
    356 #  if defined(DEBUG)
    357 
    358 PTDebug pt_debug; /* this is shared between several modules */
    359 
    360 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) {
    361  PTDebug stats;
    362  char buffer[100];
    363  PRExplodedTime tod;
    364  PRInt64 elapsed, aMil;
    365  stats = pt_debug; /* a copy */
    366  PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
    367  (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
    368 
    369  LL_SUB(elapsed, PR_Now(), stats.timeStarted);
    370  LL_I2L(aMil, 1000000);
    371  LL_DIV(elapsed, elapsed, aMil);
    372 
    373  if (NULL != msg) {
    374    PR_fprintf(debug_out, "%s", msg);
    375  }
    376  PR_fprintf(debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
    377  PR_fprintf(debug_out, "\tlocks [created: %u, destroyed: %u]\n",
    378             stats.locks_created, stats.locks_destroyed);
    379  PR_fprintf(debug_out, "\tlocks [acquired: %u, released: %u]\n",
    380             stats.locks_acquired, stats.locks_released);
    381  PR_fprintf(debug_out, "\tcvars [created: %u, destroyed: %u]\n",
    382             stats.cvars_created, stats.cvars_destroyed);
    383  PR_fprintf(debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
    384             stats.cvars_notified, stats.delayed_cv_deletes);
    385 } /* PT_FPrintStats */
    386 
    387 #  else
    388 
    389 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) {
    390  /* do nothing */
    391 } /* PT_FPrintStats */
    392 
    393 #  endif /* DEBUG */
    394 
    395 
    396 static void pt_poll_now(pt_Continuation* op) {
    397  PRInt32 msecs;
    398  PRIntervalTime epoch, now, elapsed, remaining;
    399  PRBool wait_for_remaining;
    400  PRThread* self = PR_GetCurrentThread();
    401 
    402  PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
    403 
    404  switch (op->timeout) {
    405    case PR_INTERVAL_NO_TIMEOUT:
    406      msecs = PT_DEFAULT_POLL_MSEC;
    407      do {
    408        PRIntn rv;
    409        struct pollfd tmp_pfd;
    410 
    411        tmp_pfd.revents = 0;
    412        tmp_pfd.fd = op->arg1.osfd;
    413        tmp_pfd.events = op->event;
    414 
    415        rv = poll(&tmp_pfd, 1, msecs);
    416 
    417        if (_PT_THREAD_INTERRUPTED(self)) {
    418          self->state &= ~PT_THREAD_ABORTED;
    419          op->result.code = -1;
    420          op->syserrno = EINTR;
    421          op->status = pt_continuation_done;
    422          return;
    423        }
    424 
    425        if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) {
    426          continue; /* go around the loop again */
    427        }
    428 
    429        if (rv > 0) {
    430          PRInt16 events = tmp_pfd.events;
    431          PRInt16 revents = tmp_pfd.revents;
    432 
    433          if ((revents & POLLNVAL) /* busted in all cases */
    434              || ((events & POLLOUT) && (revents & POLLHUP)))
    435          /* write op & hup */
    436          {
    437            op->result.code = -1;
    438            if (POLLNVAL & revents) {
    439              op->syserrno = EBADF;
    440            } else if (POLLHUP & revents) {
    441              op->syserrno = EPIPE;
    442            }
    443            op->status = pt_continuation_done;
    444          } else {
    445            if (op->function(op, revents)) {
    446              op->status = pt_continuation_done;
    447            }
    448          }
    449        } else if (rv == -1) {
    450          op->result.code = -1;
    451          op->syserrno = errno;
    452          op->status = pt_continuation_done;
    453        }
    454        /* else, poll timed out */
    455      } while (pt_continuation_done != op->status);
    456      break;
    457    default:
    458      now = epoch = PR_IntervalNow();
    459      remaining = op->timeout;
    460      do {
    461        PRIntn rv;
    462        struct pollfd tmp_pfd;
    463 
    464        tmp_pfd.revents = 0;
    465        tmp_pfd.fd = op->arg1.osfd;
    466        tmp_pfd.events = op->event;
    467 
    468        wait_for_remaining = PR_TRUE;
    469        msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
    470        if (msecs > PT_DEFAULT_POLL_MSEC) {
    471          wait_for_remaining = PR_FALSE;
    472          msecs = PT_DEFAULT_POLL_MSEC;
    473        }
    474        rv = poll(&tmp_pfd, 1, msecs);
    475 
    476        if (_PT_THREAD_INTERRUPTED(self)) {
    477          self->state &= ~PT_THREAD_ABORTED;
    478          op->result.code = -1;
    479          op->syserrno = EINTR;
    480          op->status = pt_continuation_done;
    481          return;
    482        }
    483 
    484        if (rv > 0) {
    485          PRInt16 events = tmp_pfd.events;
    486          PRInt16 revents = tmp_pfd.revents;
    487 
    488          if ((revents & POLLNVAL) /* busted in all cases */
    489              || ((events & POLLOUT) && (revents & POLLHUP)))
    490          /* write op & hup */
    491          {
    492            op->result.code = -1;
    493            if (POLLNVAL & revents) {
    494              op->syserrno = EBADF;
    495            } else if (POLLHUP & revents) {
    496              op->syserrno = EPIPE;
    497            }
    498            op->status = pt_continuation_done;
    499          } else {
    500            if (op->function(op, revents)) {
    501              op->status = pt_continuation_done;
    502            }
    503          }
    504        } else if ((rv == 0) || ((errno == EINTR) || (errno == EAGAIN))) {
    505          if (rv == 0) /* poll timed out */
    506          {
    507            if (wait_for_remaining) {
    508              now += remaining;
    509            } else {
    510              now += PR_MillisecondsToInterval(msecs);
    511            }
    512          } else {
    513            now = PR_IntervalNow();
    514          }
    515          elapsed = (PRIntervalTime)(now - epoch);
    516          if (elapsed >= op->timeout) {
    517            op->result.code = -1;
    518            op->syserrno = ETIMEDOUT;
    519            op->status = pt_continuation_done;
    520          } else {
    521            remaining = op->timeout - elapsed;
    522          }
    523        } else {
    524          op->result.code = -1;
    525          op->syserrno = errno;
    526          op->status = pt_continuation_done;
    527        }
    528      } while (pt_continuation_done != op->status);
    529      break;
    530  }
    531 
    532 } /* pt_poll_now */
    533 
    534 static PRIntn pt_Continue(pt_Continuation* op) {
    535  op->status = pt_continuation_pending; /* set default value */
    536  /*
    537   * let each thread call poll directly
    538   */
    539  pt_poll_now(op);
    540  PR_ASSERT(pt_continuation_done == op->status);
    541  return op->result.code;
    542 } /* pt_Continue */
    543 
    544 /*****************************************************************************/
    545 /*********************** specific continuation functions *********************/
    546 /*****************************************************************************/
    547 static PRBool pt_connect_cont(pt_Continuation* op, PRInt16 revents) {
    548  op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
    549  if (op->syserrno != 0) {
    550    op->result.code = -1;
    551  } else {
    552    op->result.code = 0;
    553  }
    554  return PR_TRUE; /* this one is cooked */
    555 } /* pt_connect_cont */
    556 
    557 static PRBool pt_accept_cont(pt_Continuation* op, PRInt16 revents) {
    558  op->syserrno = 0;
    559  op->result.code = accept(op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
    560  if (-1 == op->result.code) {
    561    op->syserrno = errno;
    562    if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno) {
    563      return PR_FALSE; /* do nothing - this one ain't finished */
    564    }
    565  }
    566  return PR_TRUE;
    567 } /* pt_accept_cont */
    568 
    569 static PRBool pt_read_cont(pt_Continuation* op, PRInt16 revents) {
    570  /*
    571   * Any number of bytes will complete the operation. It need
    572   * not (and probably will not) satisfy the request. The only
    573   * error we continue is EWOULDBLOCK|EAGAIN.
    574   */
    575  op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
    576  op->syserrno = errno;
    577  return ((-1 == op->result.code) &&
    578          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
    579             ? PR_FALSE
    580             : PR_TRUE;
    581 } /* pt_read_cont */
    582 
    583 static PRBool pt_recv_cont(pt_Continuation* op, PRInt16 revents) {
    584  /*
    585   * Any number of bytes will complete the operation. It need
    586   * not (and probably will not) satisfy the request. The only
    587   * error we continue is EWOULDBLOCK|EAGAIN.
    588   */
    589 #  if defined(SOLARIS)
    590  if (0 == op->arg4.flags)
    591    op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
    592  else
    593    op->result.code =
    594        recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
    595 #  else
    596  op->result.code =
    597      recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
    598 #  endif
    599  op->syserrno = errno;
    600  return ((-1 == op->result.code) &&
    601          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
    602             ? PR_FALSE
    603             : PR_TRUE;
    604 } /* pt_recv_cont */
    605 
    606 static PRBool pt_send_cont(pt_Continuation* op, PRInt16 revents) {
    607  PRIntn bytes;
    608 #  if defined(SOLARIS)
    609  PRInt32 tmp_amount = op->arg3.amount;
    610 #  endif
    611  /*
    612   * We want to write the entire amount out, no matter how many
    613   * tries it takes. Keep advancing the buffer and the decrementing
    614   * the amount until the amount goes away. Return the total bytes
    615   * (which should be the original amount) when finished (or an
    616   * error).
    617   */
    618 #  if defined(SOLARIS)
    619 retry:
    620  bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
    621 #  else
    622  bytes = send(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
    623 #  endif
    624  op->syserrno = errno;
    625 
    626 #  if defined(SOLARIS)
    627  /*
    628   * The write system call has been reported to return the ERANGE error
    629   * on occasion. Try to write in smaller chunks to workaround this bug.
    630   */
    631  if ((bytes == -1) && (op->syserrno == ERANGE)) {
    632    if (tmp_amount > 1) {
    633      tmp_amount = tmp_amount / 2; /* half the bytes */
    634      goto retry;
    635    }
    636  }
    637 #  endif
    638 
    639  if (bytes >= 0) /* this is progress */
    640  {
    641    char* bp = (char*)op->arg2.buffer;
    642    bp += bytes; /* adjust the buffer pointer */
    643    op->arg2.buffer = bp;
    644    op->result.code += bytes; /* accumulate the number sent */
    645    op->arg3.amount -= bytes; /* and reduce the required count */
    646    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
    647  }
    648  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
    649    op->result.code = -1;
    650    return PR_TRUE;
    651  } else {
    652    return PR_FALSE;
    653  }
    654 } /* pt_send_cont */
    655 
    656 static PRBool pt_write_cont(pt_Continuation* op, PRInt16 revents) {
    657  PRIntn bytes;
    658  /*
    659   * We want to write the entire amount out, no matter how many
    660   * tries it takes. Keep advancing the buffer and the decrementing
    661   * the amount until the amount goes away. Return the total bytes
    662   * (which should be the original amount) when finished (or an
    663   * error).
    664   */
    665  bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
    666  op->syserrno = errno;
    667  if (bytes >= 0) /* this is progress */
    668  {
    669    char* bp = (char*)op->arg2.buffer;
    670    bp += bytes; /* adjust the buffer pointer */
    671    op->arg2.buffer = bp;
    672    op->result.code += bytes; /* accumulate the number sent */
    673    op->arg3.amount -= bytes; /* and reduce the required count */
    674    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
    675  }
    676  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
    677    op->result.code = -1;
    678    return PR_TRUE;
    679  } else {
    680    return PR_FALSE;
    681  }
    682 } /* pt_write_cont */
    683 
    684 static PRBool pt_writev_cont(pt_Continuation* op, PRInt16 revents) {
    685  PRIntn bytes;
    686  struct iovec* iov = (struct iovec*)op->arg2.buffer;
    687  /*
    688   * Same rules as write, but continuing seems to be a bit more
    689   * complicated. As the number of bytes sent grows, we have to
    690   * redefine the vector we're pointing at. We might have to
    691   * modify an individual vector parms or we might have to eliminate
    692   * a pair altogether.
    693   */
    694  bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
    695  op->syserrno = errno;
    696  if (bytes >= 0) /* this is progress */
    697  {
    698    PRIntn iov_index;
    699    op->result.code += bytes; /* accumulate the number sent */
    700    for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index) {
    701      /* how much progress did we make in the i/o vector? */
    702      if (bytes < iov[iov_index].iov_len) {
    703        /* this element's not done yet */
    704        char** bp = (char**)&(iov[iov_index].iov_base);
    705        iov[iov_index].iov_len -= bytes; /* there's that much left */
    706        *bp += bytes;                    /* starting there */
    707        break;                           /* go off and do that */
    708      }
    709      bytes -= iov[iov_index].iov_len; /* that element's consumed */
    710    }
    711    op->arg2.buffer = &iov[iov_index]; /* new start of array */
    712    op->arg3.amount -= iov_index;      /* and array length */
    713    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
    714  }
    715  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
    716    op->result.code = -1;
    717    return PR_TRUE;
    718  } else {
    719    return PR_FALSE;
    720  }
    721 } /* pt_writev_cont */
    722 
    723 static PRBool pt_sendto_cont(pt_Continuation* op, PRInt16 revents) {
    724  PRIntn bytes =
    725      sendto(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
    726             (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
    727  op->syserrno = errno;
    728  if (bytes >= 0) /* this is progress */
    729  {
    730    char* bp = (char*)op->arg2.buffer;
    731    bp += bytes; /* adjust the buffer pointer */
    732    op->arg2.buffer = bp;
    733    op->result.code += bytes; /* accumulate the number sent */
    734    op->arg3.amount -= bytes; /* and reduce the required count */
    735    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
    736  }
    737  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
    738    op->result.code = -1;
    739    return PR_TRUE;
    740  } else {
    741    return PR_FALSE;
    742  }
    743 } /* pt_sendto_cont */
    744 
    745 static PRBool pt_recvfrom_cont(pt_Continuation* op, PRInt16 revents) {
    746  pt_SockLen addr_len = sizeof(PRNetAddr);
    747  op->result.code =
    748      recvfrom(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
    749               (struct sockaddr*)op->arg5.addr, &addr_len);
    750  op->syserrno = errno;
    751  return ((-1 == op->result.code) &&
    752          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
    753             ? PR_FALSE
    754             : PR_TRUE;
    755 } /* pt_recvfrom_cont */
    756 
    757 #  ifdef AIX
    758 static PRBool pt_aix_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
    759  struct sf_parms* sf_struct = (struct sf_parms*)op->arg2.buffer;
    760  ssize_t rv;
    761  unsigned long long saved_file_offset;
    762  long long saved_file_bytes;
    763 
    764  saved_file_offset = sf_struct->file_offset;
    765  saved_file_bytes = sf_struct->file_bytes;
    766  sf_struct->bytes_sent = 0;
    767 
    768  if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
    769    PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
    770              sf_struct->file_size);
    771  rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
    772  op->syserrno = errno;
    773 
    774  if (rv != -1) {
    775    op->result.code += sf_struct->bytes_sent;
    776    /*
    777     * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
    778     * being updated. So, 'file_bytes' is maintained by NSPR to
    779     * avoid conflict when this bug is fixed in AIX, in the future.
    780     */
    781    if (saved_file_bytes != -1) {
    782      saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
    783    }
    784    sf_struct->file_bytes = saved_file_bytes;
    785  } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
    786    op->result.code = -1;
    787  } else {
    788    return PR_FALSE;
    789  }
    790 
    791  if (rv == 1) { /* more data to send */
    792    return PR_FALSE;
    793  }
    794 
    795  return PR_TRUE;
    796 }
    797 #  endif /* AIX */
    798 
    799 #  ifdef HPUX11
    800 static PRBool pt_hpux_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
    801  struct iovec* hdtrl = (struct iovec*)op->arg2.buffer;
    802  int count;
    803 
    804  count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
    805                   op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
    806  PR_ASSERT(count <= op->nbytes_to_send);
    807  op->syserrno = errno;
    808 
    809  if (count != -1) {
    810    op->result.code += count;
    811  } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
    812    op->result.code = -1;
    813  } else {
    814    return PR_FALSE;
    815  }
    816  if (count != -1 && count < op->nbytes_to_send) {
    817    if (count < hdtrl[0].iov_len) {
    818      /* header not sent */
    819 
    820      hdtrl[0].iov_base = ((char*)hdtrl[0].iov_base) + count;
    821      hdtrl[0].iov_len -= count;
    822 
    823    } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
    824      /* header sent, file not sent */
    825      PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
    826 
    827      hdtrl[0].iov_base = NULL;
    828      hdtrl[0].iov_len = 0;
    829 
    830      op->arg3.file_spec.offset += file_nbytes_sent;
    831      op->arg3.file_spec.nbytes -= file_nbytes_sent;
    832    } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
    833                        hdtrl[1].iov_len)) {
    834      PRUint32 trailer_nbytes_sent =
    835          count - (hdtrl[0].iov_len + op->arg3.file_spec.nbytes);
    836 
    837      /* header sent, file sent, trailer not sent */
    838 
    839      hdtrl[0].iov_base = NULL;
    840      hdtrl[0].iov_len = 0;
    841      /*
    842       * set file offset and len so that no more file data is
    843       * sent
    844       */
    845      op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
    846      op->arg3.file_spec.nbytes = 0;
    847 
    848      hdtrl[1].iov_base = ((char*)hdtrl[1].iov_base) + trailer_nbytes_sent;
    849      hdtrl[1].iov_len -= trailer_nbytes_sent;
    850    }
    851    op->nbytes_to_send -= count;
    852    return PR_FALSE;
    853  }
    854 
    855  return PR_TRUE;
    856 }
    857 #  endif /* HPUX11 */
    858 
    859 #  ifdef SOLARIS
    860 static PRBool pt_solaris_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
    861  struct sendfilevec* vec = (struct sendfilevec*)op->arg2.buffer;
    862  size_t xferred;
    863  ssize_t count;
    864 
    865  count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
    866  op->syserrno = errno;
    867  PR_ASSERT((count == -1) || (count == xferred));
    868 
    869  if (count == -1) {
    870    if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN &&
    871        op->syserrno != EINTR) {
    872      op->result.code = -1;
    873      return PR_TRUE;
    874    }
    875    count = xferred;
    876  } else if (count == 0) {
    877    /*
    878     * We are now at EOF. The file was truncated. Solaris sendfile is
    879     * supposed to return 0 and no error in this case, though some versions
    880     * may return -1 and EINVAL .
    881     */
    882    op->result.code = -1;
    883    op->syserrno = 0; /* will be treated as EOF */
    884    return PR_TRUE;
    885  }
    886  PR_ASSERT(count <= op->nbytes_to_send);
    887 
    888  op->result.code += count;
    889  if (count < op->nbytes_to_send) {
    890    op->nbytes_to_send -= count;
    891 
    892    while (count >= vec->sfv_len) {
    893      count -= vec->sfv_len;
    894      vec++;
    895      op->arg3.amount--;
    896    }
    897    PR_ASSERT(op->arg3.amount > 0);
    898 
    899    vec->sfv_off += count;
    900    vec->sfv_len -= count;
    901    PR_ASSERT(vec->sfv_len > 0);
    902    op->arg2.buffer = vec;
    903 
    904    return PR_FALSE;
    905  }
    906 
    907  return PR_TRUE;
    908 }
    909 #  endif /* SOLARIS */
    910 
    911 #  ifdef LINUX
    912 static PRBool pt_linux_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
    913  ssize_t rv;
    914  off_t oldoffset;
    915 
    916  oldoffset = op->offset;
    917  rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
    918  op->syserrno = errno;
    919 
    920  if (rv == -1) {
    921    if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
    922      op->result.code = -1;
    923      return PR_TRUE;
    924    }
    925    rv = 0;
    926  }
    927  PR_ASSERT(rv == op->offset - oldoffset);
    928  op->result.code += rv;
    929  if (rv < op->count) {
    930    op->count -= rv;
    931    return PR_FALSE;
    932  }
    933  return PR_TRUE;
    934 }
    935 #  endif /* LINUX */
    936 
    937 void _PR_InitIO(void) {
    938 #  if defined(DEBUG)
    939  memset(&pt_debug, 0, sizeof(PTDebug));
    940  pt_debug.timeStarted = PR_Now();
    941 #  endif
    942 
    943  _pr_flock_lock = PR_NewLock();
    944  PR_ASSERT(NULL != _pr_flock_lock);
    945  _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
    946  PR_ASSERT(NULL != _pr_flock_cv);
    947  _pr_rename_lock = PR_NewLock();
    948  PR_ASSERT(NULL != _pr_rename_lock);
    949 
    950  _PR_InitFdCache(); /* do that */
    951 
    952  _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    953  _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    954  _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    955  PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
    956 
    957 #  ifdef _PR_IPV6_V6ONLY_PROBE
    958  /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
    959   * is turned on by default, contrary to what RFC 3493, Section
    960   * 5.3 says.  So we have to turn it off.  Find out whether we
    961   * are running on such a system.
    962   */
    963  {
    964    int osfd;
    965    osfd = socket(AF_INET6, SOCK_STREAM, 0);
    966    if (osfd != -1) {
    967      int on;
    968      socklen_t optlen = sizeof(on);
    969      if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, &optlen) == 0) {
    970        _pr_ipv6_v6only_on_by_default = on;
    971      }
    972      close(osfd);
    973    }
    974  }
    975 #  endif
    976 } /* _PR_InitIO */
    977 
    978 void _PR_CleanupIO(void) {
    979  _PR_Putfd(_pr_stdin);
    980  _pr_stdin = NULL;
    981  _PR_Putfd(_pr_stdout);
    982  _pr_stdout = NULL;
    983  _PR_Putfd(_pr_stderr);
    984  _pr_stderr = NULL;
    985 
    986  _PR_CleanupFdCache();
    987 
    988  if (_pr_flock_cv) {
    989    PR_DestroyCondVar(_pr_flock_cv);
    990    _pr_flock_cv = NULL;
    991  }
    992  if (_pr_flock_lock) {
    993    PR_DestroyLock(_pr_flock_lock);
    994    _pr_flock_lock = NULL;
    995  }
    996  if (_pr_rename_lock) {
    997    PR_DestroyLock(_pr_rename_lock);
    998    _pr_rename_lock = NULL;
    999  }
   1000 } /* _PR_CleanupIO */
   1001 
   1002 PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) {
   1003  PRFileDesc* result = NULL;
   1004  PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
   1005 
   1006  if (!_pr_initialized) {
   1007    _PR_ImplicitInitialization();
   1008  }
   1009 
   1010  switch (osfd) {
   1011    case PR_StandardInput:
   1012      result = _pr_stdin;
   1013      break;
   1014    case PR_StandardOutput:
   1015      result = _pr_stdout;
   1016      break;
   1017    case PR_StandardError:
   1018      result = _pr_stderr;
   1019      break;
   1020    default:
   1021      (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1022  }
   1023  return result;
   1024 } /* PR_GetSpecialFD */
   1025 
   1026 /*****************************************************************************/
   1027 /***************************** I/O private methods ***************************/
   1028 /*****************************************************************************/
   1029 
   1030 static PRBool pt_TestAbort(void) {
   1031  PRThread* me = PR_GetCurrentThread();
   1032  if (_PT_THREAD_INTERRUPTED(me)) {
   1033    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1034    me->state &= ~PT_THREAD_ABORTED;
   1035    return PR_TRUE;
   1036  }
   1037  return PR_FALSE;
   1038 } /* pt_TestAbort */
   1039 
   1040 static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) {
   1041  switch (syserrno) {
   1042    case EINTR:
   1043      PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1044      break;
   1045    case ETIMEDOUT:
   1046      PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
   1047      break;
   1048    default:
   1049      mapper(syserrno);
   1050  }
   1051 } /* pt_MapError */
   1052 
   1053 static PRStatus pt_Close(PRFileDesc* fd) {
   1054  if ((NULL == fd) || (NULL == fd->secret) ||
   1055      ((_PR_FILEDESC_OPEN != fd->secret->state) &&
   1056       (_PR_FILEDESC_CLOSED != fd->secret->state))) {
   1057    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1058    return PR_FAILURE;
   1059  }
   1060  if (pt_TestAbort()) {
   1061    return PR_FAILURE;
   1062  }
   1063 
   1064  if (_PR_FILEDESC_OPEN == fd->secret->state) {
   1065    if (-1 == close(fd->secret->md.osfd)) {
   1066      pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
   1067      return PR_FAILURE;
   1068    }
   1069    fd->secret->state = _PR_FILEDESC_CLOSED;
   1070  }
   1071  _PR_Putfd(fd);
   1072  return PR_SUCCESS;
   1073 } /* pt_Close */
   1074 
   1075 static PRInt32 pt_Read(PRFileDesc* fd, void* buf, PRInt32 amount) {
   1076  PRInt32 syserrno, bytes = -1;
   1077 
   1078  if (pt_TestAbort()) {
   1079    return bytes;
   1080  }
   1081 
   1082  bytes = read(fd->secret->md.osfd, buf, amount);
   1083  syserrno = errno;
   1084 
   1085  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1086      (!fd->secret->nonblocking)) {
   1087    pt_Continuation op;
   1088    op.arg1.osfd = fd->secret->md.osfd;
   1089    op.arg2.buffer = buf;
   1090    op.arg3.amount = amount;
   1091    op.timeout = PR_INTERVAL_NO_TIMEOUT;
   1092    op.function = pt_read_cont;
   1093    op.event = POLLIN | POLLPRI;
   1094    bytes = pt_Continue(&op);
   1095    syserrno = op.syserrno;
   1096  }
   1097  if (bytes < 0) {
   1098    pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
   1099  }
   1100  return bytes;
   1101 } /* pt_Read */
   1102 
   1103 static PRInt32 pt_Write(PRFileDesc* fd, const void* buf, PRInt32 amount) {
   1104  PRInt32 syserrno, bytes = -1;
   1105  PRBool fNeedContinue = PR_FALSE;
   1106 
   1107  if (pt_TestAbort()) {
   1108    return bytes;
   1109  }
   1110 
   1111  bytes = write(fd->secret->md.osfd, buf, amount);
   1112  syserrno = errno;
   1113 
   1114  if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) {
   1115    buf = (char*)buf + bytes;
   1116    amount -= bytes;
   1117    fNeedContinue = PR_TRUE;
   1118  }
   1119  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1120      (!fd->secret->nonblocking)) {
   1121    bytes = 0;
   1122    fNeedContinue = PR_TRUE;
   1123  }
   1124 
   1125  if (fNeedContinue == PR_TRUE) {
   1126    pt_Continuation op;
   1127    op.arg1.osfd = fd->secret->md.osfd;
   1128    op.arg2.buffer = (void*)buf;
   1129    op.arg3.amount = amount;
   1130    op.timeout = PR_INTERVAL_NO_TIMEOUT;
   1131    op.result.code = bytes; /* initialize the number sent */
   1132    op.function = pt_write_cont;
   1133    op.event = POLLOUT | POLLPRI;
   1134    bytes = pt_Continue(&op);
   1135    syserrno = op.syserrno;
   1136  }
   1137  if (bytes == -1) {
   1138    pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
   1139  }
   1140  return bytes;
   1141 } /* pt_Write */
   1142 
   1143 static PRInt32 pt_Writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_len,
   1144                         PRIntervalTime timeout) {
   1145  PRIntn iov_index;
   1146  PRBool fNeedContinue = PR_FALSE;
   1147  PRInt32 syserrno, bytes, rv = -1;
   1148  struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
   1149  int osiov_len;
   1150 
   1151  if (pt_TestAbort()) {
   1152    return rv;
   1153  }
   1154 
   1155  /* Ensured by PR_Writev */
   1156  PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
   1157 
   1158  /*
   1159   * We can't pass iov to writev because PRIOVec and struct iovec
   1160   * may not be binary compatible.  Make osiov a copy of iov and
   1161   * pass osiov to writev.  We can modify osiov if we need to
   1162   * continue the operation.
   1163   */
   1164  osiov = osiov_local;
   1165  osiov_len = iov_len;
   1166  for (iov_index = 0; iov_index < osiov_len; iov_index++) {
   1167    osiov[iov_index].iov_base = iov[iov_index].iov_base;
   1168    osiov[iov_index].iov_len = iov[iov_index].iov_len;
   1169  }
   1170 
   1171  rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
   1172  syserrno = errno;
   1173 
   1174  if (!fd->secret->nonblocking) {
   1175    if (bytes >= 0) {
   1176      /*
   1177       * If we moved some bytes, how does that implicate the
   1178       * i/o vector list?  In other words, exactly where are
   1179       * we within that array?  What are the parameters for
   1180       * resumption?  Maybe we're done!
   1181       */
   1182      for (; osiov_len > 0; osiov++, osiov_len--) {
   1183        if (bytes < osiov->iov_len) {
   1184          /* this one's not done yet */
   1185          osiov->iov_base = (char*)osiov->iov_base + bytes;
   1186          osiov->iov_len -= bytes;
   1187          break; /* go off and do that */
   1188        }
   1189        bytes -= osiov->iov_len; /* this one's done cooked */
   1190      }
   1191      PR_ASSERT(osiov_len > 0 || bytes == 0);
   1192      if (osiov_len > 0) {
   1193        if (PR_INTERVAL_NO_WAIT == timeout) {
   1194          rv = -1;
   1195          syserrno = ETIMEDOUT;
   1196        } else {
   1197          fNeedContinue = PR_TRUE;
   1198        }
   1199      }
   1200    } else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN) {
   1201      if (PR_INTERVAL_NO_WAIT == timeout) {
   1202        syserrno = ETIMEDOUT;
   1203      } else {
   1204        rv = 0;
   1205        fNeedContinue = PR_TRUE;
   1206      }
   1207    }
   1208  }
   1209 
   1210  if (fNeedContinue == PR_TRUE) {
   1211    pt_Continuation op;
   1212 
   1213    op.arg1.osfd = fd->secret->md.osfd;
   1214    op.arg2.buffer = (void*)osiov;
   1215    op.arg3.amount = osiov_len;
   1216    op.timeout = timeout;
   1217    op.result.code = rv;
   1218    op.function = pt_writev_cont;
   1219    op.event = POLLOUT | POLLPRI;
   1220    rv = pt_Continue(&op);
   1221    syserrno = op.syserrno;
   1222  }
   1223  if (rv == -1) {
   1224    pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
   1225  }
   1226  return rv;
   1227 } /* pt_Writev */
   1228 
   1229 static PRInt32 pt_Seek(PRFileDesc* fd, PRInt32 offset, PRSeekWhence whence) {
   1230  return _PR_MD_LSEEK(fd, offset, whence);
   1231 } /* pt_Seek */
   1232 
   1233 static PRInt64 pt_Seek64(PRFileDesc* fd, PRInt64 offset, PRSeekWhence whence) {
   1234  return _PR_MD_LSEEK64(fd, offset, whence);
   1235 } /* pt_Seek64 */
   1236 
   1237 static PRInt32 pt_Available_f(PRFileDesc* fd) {
   1238  PRInt32 result, cur, end;
   1239 
   1240  cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
   1241 
   1242  if (cur >= 0) {
   1243    end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
   1244  }
   1245 
   1246  if ((cur < 0) || (end < 0)) {
   1247    return -1;
   1248  }
   1249 
   1250  result = end - cur;
   1251  _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
   1252 
   1253  return result;
   1254 } /* pt_Available_f */
   1255 
   1256 static PRInt64 pt_Available64_f(PRFileDesc* fd) {
   1257  PRInt64 result, cur, end;
   1258  PRInt64 minus_one;
   1259 
   1260  LL_I2L(minus_one, -1);
   1261  cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
   1262 
   1263  if (LL_GE_ZERO(cur)) {
   1264    end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
   1265  }
   1266 
   1267  if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) {
   1268    return minus_one;
   1269  }
   1270 
   1271  LL_SUB(result, end, cur);
   1272  (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
   1273 
   1274  return result;
   1275 } /* pt_Available64_f */
   1276 
   1277 static PRInt32 pt_Available_s(PRFileDesc* fd) {
   1278  PRInt32 rv, bytes = -1;
   1279  if (pt_TestAbort()) {
   1280    return bytes;
   1281  }
   1282 
   1283  rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
   1284 
   1285  if (rv == -1) {
   1286    pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
   1287  }
   1288  return bytes;
   1289 } /* pt_Available_s */
   1290 
   1291 static PRInt64 pt_Available64_s(PRFileDesc* fd) {
   1292  PRInt64 rv;
   1293  LL_I2L(rv, pt_Available_s(fd));
   1294  return rv;
   1295 } /* pt_Available64_s */
   1296 
   1297 static PRStatus pt_FileInfo(PRFileDesc* fd, PRFileInfo* info) {
   1298  PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
   1299  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   1300 } /* pt_FileInfo */
   1301 
   1302 static PRStatus pt_FileInfo64(PRFileDesc* fd, PRFileInfo64* info) {
   1303  PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
   1304  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   1305 } /* pt_FileInfo64 */
   1306 
   1307 static PRStatus pt_Synch(PRFileDesc* fd) {
   1308  return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
   1309 } /* pt_Synch */
   1310 
   1311 static PRStatus pt_Fsync(PRFileDesc* fd) {
   1312  PRIntn rv = -1;
   1313  if (pt_TestAbort()) {
   1314    return PR_FAILURE;
   1315  }
   1316 
   1317  rv = fsync(fd->secret->md.osfd);
   1318  if (rv < 0) {
   1319    pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
   1320    return PR_FAILURE;
   1321  }
   1322  return PR_SUCCESS;
   1323 } /* pt_Fsync */
   1324 
   1325 static PRStatus pt_Connect(PRFileDesc* fd, const PRNetAddr* addr,
   1326                           PRIntervalTime timeout) {
   1327  PRIntn rv = -1, syserrno;
   1328  pt_SockLen addr_len;
   1329  const PRNetAddr* addrp = addr;
   1330 #  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
   1331  PRNetAddr addrCopy;
   1332 #  endif
   1333 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1334  PRUint16 md_af = addr->raw.family;
   1335 #  endif
   1336 
   1337  if (pt_TestAbort()) {
   1338    return PR_FAILURE;
   1339  }
   1340 
   1341  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1342  addr_len = PR_NETADDR_SIZE(addr);
   1343 #  ifdef _PR_INET6
   1344  if (addr->raw.family == PR_AF_INET6) {
   1345 #    ifdef _PR_HAVE_SOCKADDR_LEN
   1346    md_af = AF_INET6;
   1347 #    else
   1348    addrCopy = *addr;
   1349    addrCopy.raw.family = AF_INET6;
   1350    addrp = &addrCopy;
   1351 #    endif
   1352  }
   1353 #  endif
   1354 
   1355 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1356  addrCopy = *addr;
   1357  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
   1358  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
   1359  addrp = &addrCopy;
   1360 #  endif
   1361  rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
   1362  syserrno = errno;
   1363  if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking)) {
   1364    if (PR_INTERVAL_NO_WAIT == timeout) {
   1365      syserrno = ETIMEDOUT;
   1366    } else {
   1367      pt_Continuation op;
   1368      op.arg1.osfd = fd->secret->md.osfd;
   1369      op.arg2.buffer = (void*)addrp;
   1370      op.arg3.amount = addr_len;
   1371      op.timeout = timeout;
   1372      op.function = pt_connect_cont;
   1373      op.event = POLLOUT | POLLPRI;
   1374      rv = pt_Continue(&op);
   1375      syserrno = op.syserrno;
   1376    }
   1377  }
   1378  if (-1 == rv) {
   1379    pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
   1380    return PR_FAILURE;
   1381  }
   1382  return PR_SUCCESS;
   1383 } /* pt_Connect */
   1384 
   1385 static PRStatus pt_ConnectContinue(PRFileDesc* fd, PRInt16 out_flags) {
   1386  int err;
   1387  PRInt32 osfd;
   1388 
   1389  if (out_flags & PR_POLL_NVAL) {
   1390    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1391    return PR_FAILURE;
   1392  }
   1393  if ((out_flags &
   1394       (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP)) == 0) {
   1395    PR_ASSERT(out_flags == 0);
   1396    PR_SetError(PR_IN_PROGRESS_ERROR, 0);
   1397    return PR_FAILURE;
   1398  }
   1399 
   1400  osfd = fd->secret->md.osfd;
   1401 
   1402  err = _MD_unix_get_nonblocking_connect_error(osfd);
   1403  if (err != 0) {
   1404    _PR_MD_MAP_CONNECT_ERROR(err);
   1405    return PR_FAILURE;
   1406  }
   1407  return PR_SUCCESS;
   1408 } /* pt_ConnectContinue */
   1409 
   1410 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc* pd) {
   1411  /* Find the NSPR layer and invoke its connectcontinue method */
   1412  PRFileDesc* bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
   1413 
   1414  if (NULL == bottom) {
   1415    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1416    return PR_FAILURE;
   1417  }
   1418  return pt_ConnectContinue(bottom, pd->out_flags);
   1419 } /* PR_GetConnectStatus */
   1420 
   1421 static PRFileDesc* pt_Accept(PRFileDesc* fd, PRNetAddr* addr,
   1422                             PRIntervalTime timeout) {
   1423  PRFileDesc* newfd = NULL;
   1424  PRIntn syserrno, osfd = -1;
   1425  pt_SockLen addr_len = sizeof(PRNetAddr);
   1426 
   1427  if (pt_TestAbort()) {
   1428    return newfd;
   1429  }
   1430 
   1431 #  ifdef _PR_STRICT_ADDR_LEN
   1432  if (addr) {
   1433    /*
   1434     * Set addr->raw.family just so that we can use the
   1435     * PR_NETADDR_SIZE macro.
   1436     */
   1437    addr->raw.family = fd->secret->af;
   1438    addr_len = PR_NETADDR_SIZE(addr);
   1439  }
   1440 #  endif
   1441 
   1442  osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
   1443  syserrno = errno;
   1444 
   1445  if (osfd == -1) {
   1446    if (fd->secret->nonblocking) {
   1447      goto failed;
   1448    }
   1449 
   1450    if (EWOULDBLOCK != syserrno && EAGAIN != syserrno &&
   1451        ECONNABORTED != syserrno) {
   1452      goto failed;
   1453    } else {
   1454      if (PR_INTERVAL_NO_WAIT == timeout) {
   1455        syserrno = ETIMEDOUT;
   1456      } else {
   1457        pt_Continuation op;
   1458        op.arg1.osfd = fd->secret->md.osfd;
   1459        op.arg2.buffer = addr;
   1460        op.arg3.addr_len = &addr_len;
   1461        op.timeout = timeout;
   1462        op.function = pt_accept_cont;
   1463        op.event = POLLIN | POLLPRI;
   1464        osfd = pt_Continue(&op);
   1465        syserrno = op.syserrno;
   1466      }
   1467      if (osfd < 0) {
   1468        goto failed;
   1469      }
   1470    }
   1471  }
   1472 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1473  /* ignore the sa_len field of struct sockaddr */
   1474  if (addr) {
   1475    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
   1476  }
   1477 #  endif /* _PR_HAVE_SOCKADDR_LEN */
   1478 #  ifdef _PR_INET6
   1479  if (addr && (AF_INET6 == addr->raw.family)) {
   1480    addr->raw.family = PR_AF_INET6;
   1481  }
   1482 #  endif
   1483  newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
   1484  if (newfd == NULL) {
   1485    close(osfd); /* $$$ whoops! this doesn't work $$$ */
   1486  } else {
   1487    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1488    PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
   1489 #  ifdef LINUX
   1490    /*
   1491     * On Linux, experiments showed that the accepted sockets
   1492     * inherit the TCP_NODELAY socket option of the listening
   1493     * socket.
   1494     */
   1495    newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
   1496 #  endif
   1497  }
   1498  return newfd;
   1499 
   1500 failed:
   1501  pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
   1502  return NULL;
   1503 } /* pt_Accept */
   1504 
   1505 static PRStatus pt_Bind(PRFileDesc* fd, const PRNetAddr* addr) {
   1506  PRIntn rv;
   1507  pt_SockLen addr_len;
   1508  const PRNetAddr* addrp = addr;
   1509 #  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
   1510  PRNetAddr addrCopy;
   1511 #  endif
   1512 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1513  PRUint16 md_af = addr->raw.family;
   1514 #  endif
   1515 
   1516  if (pt_TestAbort()) {
   1517    return PR_FAILURE;
   1518  }
   1519 
   1520  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1521  if (addr->raw.family == AF_UNIX) {
   1522    /* Disallow relative pathnames */
   1523    if (addr->local.path[0] != '/'
   1524 #  if defined(LINUX)
   1525        /* Linux has abstract socket address support */
   1526        && addr->local.path[0] != 0
   1527 #  endif
   1528    ) {
   1529      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1530      return PR_FAILURE;
   1531    }
   1532  }
   1533 
   1534 #  ifdef _PR_INET6
   1535  if (addr->raw.family == PR_AF_INET6) {
   1536 #    ifdef _PR_HAVE_SOCKADDR_LEN
   1537    md_af = AF_INET6;
   1538 #    else
   1539    addrCopy = *addr;
   1540    addrCopy.raw.family = AF_INET6;
   1541    addrp = &addrCopy;
   1542 #    endif
   1543  }
   1544 #  endif
   1545 
   1546  addr_len = PR_NETADDR_SIZE(addr);
   1547 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1548  addrCopy = *addr;
   1549  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
   1550  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
   1551  addrp = &addrCopy;
   1552 #  endif
   1553  rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
   1554 
   1555  if (rv == -1) {
   1556    pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
   1557    return PR_FAILURE;
   1558  }
   1559  return PR_SUCCESS;
   1560 } /* pt_Bind */
   1561 
   1562 static PRStatus pt_Listen(PRFileDesc* fd, PRIntn backlog) {
   1563  PRIntn rv;
   1564 
   1565  if (pt_TestAbort()) {
   1566    return PR_FAILURE;
   1567  }
   1568 
   1569  rv = listen(fd->secret->md.osfd, backlog);
   1570  if (rv == -1) {
   1571    pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
   1572    return PR_FAILURE;
   1573  }
   1574  return PR_SUCCESS;
   1575 } /* pt_Listen */
   1576 
   1577 static PRStatus pt_Shutdown(PRFileDesc* fd, PRIntn how) {
   1578  PRIntn rv = -1;
   1579  if (pt_TestAbort()) {
   1580    return PR_FAILURE;
   1581  }
   1582 
   1583  rv = shutdown(fd->secret->md.osfd, how);
   1584 
   1585  if (rv == -1) {
   1586    pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
   1587    return PR_FAILURE;
   1588  }
   1589  return PR_SUCCESS;
   1590 } /* pt_Shutdown */
   1591 
   1592 static PRInt16 pt_Poll(PRFileDesc* fd, PRInt16 in_flags, PRInt16* out_flags) {
   1593  *out_flags = 0;
   1594  return in_flags;
   1595 } /* pt_Poll */
   1596 
   1597 static PRInt32 pt_Recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
   1598                       PRIntervalTime timeout) {
   1599  PRInt32 syserrno, bytes = -1;
   1600  PRIntn osflags;
   1601 
   1602  if (0 == flags) {
   1603    osflags = 0;
   1604  } else if (PR_MSG_PEEK == flags) {
   1605    osflags = MSG_PEEK;
   1606  } else {
   1607    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1608    return bytes;
   1609  }
   1610 
   1611  if (pt_TestAbort()) {
   1612    return bytes;
   1613  }
   1614 
   1615  /* recv() is a much slower call on pre-2.6 Solaris than read(). */
   1616 #  if defined(SOLARIS)
   1617  if (0 == osflags) {
   1618    bytes = read(fd->secret->md.osfd, buf, amount);
   1619  } else {
   1620    bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
   1621  }
   1622 #  else
   1623  bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
   1624 #  endif
   1625  syserrno = errno;
   1626 
   1627  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1628      (!fd->secret->nonblocking)) {
   1629    if (PR_INTERVAL_NO_WAIT == timeout) {
   1630      syserrno = ETIMEDOUT;
   1631    } else {
   1632      pt_Continuation op;
   1633      op.arg1.osfd = fd->secret->md.osfd;
   1634      op.arg2.buffer = buf;
   1635      op.arg3.amount = amount;
   1636      op.arg4.flags = osflags;
   1637      op.timeout = timeout;
   1638      op.function = pt_recv_cont;
   1639      op.event = POLLIN | POLLPRI;
   1640      bytes = pt_Continue(&op);
   1641      syserrno = op.syserrno;
   1642    }
   1643  }
   1644  if (bytes < 0) {
   1645    pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
   1646  }
   1647  return bytes;
   1648 } /* pt_Recv */
   1649 
   1650 static PRInt32 pt_SocketRead(PRFileDesc* fd, void* buf, PRInt32 amount) {
   1651  return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
   1652 } /* pt_SocketRead */
   1653 
   1654 static PRInt32 pt_Send(PRFileDesc* fd, const void* buf, PRInt32 amount,
   1655                       PRIntn flags, PRIntervalTime timeout) {
   1656  PRInt32 syserrno, bytes = -1;
   1657  PRBool fNeedContinue = PR_FALSE;
   1658 #  if defined(SOLARIS)
   1659  PRInt32 tmp_amount = amount;
   1660 #  endif
   1661 
   1662  if (pt_TestAbort()) {
   1663    return bytes;
   1664  }
   1665 
   1666  /*
   1667   * On pre-2.6 Solaris, send() is much slower than write().
   1668   * On 2.6 and beyond, with in-kernel sockets, send() and
   1669   * write() are fairly equivalent in performance.
   1670   */
   1671 #  if defined(SOLARIS)
   1672  PR_ASSERT(0 == flags);
   1673 retry:
   1674  bytes = write(fd->secret->md.osfd, buf, tmp_amount);
   1675 #  else
   1676  bytes = send(fd->secret->md.osfd, buf, amount, flags);
   1677 #  endif
   1678  syserrno = errno;
   1679 
   1680 #  if defined(SOLARIS)
   1681  /*
   1682   * The write system call has been reported to return the ERANGE error
   1683   * on occasion. Try to write in smaller chunks to workaround this bug.
   1684   */
   1685  if ((bytes == -1) && (syserrno == ERANGE)) {
   1686    if (tmp_amount > 1) {
   1687      tmp_amount = tmp_amount / 2; /* half the bytes */
   1688      goto retry;
   1689    }
   1690  }
   1691 #  endif
   1692 
   1693  if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) {
   1694    if (PR_INTERVAL_NO_WAIT == timeout) {
   1695      bytes = -1;
   1696      syserrno = ETIMEDOUT;
   1697    } else {
   1698      buf = (char*)buf + bytes;
   1699      amount -= bytes;
   1700      fNeedContinue = PR_TRUE;
   1701    }
   1702  }
   1703  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1704      (!fd->secret->nonblocking)) {
   1705    if (PR_INTERVAL_NO_WAIT == timeout) {
   1706      syserrno = ETIMEDOUT;
   1707    } else {
   1708      bytes = 0;
   1709      fNeedContinue = PR_TRUE;
   1710    }
   1711  }
   1712 
   1713  if (fNeedContinue == PR_TRUE) {
   1714    pt_Continuation op;
   1715    op.arg1.osfd = fd->secret->md.osfd;
   1716    op.arg2.buffer = (void*)buf;
   1717    op.arg3.amount = amount;
   1718    op.arg4.flags = flags;
   1719    op.timeout = timeout;
   1720    op.result.code = bytes; /* initialize the number sent */
   1721    op.function = pt_send_cont;
   1722    op.event = POLLOUT | POLLPRI;
   1723    bytes = pt_Continue(&op);
   1724    syserrno = op.syserrno;
   1725  }
   1726  if (bytes == -1) {
   1727    pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
   1728  }
   1729  return bytes;
   1730 } /* pt_Send */
   1731 
   1732 static PRInt32 pt_SocketWrite(PRFileDesc* fd, const void* buf, PRInt32 amount) {
   1733  return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
   1734 } /* pt_SocketWrite */
   1735 
   1736 static PRInt32 pt_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount,
   1737                         PRIntn flags, const PRNetAddr* addr,
   1738                         PRIntervalTime timeout) {
   1739  PRInt32 syserrno, bytes = -1;
   1740  PRBool fNeedContinue = PR_FALSE;
   1741  pt_SockLen addr_len;
   1742  const PRNetAddr* addrp = addr;
   1743 #  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
   1744  PRNetAddr addrCopy;
   1745 #  endif
   1746 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1747  PRUint16 md_af = addr->raw.family;
   1748 #  endif
   1749 
   1750  if (pt_TestAbort()) {
   1751    return bytes;
   1752  }
   1753 
   1754  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1755 #  ifdef _PR_INET6
   1756  if (addr->raw.family == PR_AF_INET6) {
   1757 #    ifdef _PR_HAVE_SOCKADDR_LEN
   1758    md_af = AF_INET6;
   1759 #    else
   1760    addrCopy = *addr;
   1761    addrCopy.raw.family = AF_INET6;
   1762    addrp = &addrCopy;
   1763 #    endif
   1764  }
   1765 #  endif
   1766 
   1767  addr_len = PR_NETADDR_SIZE(addr);
   1768 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1769  addrCopy = *addr;
   1770  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
   1771  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
   1772  addrp = &addrCopy;
   1773 #  endif
   1774  bytes = sendto(fd->secret->md.osfd, buf, amount, flags,
   1775                 (struct sockaddr*)addrp, addr_len);
   1776  syserrno = errno;
   1777  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1778      (!fd->secret->nonblocking)) {
   1779    if (PR_INTERVAL_NO_WAIT == timeout) {
   1780      syserrno = ETIMEDOUT;
   1781    } else {
   1782      fNeedContinue = PR_TRUE;
   1783    }
   1784  }
   1785  if (fNeedContinue == PR_TRUE) {
   1786    pt_Continuation op;
   1787    op.arg1.osfd = fd->secret->md.osfd;
   1788    op.arg2.buffer = (void*)buf;
   1789    op.arg3.amount = amount;
   1790    op.arg4.flags = flags;
   1791    op.arg5.addr = (PRNetAddr*)addrp;
   1792    op.timeout = timeout;
   1793    op.result.code = 0; /* initialize the number sent */
   1794    op.function = pt_sendto_cont;
   1795    op.event = POLLOUT | POLLPRI;
   1796    bytes = pt_Continue(&op);
   1797    syserrno = op.syserrno;
   1798  }
   1799  if (bytes < 0) {
   1800    pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
   1801  }
   1802  return bytes;
   1803 } /* pt_SendTo */
   1804 
   1805 #  if defined(LINUX) || defined(DARWIN)
   1806 /* Linux uses SendTo to send data during TCP Fast Open. OSX uses connectx, but
   1807 * we will make it imitate the Linux's interface. */
   1808 static PRInt32 pt_TCP_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount,
   1809                             PRIntn flags, const PRNetAddr* addr,
   1810                             PRIntervalTime timeout) {
   1811 #    if defined(LINUX) || HAS_CONNECTX
   1812  PRInt32 syserrno;
   1813  PRBool fNeedContinue = PR_FALSE;
   1814  pt_SockLen addr_len;
   1815  const PRNetAddr* addrp = addr;
   1816 #      if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
   1817  PRNetAddr addrCopy;
   1818 #      endif
   1819 #      ifdef _PR_HAVE_SOCKADDR_LEN
   1820  PRUint16 md_af = addr->raw.family;
   1821 #      endif
   1822 
   1823  if (pt_TestAbort()) {
   1824    return -1;
   1825  }
   1826 
   1827  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1828  addr_len = PR_NETADDR_SIZE(addr);
   1829 #      if defined(_PR_INET6)
   1830  if (addr->raw.family == PR_AF_INET6) {
   1831 #        ifdef _PR_HAVE_SOCKADDR_LEN
   1832    md_af = AF_INET6;
   1833 #        else
   1834    /* If _PR_INET6 is defined and it is PR_AF_INET6 we set family
   1835     * to AF_INET6. */
   1836    addrCopy = *addr;
   1837    addrCopy.raw.family = AF_INET6;
   1838    addrp = &addrCopy;
   1839 #        endif
   1840  }
   1841 #      endif
   1842 
   1843 #      ifdef _PR_HAVE_SOCKADDR_LEN
   1844  /* if _PR_HAVE_SOCKADDR_LEN is defined and it is PR_AF_INET6 we set family
   1845   * to AF_INET6 and we set address length. */
   1846  addrCopy = *addr;
   1847  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
   1848  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
   1849  addrp = &addrCopy;
   1850 #      endif
   1851 
   1852  size_t bytes = 0;
   1853  PRInt32 netResult = 0;
   1854 #      ifndef HAS_CONNECTX
   1855  netResult = sendto(fd->secret->md.osfd, buf, amount, MSG_FASTOPEN,
   1856                     (struct sockaddr*)addrp, addr_len);
   1857  if (netResult >= 0) {
   1858    bytes = netResult;
   1859  }
   1860 #      else
   1861  sa_endpoints_t endpoints;
   1862  endpoints.sae_srcif = 0;
   1863  endpoints.sae_srcaddr = NULL;
   1864  endpoints.sae_srcaddrlen = 0;
   1865  endpoints.sae_dstaddr = (struct sockaddr*)addrp;
   1866  endpoints.sae_dstaddrlen = addr_len;
   1867  struct iovec iov[1];
   1868  iov[0].iov_base = buf;
   1869  iov[0].iov_len = amount;
   1870  netResult = connectx(fd->secret->md.osfd, &endpoints, SAE_ASSOCID_ANY,
   1871                       CONNECT_DATA_IDEMPOTENT, iov, 1, &bytes, NULL);
   1872 #      endif
   1873  syserrno = errno;
   1874  if ((netResult < 0) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1875      (!fd->secret->nonblocking)) {
   1876    if (PR_INTERVAL_NO_WAIT == timeout) {
   1877      syserrno = ETIMEDOUT;
   1878    } else {
   1879      fNeedContinue = PR_TRUE;
   1880    }
   1881  }
   1882  if (fNeedContinue == PR_TRUE) {
   1883    pt_Continuation op;
   1884    op.arg1.osfd = fd->secret->md.osfd;
   1885    op.arg2.buffer = (void*)buf;
   1886    op.arg3.amount = amount;
   1887    op.arg4.flags = flags;
   1888    op.arg5.addr = (PRNetAddr*)addrp;
   1889    op.timeout = timeout;
   1890    op.result.code = 0; /* initialize the number sent */
   1891    op.function = pt_sendto_cont;
   1892    op.event = POLLOUT | POLLPRI;
   1893    netResult = pt_Continue(&op);
   1894    if (netResult >= 0) {
   1895      bytes = netResult;
   1896    }
   1897    syserrno = op.syserrno;
   1898  }
   1899  if (netResult < 0) {
   1900    pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
   1901    return -1;
   1902  }
   1903  return bytes;
   1904 #    else /* !(defined(LINUX) || HAS_CONNECTX) */
   1905  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   1906  return -1;
   1907 #    endif
   1908 } /* pt_TCP_SendTo */
   1909 #  endif /* LINUX || DARWIN */
   1910 
   1911 static PRInt32 pt_RecvFrom(PRFileDesc* fd, void* buf, PRInt32 amount,
   1912                           PRIntn flags, PRNetAddr* addr,
   1913                           PRIntervalTime timeout) {
   1914  PRBool fNeedContinue = PR_FALSE;
   1915  PRInt32 syserrno, bytes = -1;
   1916  pt_SockLen addr_len = sizeof(PRNetAddr);
   1917 
   1918  if (pt_TestAbort()) {
   1919    return bytes;
   1920  }
   1921 
   1922  bytes = recvfrom(fd->secret->md.osfd, buf, amount, flags,
   1923                   (struct sockaddr*)addr, &addr_len);
   1924  syserrno = errno;
   1925 
   1926  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
   1927      (!fd->secret->nonblocking)) {
   1928    if (PR_INTERVAL_NO_WAIT == timeout) {
   1929      syserrno = ETIMEDOUT;
   1930    } else {
   1931      fNeedContinue = PR_TRUE;
   1932    }
   1933  }
   1934 
   1935  if (fNeedContinue == PR_TRUE) {
   1936    pt_Continuation op;
   1937    op.arg1.osfd = fd->secret->md.osfd;
   1938    op.arg2.buffer = buf;
   1939    op.arg3.amount = amount;
   1940    op.arg4.flags = flags;
   1941    op.arg5.addr = addr;
   1942    op.timeout = timeout;
   1943    op.function = pt_recvfrom_cont;
   1944    op.event = POLLIN | POLLPRI;
   1945    bytes = pt_Continue(&op);
   1946    syserrno = op.syserrno;
   1947  }
   1948  if (bytes >= 0) {
   1949 #  ifdef _PR_HAVE_SOCKADDR_LEN
   1950    /* ignore the sa_len field of struct sockaddr */
   1951    if (addr) {
   1952      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
   1953    }
   1954 #  endif /* _PR_HAVE_SOCKADDR_LEN */
   1955 #  ifdef _PR_INET6
   1956    if (addr && (AF_INET6 == addr->raw.family)) {
   1957      addr->raw.family = PR_AF_INET6;
   1958    }
   1959 #  endif
   1960  } else {
   1961    pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
   1962  }
   1963  return bytes;
   1964 } /* pt_RecvFrom */
   1965 
   1966 #  ifdef AIX
   1967 #    ifndef HAVE_SEND_FILE
   1968 static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
   1969 
   1970 static void pt_aix_sendfile_init_routine(void) {
   1971  void* handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
   1972  pt_aix_sendfile_fptr = (ssize_t(*)())dlsym(handle, "send_file");
   1973  dlclose(handle);
   1974 }
   1975 
   1976 /*
   1977 * pt_AIXDispatchSendFile
   1978 */
   1979 static PRInt32 pt_AIXDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   1980                                      PRTransmitFileFlags flags,
   1981                                      PRIntervalTime timeout) {
   1982  int rv;
   1983 
   1984  rv = pthread_once(&pt_aix_sendfile_once_block, pt_aix_sendfile_init_routine);
   1985  PR_ASSERT(0 == rv);
   1986  if (pt_aix_sendfile_fptr) {
   1987    return pt_AIXSendFile(sd, sfd, flags, timeout);
   1988  } else {
   1989    return PR_EmulateSendFile(sd, sfd, flags, timeout);
   1990  }
   1991 }
   1992 #    endif /* !HAVE_SEND_FILE */
   1993 
   1994 /*
   1995 * pt_AIXSendFile
   1996 *
   1997 *    Send file sfd->fd across socket sd. If specified, header and trailer
   1998 *    buffers are sent before and after the file, respectively.
   1999 *
   2000 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
   2001 *
   2002 *    return number of bytes sent or -1 on error
   2003 *
   2004 *      This implementation takes advantage of the send_file() system
   2005 *      call available in AIX 4.3.2.
   2006 */
   2007 
   2008 static PRInt32 pt_AIXSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2009                              PRTransmitFileFlags flags,
   2010                              PRIntervalTime timeout) {
   2011  struct sf_parms sf_struct;
   2012  uint_t send_flags;
   2013  ssize_t rv;
   2014  int syserrno;
   2015  PRInt32 count;
   2016  unsigned long long saved_file_offset;
   2017  long long saved_file_bytes;
   2018 
   2019  sf_struct.header_data = (void*)sfd->header; /* cast away the 'const' */
   2020  sf_struct.header_length = sfd->hlen;
   2021  sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
   2022  sf_struct.file_size = 0;
   2023  sf_struct.file_offset = sfd->file_offset;
   2024  if (sfd->file_nbytes == 0) {
   2025    sf_struct.file_bytes = -1;
   2026  } else {
   2027    sf_struct.file_bytes = sfd->file_nbytes;
   2028  }
   2029  sf_struct.trailer_data = (void*)sfd->trailer;
   2030  sf_struct.trailer_length = sfd->tlen;
   2031  sf_struct.bytes_sent = 0;
   2032 
   2033  saved_file_offset = sf_struct.file_offset;
   2034  saved_file_bytes = sf_struct.file_bytes;
   2035 
   2036  send_flags = 0; /* flags processed at the end */
   2037 
   2038  /* The first argument to send_file() is int*. */
   2039  PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
   2040  do {
   2041    rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
   2042  } while (rv == -1 && (syserrno = errno) == EINTR);
   2043 
   2044  if (rv == -1) {
   2045    if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
   2046      count = 0; /* Not a real error.  Need to continue. */
   2047    } else {
   2048      count = -1;
   2049    }
   2050  } else {
   2051    count = sf_struct.bytes_sent;
   2052    /*
   2053     * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
   2054     * being updated. So, 'file_bytes' is maintained by NSPR to
   2055     * avoid conflict when this bug is fixed in AIX, in the future.
   2056     */
   2057    if (saved_file_bytes != -1) {
   2058      saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
   2059    }
   2060    sf_struct.file_bytes = saved_file_bytes;
   2061  }
   2062 
   2063  if ((rv == 1) || ((rv == -1) && (count == 0))) {
   2064    pt_Continuation op;
   2065 
   2066    op.arg1.osfd = sd->secret->md.osfd;
   2067    op.arg2.buffer = &sf_struct;
   2068    op.arg4.flags = send_flags;
   2069    op.result.code = count;
   2070    op.timeout = timeout;
   2071    op.function = pt_aix_sendfile_cont;
   2072    op.event = POLLOUT | POLLPRI;
   2073    count = pt_Continue(&op);
   2074    syserrno = op.syserrno;
   2075  }
   2076 
   2077  if (count == -1) {
   2078    pt_MapError(_MD_aix_map_sendfile_error, syserrno);
   2079    return -1;
   2080  }
   2081  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
   2082    PR_Close(sd);
   2083  }
   2084  PR_ASSERT(count ==
   2085            (sfd->hlen + sfd->tlen +
   2086             ((sfd->file_nbytes == 0) ? sf_struct.file_size - sfd->file_offset
   2087                                      : sfd->file_nbytes)));
   2088  return count;
   2089 }
   2090 #  endif /* AIX */
   2091 
   2092 #  ifdef HPUX11
   2093 /*
   2094 * pt_HPUXSendFile
   2095 *
   2096 *    Send file sfd->fd across socket sd. If specified, header and trailer
   2097 *    buffers are sent before and after the file, respectively.
   2098 *
   2099 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
   2100 *
   2101 *    return number of bytes sent or -1 on error
   2102 *
   2103 *      This implementation takes advantage of the sendfile() system
   2104 *      call available in HP-UX B.11.00.
   2105 */
   2106 
   2107 static PRInt32 pt_HPUXSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2108                               PRTransmitFileFlags flags,
   2109                               PRIntervalTime timeout) {
   2110  struct stat statbuf;
   2111  size_t nbytes_to_send, file_nbytes_to_send;
   2112  struct iovec hdtrl[2]; /* optional header and trailer buffers */
   2113  int send_flags;
   2114  PRInt32 count;
   2115  int syserrno;
   2116 
   2117  if (sfd->file_nbytes == 0) {
   2118    /* Get file size */
   2119    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
   2120      _PR_MD_MAP_FSTAT_ERROR(errno);
   2121      return -1;
   2122    }
   2123    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
   2124  } else {
   2125    file_nbytes_to_send = sfd->file_nbytes;
   2126  }
   2127  nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
   2128 
   2129  hdtrl[0].iov_base = (void*)sfd->header; /* cast away the 'const' */
   2130  hdtrl[0].iov_len = sfd->hlen;
   2131  hdtrl[1].iov_base = (void*)sfd->trailer;
   2132  hdtrl[1].iov_len = sfd->tlen;
   2133  /*
   2134   * SF_DISCONNECT seems to close the socket even if sendfile()
   2135   * only does a partial send on a nonblocking socket.  This
   2136   * would prevent the subsequent sendfile() calls on that socket
   2137   * from working.  So we don't use the SD_DISCONNECT flag.
   2138   */
   2139  send_flags = 0;
   2140 
   2141  do {
   2142    count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
   2143                     sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
   2144  } while (count == -1 && (syserrno = errno) == EINTR);
   2145 
   2146  if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
   2147    count = 0;
   2148  }
   2149  if (count != -1 && count < nbytes_to_send) {
   2150    pt_Continuation op;
   2151 
   2152    if (count < sfd->hlen) {
   2153      /* header not sent */
   2154 
   2155      hdtrl[0].iov_base = ((char*)sfd->header) + count;
   2156      hdtrl[0].iov_len = sfd->hlen - count;
   2157      op.arg3.file_spec.offset = sfd->file_offset;
   2158      op.arg3.file_spec.nbytes = file_nbytes_to_send;
   2159    } else if (count < (sfd->hlen + file_nbytes_to_send)) {
   2160      /* header sent, file not sent */
   2161 
   2162      hdtrl[0].iov_base = NULL;
   2163      hdtrl[0].iov_len = 0;
   2164 
   2165      op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
   2166      op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
   2167    } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
   2168      PRUint32 trailer_nbytes_sent;
   2169 
   2170      /* header sent, file sent, trailer not sent */
   2171 
   2172      hdtrl[0].iov_base = NULL;
   2173      hdtrl[0].iov_len = 0;
   2174      /*
   2175       * set file offset and len so that no more file data is
   2176       * sent
   2177       */
   2178      op.arg3.file_spec.offset = statbuf.st_size;
   2179      op.arg3.file_spec.nbytes = 0;
   2180 
   2181      trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
   2182      hdtrl[1].iov_base = ((char*)sfd->trailer) + trailer_nbytes_sent;
   2183      hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
   2184    }
   2185 
   2186    op.arg1.osfd = sd->secret->md.osfd;
   2187    op.filedesc = sfd->fd->secret->md.osfd;
   2188    op.arg2.buffer = hdtrl;
   2189    op.arg3.file_spec.st_size = statbuf.st_size;
   2190    op.arg4.flags = send_flags;
   2191    op.nbytes_to_send = nbytes_to_send - count;
   2192    op.result.code = count;
   2193    op.timeout = timeout;
   2194    op.function = pt_hpux_sendfile_cont;
   2195    op.event = POLLOUT | POLLPRI;
   2196    count = pt_Continue(&op);
   2197    syserrno = op.syserrno;
   2198  }
   2199 
   2200  if (count == -1) {
   2201    pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
   2202    return -1;
   2203  }
   2204  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
   2205    PR_Close(sd);
   2206  }
   2207  PR_ASSERT(count == nbytes_to_send);
   2208  return count;
   2209 }
   2210 
   2211 #  endif /* HPUX11 */
   2212 
   2213 #  ifdef SOLARIS
   2214 
   2215 /*
   2216 *    pt_SolarisSendFile
   2217 *
   2218 *    Send file sfd->fd across socket sd. If specified, header and trailer
   2219 *    buffers are sent before and after the file, respectively.
   2220 *
   2221 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
   2222 *
   2223 *    return number of bytes sent or -1 on error
   2224 *
   2225 *    This implementation takes advantage of the sendfilev() system
   2226 *    call available in Solaris 8.
   2227 */
   2228 
   2229 static PRInt32 pt_SolarisSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2230                                  PRTransmitFileFlags flags,
   2231                                  PRIntervalTime timeout) {
   2232  struct stat statbuf;
   2233  size_t nbytes_to_send, file_nbytes_to_send;
   2234  struct sendfilevec sfv_struct[3];
   2235  int sfvcnt = 0;
   2236  size_t xferred;
   2237  PRInt32 count;
   2238  int syserrno;
   2239 
   2240  if (sfd->file_nbytes == 0) {
   2241    /* Get file size */
   2242    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
   2243      _PR_MD_MAP_FSTAT_ERROR(errno);
   2244      return -1;
   2245    }
   2246    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
   2247  } else {
   2248    file_nbytes_to_send = sfd->file_nbytes;
   2249  }
   2250 
   2251  nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
   2252 
   2253  if (sfd->hlen != 0) {
   2254    sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
   2255    sfv_struct[sfvcnt].sfv_flag = 0;
   2256    sfv_struct[sfvcnt].sfv_off = (off_t)sfd->header;
   2257    sfv_struct[sfvcnt].sfv_len = sfd->hlen;
   2258    sfvcnt++;
   2259  }
   2260 
   2261  if (file_nbytes_to_send != 0) {
   2262    sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
   2263    sfv_struct[sfvcnt].sfv_flag = 0;
   2264    sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
   2265    sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
   2266    sfvcnt++;
   2267  }
   2268 
   2269  if (sfd->tlen != 0) {
   2270    sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
   2271    sfv_struct[sfvcnt].sfv_flag = 0;
   2272    sfv_struct[sfvcnt].sfv_off = (off_t)sfd->trailer;
   2273    sfv_struct[sfvcnt].sfv_len = sfd->tlen;
   2274    sfvcnt++;
   2275  }
   2276 
   2277  if (0 == sfvcnt) {
   2278    count = 0;
   2279    goto done;
   2280  }
   2281 
   2282  /*
   2283   * Strictly speaking, we may have sent some bytes when the
   2284   * sendfilev() is interrupted and we should retry it from an
   2285   * updated offset.  We are not doing that here.
   2286   */
   2287  count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct, sfvcnt, &xferred);
   2288 
   2289  PR_ASSERT((count == -1) || (count == xferred));
   2290 
   2291  if (count == -1) {
   2292    syserrno = errno;
   2293    if (syserrno == EINTR || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
   2294      count = xferred;
   2295    }
   2296  } else if (count == 0) {
   2297    /*
   2298     * We are now at EOF. The file was truncated. Solaris sendfile is
   2299     * supposed to return 0 and no error in this case, though some versions
   2300     * may return -1 and EINVAL .
   2301     */
   2302    count = -1;
   2303    syserrno = 0; /* will be treated as EOF */
   2304  }
   2305 
   2306  if (count != -1 && count < nbytes_to_send) {
   2307    pt_Continuation op;
   2308    struct sendfilevec* vec = sfv_struct;
   2309    PRInt32 rem = count;
   2310 
   2311    while (rem >= vec->sfv_len) {
   2312      rem -= vec->sfv_len;
   2313      vec++;
   2314      sfvcnt--;
   2315    }
   2316    PR_ASSERT(sfvcnt > 0);
   2317 
   2318    vec->sfv_off += rem;
   2319    vec->sfv_len -= rem;
   2320    PR_ASSERT(vec->sfv_len > 0);
   2321 
   2322    op.arg1.osfd = sd->secret->md.osfd;
   2323    op.arg2.buffer = vec;
   2324    op.arg3.amount = sfvcnt;
   2325    op.arg4.flags = 0;
   2326    op.nbytes_to_send = nbytes_to_send - count;
   2327    op.result.code = count;
   2328    op.timeout = timeout;
   2329    op.function = pt_solaris_sendfile_cont;
   2330    op.event = POLLOUT | POLLPRI;
   2331    count = pt_Continue(&op);
   2332    syserrno = op.syserrno;
   2333  }
   2334 
   2335 done:
   2336  if (count == -1) {
   2337    pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
   2338    return -1;
   2339  }
   2340  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
   2341    PR_Close(sd);
   2342  }
   2343  PR_ASSERT(count == nbytes_to_send);
   2344  return count;
   2345 }
   2346 
   2347 #    ifndef HAVE_SENDFILEV
   2348 static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
   2349 
   2350 static void pt_solaris_sendfilev_init_routine(void) {
   2351  void* handle;
   2352  PRBool close_it = PR_FALSE;
   2353 
   2354  /*
   2355   * We do not want to unload libsendfile.so.  This handle is leaked
   2356   * intentionally.
   2357   */
   2358  handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
   2359  PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
   2360         ("dlopen(libsendfile.so) returns %p", handle));
   2361 
   2362  if (NULL == handle) {
   2363    /*
   2364     * The dlopen(0, mode) call is to allow for the possibility that
   2365     * sendfilev() may become part of a standard system library in a
   2366     * future Solaris release.
   2367     */
   2368    handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
   2369    PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("dlopen(0) returns %p", handle));
   2370    close_it = PR_TRUE;
   2371  }
   2372  pt_solaris_sendfilev_fptr = (ssize_t(*)())dlsym(handle, "sendfilev");
   2373  PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
   2374         ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
   2375 
   2376  if (close_it) {
   2377    dlclose(handle);
   2378  }
   2379 }
   2380 
   2381 /*
   2382 * pt_SolarisDispatchSendFile
   2383 */
   2384 static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2385                                          PRTransmitFileFlags flags,
   2386                                          PRIntervalTime timeout) {
   2387  int rv;
   2388 
   2389  rv = pthread_once(&pt_solaris_sendfilev_once_block,
   2390                    pt_solaris_sendfilev_init_routine);
   2391  PR_ASSERT(0 == rv);
   2392  if (pt_solaris_sendfilev_fptr) {
   2393    return pt_SolarisSendFile(sd, sfd, flags, timeout);
   2394  } else {
   2395    return PR_EmulateSendFile(sd, sfd, flags, timeout);
   2396  }
   2397 }
   2398 #    endif /* !HAVE_SENDFILEV */
   2399 
   2400 #  endif /* SOLARIS */
   2401 
   2402 #  ifdef LINUX
   2403 /*
   2404 * pt_LinuxSendFile
   2405 *
   2406 *    Send file sfd->fd across socket sd. If specified, header and trailer
   2407 *    buffers are sent before and after the file, respectively.
   2408 *
   2409 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
   2410 *
   2411 *    return number of bytes sent or -1 on error
   2412 *
   2413 *      This implementation takes advantage of the sendfile() system
   2414 *      call available in Linux kernel 2.2 or higher.
   2415 */
   2416 
   2417 static PRInt32 pt_LinuxSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2418                                PRTransmitFileFlags flags,
   2419                                PRIntervalTime timeout) {
   2420  struct stat statbuf;
   2421  size_t file_nbytes_to_send;
   2422  PRInt32 count = 0;
   2423  ssize_t rv;
   2424  int syserrno;
   2425  off_t offset;
   2426  PRBool tcp_cork_enabled = PR_FALSE;
   2427  int tcp_cork;
   2428 
   2429  if (sfd->file_nbytes == 0) {
   2430    /* Get file size */
   2431    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
   2432      _PR_MD_MAP_FSTAT_ERROR(errno);
   2433      return -1;
   2434    }
   2435    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
   2436  } else {
   2437    file_nbytes_to_send = sfd->file_nbytes;
   2438  }
   2439 
   2440  if ((sfd->hlen != 0 || sfd->tlen != 0) && sd->secret->md.tcp_nodelay == 0) {
   2441    tcp_cork = 1;
   2442    if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork,
   2443                   sizeof tcp_cork) == 0) {
   2444      tcp_cork_enabled = PR_TRUE;
   2445    } else {
   2446      syserrno = errno;
   2447      if (syserrno != EINVAL) {
   2448        _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
   2449        return -1;
   2450      }
   2451      /*
   2452       * The most likely reason for the EINVAL error is that
   2453       * TCP_NODELAY is set (with a function other than
   2454       * PR_SetSocketOption).  This is not fatal, so we keep
   2455       * on going.
   2456       */
   2457      PR_LOG(_pr_io_lm, PR_LOG_WARNING,
   2458             ("pt_LinuxSendFile: "
   2459              "setsockopt(TCP_CORK) failed with EINVAL\n"));
   2460    }
   2461  }
   2462 
   2463  if (sfd->hlen != 0) {
   2464    count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
   2465    if (count == -1) {
   2466      goto failed;
   2467    }
   2468  }
   2469 
   2470  if (file_nbytes_to_send != 0) {
   2471    offset = sfd->file_offset;
   2472    do {
   2473      rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, &offset,
   2474                    file_nbytes_to_send);
   2475    } while (rv == -1 && (syserrno = errno) == EINTR);
   2476    if (rv == -1) {
   2477      if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
   2478        _MD_linux_map_sendfile_error(syserrno);
   2479        count = -1;
   2480        goto failed;
   2481      }
   2482      rv = 0;
   2483    }
   2484    PR_ASSERT(rv == offset - sfd->file_offset);
   2485    count += rv;
   2486 
   2487    if (rv < file_nbytes_to_send) {
   2488      pt_Continuation op;
   2489 
   2490      op.arg1.osfd = sd->secret->md.osfd;
   2491      op.in_fd = sfd->fd->secret->md.osfd;
   2492      op.offset = offset;
   2493      op.count = file_nbytes_to_send - rv;
   2494      op.result.code = count;
   2495      op.timeout = timeout;
   2496      op.function = pt_linux_sendfile_cont;
   2497      op.event = POLLOUT | POLLPRI;
   2498      count = pt_Continue(&op);
   2499      syserrno = op.syserrno;
   2500      if (count == -1) {
   2501        pt_MapError(_MD_linux_map_sendfile_error, syserrno);
   2502        goto failed;
   2503      }
   2504    }
   2505  }
   2506 
   2507  if (sfd->tlen != 0) {
   2508    rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
   2509    if (rv == -1) {
   2510      count = -1;
   2511      goto failed;
   2512    }
   2513    count += rv;
   2514  }
   2515 
   2516 failed:
   2517  if (tcp_cork_enabled) {
   2518    tcp_cork = 0;
   2519    if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork,
   2520                   sizeof tcp_cork) == -1 &&
   2521        count != -1) {
   2522      _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
   2523      count = -1;
   2524    }
   2525  }
   2526  if (count != -1) {
   2527    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
   2528      PR_Close(sd);
   2529    }
   2530    PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
   2531  }
   2532  return count;
   2533 }
   2534 #  endif /* LINUX */
   2535 
   2536 #  ifdef AIX
   2537 extern int _pr_aix_send_file_use_disabled;
   2538 #  endif
   2539 
   2540 static PRInt32 pt_SendFile(PRFileDesc* sd, PRSendFileData* sfd,
   2541                           PRTransmitFileFlags flags, PRIntervalTime timeout) {
   2542  if (pt_TestAbort()) {
   2543    return -1;
   2544  }
   2545  /* The socket must be in blocking mode. */
   2546  if (sd->secret->nonblocking) {
   2547    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   2548    return -1;
   2549  }
   2550 #  ifdef HPUX11
   2551  return (pt_HPUXSendFile(sd, sfd, flags, timeout));
   2552 #  elif defined(AIX)
   2553 #    ifdef HAVE_SEND_FILE
   2554  /*
   2555   * A bug in AIX 4.3.2 results in corruption of data transferred by
   2556   * send_file(); AIX patch PTF U463956 contains the fix.  A user can
   2557   * disable the use of send_file function in NSPR, when this patch is
   2558   * not installed on the system, by setting the envionment variable
   2559   * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
   2560   */
   2561  if (_pr_aix_send_file_use_disabled) {
   2562    return (PR_EmulateSendFile(sd, sfd, flags, timeout));
   2563  } else {
   2564    return (pt_AIXSendFile(sd, sfd, flags, timeout));
   2565  }
   2566 #    else
   2567  return (PR_EmulateSendFile(sd, sfd, flags, timeout));
   2568  /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
   2569 #    endif /* HAVE_SEND_FILE */
   2570 #  elif defined(SOLARIS)
   2571 #    ifdef HAVE_SENDFILEV
   2572  return (pt_SolarisSendFile(sd, sfd, flags, timeout));
   2573 #    else
   2574  return (pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
   2575 #    endif /* HAVE_SENDFILEV */
   2576 #  elif defined(LINUX)
   2577  return (pt_LinuxSendFile(sd, sfd, flags, timeout));
   2578 #  else
   2579  return (PR_EmulateSendFile(sd, sfd, flags, timeout));
   2580 #  endif
   2581 }
   2582 
   2583 static PRInt32 pt_TransmitFile(PRFileDesc* sd, PRFileDesc* fd,
   2584                               const void* headers, PRInt32 hlen,
   2585                               PRTransmitFileFlags flags,
   2586                               PRIntervalTime timeout) {
   2587  PRSendFileData sfd;
   2588 
   2589  sfd.fd = fd;
   2590  sfd.file_offset = 0;
   2591  sfd.file_nbytes = 0;
   2592  sfd.header = headers;
   2593  sfd.hlen = hlen;
   2594  sfd.trailer = NULL;
   2595  sfd.tlen = 0;
   2596 
   2597  return (pt_SendFile(sd, &sfd, flags, timeout));
   2598 } /* pt_TransmitFile */
   2599 
   2600 static PRInt32 pt_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
   2601                             void* buf, PRInt32 amount,
   2602                             PRIntervalTime timeout) {
   2603  PRInt32 rv = -1;
   2604 
   2605  if (pt_TestAbort()) {
   2606    return rv;
   2607  }
   2608  /* The socket must be in blocking mode. */
   2609  if (sd->secret->nonblocking) {
   2610    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   2611    return rv;
   2612  }
   2613 
   2614  rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
   2615  return rv;
   2616 } /* pt_AcceptRead */
   2617 
   2618 static PRStatus pt_GetSockName(PRFileDesc* fd, PRNetAddr* addr) {
   2619  PRIntn rv = -1;
   2620  pt_SockLen addr_len = sizeof(PRNetAddr);
   2621 
   2622  if (pt_TestAbort()) {
   2623    return PR_FAILURE;
   2624  }
   2625 
   2626  rv = getsockname(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
   2627  if (rv == -1) {
   2628    pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
   2629    return PR_FAILURE;
   2630  }
   2631 #  ifdef _PR_HAVE_SOCKADDR_LEN
   2632  /* ignore the sa_len field of struct sockaddr */
   2633  if (addr) {
   2634    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
   2635  }
   2636 #  endif /* _PR_HAVE_SOCKADDR_LEN */
   2637 #  ifdef _PR_INET6
   2638  if (AF_INET6 == addr->raw.family) {
   2639    addr->raw.family = PR_AF_INET6;
   2640  }
   2641 #  endif
   2642  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   2643  PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
   2644  return PR_SUCCESS;
   2645 } /* pt_GetSockName */
   2646 
   2647 static PRStatus pt_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
   2648  PRIntn rv = -1;
   2649  pt_SockLen addr_len = sizeof(PRNetAddr);
   2650 
   2651  if (pt_TestAbort()) {
   2652    return PR_FAILURE;
   2653  }
   2654 
   2655  rv = getpeername(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
   2656 
   2657  if (rv == -1) {
   2658    pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
   2659    return PR_FAILURE;
   2660  }
   2661 #  ifdef _PR_HAVE_SOCKADDR_LEN
   2662  /* ignore the sa_len field of struct sockaddr */
   2663  if (addr) {
   2664    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
   2665  }
   2666 #  endif /* _PR_HAVE_SOCKADDR_LEN */
   2667 #  ifdef _PR_INET6
   2668  if (AF_INET6 == addr->raw.family) {
   2669    addr->raw.family = PR_AF_INET6;
   2670  }
   2671 #  endif
   2672  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   2673  PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
   2674  return PR_SUCCESS;
   2675 } /* pt_GetPeerName */
   2676 
   2677 static PRStatus pt_GetSocketOption(PRFileDesc* fd, PRSocketOptionData* data) {
   2678  PRIntn rv;
   2679  pt_SockLen length;
   2680  PRInt32 level, name;
   2681 
   2682  /*
   2683   * PR_SockOpt_Nonblocking is a special case that does not
   2684   * translate to a getsockopt() call
   2685   */
   2686  if (PR_SockOpt_Nonblocking == data->option) {
   2687    data->value.non_blocking = fd->secret->nonblocking;
   2688    return PR_SUCCESS;
   2689  }
   2690 
   2691  rv = _PR_MapOptionName(data->option, &level, &name);
   2692  if (PR_SUCCESS == rv) {
   2693    switch (data->option) {
   2694      case PR_SockOpt_Linger: {
   2695        struct linger linger;
   2696        length = sizeof(linger);
   2697        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&linger,
   2698                        &length);
   2699        PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
   2700        data->value.linger.polarity = (linger.l_onoff) ? PR_TRUE : PR_FALSE;
   2701        data->value.linger.linger = PR_SecondsToInterval(linger.l_linger);
   2702        break;
   2703      }
   2704      case PR_SockOpt_Reuseaddr:
   2705      case PR_SockOpt_Keepalive:
   2706      case PR_SockOpt_NoDelay:
   2707      case PR_SockOpt_Broadcast:
   2708      case PR_SockOpt_Reuseport: {
   2709        PRIntn value;
   2710        length = sizeof(PRIntn);
   2711        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2712                        &length);
   2713        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
   2714        data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
   2715        break;
   2716      }
   2717      case PR_SockOpt_McastLoopback: {
   2718        PRUint8 xbool;
   2719        length = sizeof(xbool);
   2720        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&xbool,
   2721                        &length);
   2722        PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
   2723        data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
   2724        break;
   2725      }
   2726      case PR_SockOpt_RecvBufferSize:
   2727      case PR_SockOpt_SendBufferSize:
   2728      case PR_SockOpt_MaxSegment: {
   2729        PRIntn value;
   2730        length = sizeof(PRIntn);
   2731        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2732                        &length);
   2733        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
   2734        data->value.recv_buffer_size = value;
   2735        break;
   2736      }
   2737      case PR_SockOpt_IpTimeToLive:
   2738      case PR_SockOpt_IpTypeOfService: {
   2739        length = sizeof(PRUintn);
   2740        rv = getsockopt(fd->secret->md.osfd, level, name,
   2741                        (char*)&data->value.ip_ttl, &length);
   2742        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
   2743        break;
   2744      }
   2745      case PR_SockOpt_McastTimeToLive: {
   2746        PRUint8 ttl;
   2747        length = sizeof(ttl);
   2748        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&ttl, &length);
   2749        PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
   2750        data->value.mcast_ttl = ttl;
   2751        break;
   2752      }
   2753      case PR_SockOpt_AddMember:
   2754      case PR_SockOpt_DropMember: {
   2755        struct ip_mreq mreq;
   2756        length = sizeof(mreq);
   2757        rv =
   2758            getsockopt(fd->secret->md.osfd, level, name, (char*)&mreq, &length);
   2759        PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
   2760        data->value.add_member.mcaddr.inet.ip = mreq.imr_multiaddr.s_addr;
   2761        data->value.add_member.ifaddr.inet.ip = mreq.imr_interface.s_addr;
   2762        break;
   2763      }
   2764      case PR_SockOpt_McastInterface: {
   2765        length = sizeof(data->value.mcast_if.inet.ip);
   2766        rv = getsockopt(fd->secret->md.osfd, level, name,
   2767                        (char*)&data->value.mcast_if.inet.ip, &length);
   2768        PR_ASSERT((-1 == rv) ||
   2769                  (sizeof(data->value.mcast_if.inet.ip) == length));
   2770        break;
   2771      }
   2772      case PR_SockOpt_DontFrag: {
   2773 #  if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
   2774        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
   2775        rv = PR_FAILURE;
   2776 #  else
   2777        PRIntn value;
   2778        length = sizeof(value);
   2779        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2780                        &length);
   2781 #    if defined(DARWIN)
   2782        data->value.dont_fragment = value;
   2783 #    else
   2784        data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0;
   2785 #    endif
   2786 #  endif /* !(!defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
   2787        break;
   2788      }
   2789      default:
   2790        PR_NOT_REACHED("Unknown socket option");
   2791        break;
   2792    }
   2793    if (-1 == rv) {
   2794      _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
   2795    }
   2796  }
   2797  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   2798 } /* pt_GetSocketOption */
   2799 
   2800 static PRStatus pt_SetSocketOption(PRFileDesc* fd,
   2801                                   const PRSocketOptionData* data) {
   2802  PRIntn rv;
   2803  PRInt32 level, name;
   2804 
   2805  /*
   2806   * PR_SockOpt_Nonblocking is a special case that does not
   2807   * translate to a setsockopt call.
   2808   */
   2809  if (PR_SockOpt_Nonblocking == data->option) {
   2810    fd->secret->nonblocking = data->value.non_blocking;
   2811    return PR_SUCCESS;
   2812  }
   2813 
   2814  rv = _PR_MapOptionName(data->option, &level, &name);
   2815  if (PR_SUCCESS == rv) {
   2816    switch (data->option) {
   2817      case PR_SockOpt_Linger: {
   2818        struct linger linger;
   2819        linger.l_onoff = data->value.linger.polarity;
   2820        linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
   2821        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&linger,
   2822                        sizeof(linger));
   2823        break;
   2824      }
   2825      case PR_SockOpt_Reuseaddr:
   2826      case PR_SockOpt_Keepalive:
   2827      case PR_SockOpt_NoDelay:
   2828      case PR_SockOpt_Broadcast:
   2829      case PR_SockOpt_Reuseport: {
   2830        PRIntn value = (data->value.reuse_addr) ? 1 : 0;
   2831        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2832                        sizeof(PRIntn));
   2833 #  ifdef LINUX
   2834        /* for pt_LinuxSendFile */
   2835        if (name == TCP_NODELAY && rv == 0) {
   2836          fd->secret->md.tcp_nodelay = value;
   2837        }
   2838 #  endif
   2839        break;
   2840      }
   2841      case PR_SockOpt_McastLoopback: {
   2842        PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
   2843        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&xbool,
   2844                        sizeof(xbool));
   2845        break;
   2846      }
   2847      case PR_SockOpt_RecvBufferSize:
   2848      case PR_SockOpt_SendBufferSize:
   2849      case PR_SockOpt_MaxSegment: {
   2850        PRIntn value = data->value.recv_buffer_size;
   2851        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2852                        sizeof(PRIntn));
   2853        break;
   2854      }
   2855      case PR_SockOpt_IpTimeToLive:
   2856      case PR_SockOpt_IpTypeOfService: {
   2857        rv = setsockopt(fd->secret->md.osfd, level, name,
   2858                        (char*)&data->value.ip_ttl, sizeof(PRUintn));
   2859        break;
   2860      }
   2861      case PR_SockOpt_McastTimeToLive: {
   2862        PRUint8 ttl = data->value.mcast_ttl;
   2863        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&ttl,
   2864                        sizeof(ttl));
   2865        break;
   2866      }
   2867      case PR_SockOpt_AddMember:
   2868      case PR_SockOpt_DropMember: {
   2869        struct ip_mreq mreq;
   2870        mreq.imr_multiaddr.s_addr = data->value.add_member.mcaddr.inet.ip;
   2871        mreq.imr_interface.s_addr = data->value.add_member.ifaddr.inet.ip;
   2872        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&mreq,
   2873                        sizeof(mreq));
   2874        break;
   2875      }
   2876      case PR_SockOpt_McastInterface: {
   2877        rv = setsockopt(fd->secret->md.osfd, level, name,
   2878                        (char*)&data->value.mcast_if.inet.ip,
   2879                        sizeof(data->value.mcast_if.inet.ip));
   2880        break;
   2881      }
   2882      case PR_SockOpt_DontFrag: {
   2883 #  if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
   2884        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
   2885        rv = PR_FAILURE;
   2886 #  else
   2887        PRIntn value;
   2888 #    if defined(LINUX) || defined(ANDROID)
   2889        value = (data->value.dont_fragment) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
   2890 #    elif defined(DARWIN)
   2891        value = data->value.dont_fragment;
   2892 #    endif
   2893        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
   2894                        sizeof(value));
   2895 #  endif /* !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
   2896        break;
   2897      }
   2898      default:
   2899        PR_NOT_REACHED("Unknown socket option");
   2900        break;
   2901    }
   2902    if (-1 == rv) {
   2903      _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
   2904    }
   2905  }
   2906  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   2907 } /* pt_SetSocketOption */
   2908 
   2909 /*****************************************************************************/
   2910 /****************************** I/O method objects ***************************/
   2911 /*****************************************************************************/
   2912 
   2913 static PRIOMethods _pr_file_methods = {PR_DESC_FILE,
   2914                                       pt_Close,
   2915                                       pt_Read,
   2916                                       pt_Write,
   2917                                       pt_Available_f,
   2918                                       pt_Available64_f,
   2919                                       pt_Fsync,
   2920                                       pt_Seek,
   2921                                       pt_Seek64,
   2922                                       pt_FileInfo,
   2923                                       pt_FileInfo64,
   2924                                       (PRWritevFN)_PR_InvalidInt,
   2925                                       (PRConnectFN)_PR_InvalidStatus,
   2926                                       (PRAcceptFN)_PR_InvalidDesc,
   2927                                       (PRBindFN)_PR_InvalidStatus,
   2928                                       (PRListenFN)_PR_InvalidStatus,
   2929                                       (PRShutdownFN)_PR_InvalidStatus,
   2930                                       (PRRecvFN)_PR_InvalidInt,
   2931                                       (PRSendFN)_PR_InvalidInt,
   2932                                       (PRRecvfromFN)_PR_InvalidInt,
   2933                                       (PRSendtoFN)_PR_InvalidInt,
   2934                                       pt_Poll,
   2935                                       (PRAcceptreadFN)_PR_InvalidInt,
   2936                                       (PRTransmitfileFN)_PR_InvalidInt,
   2937                                       (PRGetsocknameFN)_PR_InvalidStatus,
   2938                                       (PRGetpeernameFN)_PR_InvalidStatus,
   2939                                       (PRReservedFN)_PR_InvalidInt,
   2940                                       (PRReservedFN)_PR_InvalidInt,
   2941                                       (PRGetsocketoptionFN)_PR_InvalidStatus,
   2942                                       (PRSetsocketoptionFN)_PR_InvalidStatus,
   2943                                       (PRSendfileFN)_PR_InvalidInt,
   2944                                       (PRConnectcontinueFN)_PR_InvalidStatus,
   2945                                       (PRReservedFN)_PR_InvalidInt,
   2946                                       (PRReservedFN)_PR_InvalidInt,
   2947                                       (PRReservedFN)_PR_InvalidInt,
   2948                                       (PRReservedFN)_PR_InvalidInt};
   2949 
   2950 static PRIOMethods _pr_pipe_methods = {PR_DESC_PIPE,
   2951                                       pt_Close,
   2952                                       pt_Read,
   2953                                       pt_Write,
   2954                                       pt_Available_s,
   2955                                       pt_Available64_s,
   2956                                       pt_Synch,
   2957                                       (PRSeekFN)_PR_InvalidInt,
   2958                                       (PRSeek64FN)_PR_InvalidInt64,
   2959                                       (PRFileInfoFN)_PR_InvalidStatus,
   2960                                       (PRFileInfo64FN)_PR_InvalidStatus,
   2961                                       (PRWritevFN)_PR_InvalidInt,
   2962                                       (PRConnectFN)_PR_InvalidStatus,
   2963                                       (PRAcceptFN)_PR_InvalidDesc,
   2964                                       (PRBindFN)_PR_InvalidStatus,
   2965                                       (PRListenFN)_PR_InvalidStatus,
   2966                                       (PRShutdownFN)_PR_InvalidStatus,
   2967                                       (PRRecvFN)_PR_InvalidInt,
   2968                                       (PRSendFN)_PR_InvalidInt,
   2969                                       (PRRecvfromFN)_PR_InvalidInt,
   2970                                       (PRSendtoFN)_PR_InvalidInt,
   2971                                       pt_Poll,
   2972                                       (PRAcceptreadFN)_PR_InvalidInt,
   2973                                       (PRTransmitfileFN)_PR_InvalidInt,
   2974                                       (PRGetsocknameFN)_PR_InvalidStatus,
   2975                                       (PRGetpeernameFN)_PR_InvalidStatus,
   2976                                       (PRReservedFN)_PR_InvalidInt,
   2977                                       (PRReservedFN)_PR_InvalidInt,
   2978                                       (PRGetsocketoptionFN)_PR_InvalidStatus,
   2979                                       (PRSetsocketoptionFN)_PR_InvalidStatus,
   2980                                       (PRSendfileFN)_PR_InvalidInt,
   2981                                       (PRConnectcontinueFN)_PR_InvalidStatus,
   2982                                       (PRReservedFN)_PR_InvalidInt,
   2983                                       (PRReservedFN)_PR_InvalidInt,
   2984                                       (PRReservedFN)_PR_InvalidInt,
   2985                                       (PRReservedFN)_PR_InvalidInt};
   2986 
   2987 static PRIOMethods _pr_tcp_methods = {
   2988    PR_DESC_SOCKET_TCP,
   2989    pt_Close,
   2990    pt_SocketRead,
   2991    pt_SocketWrite,
   2992    pt_Available_s,
   2993    pt_Available64_s,
   2994    pt_Synch,
   2995    (PRSeekFN)_PR_InvalidInt,
   2996    (PRSeek64FN)_PR_InvalidInt64,
   2997    (PRFileInfoFN)_PR_InvalidStatus,
   2998    (PRFileInfo64FN)_PR_InvalidStatus,
   2999    pt_Writev,
   3000    pt_Connect,
   3001    pt_Accept,
   3002    pt_Bind,
   3003    pt_Listen,
   3004    pt_Shutdown,
   3005    pt_Recv,
   3006    pt_Send,
   3007    (PRRecvfromFN)_PR_InvalidInt,
   3008 #  if defined(LINUX) || defined(DARWIN)
   3009    pt_TCP_SendTo, /* This is for TCP Fast Open. Linux uses SendTo function for
   3010                      this. OSX uses connectx, but we imitate Linux. */
   3011 #  else
   3012    (PRSendtoFN)_PR_InvalidInt,
   3013 #  endif
   3014    pt_Poll,
   3015    pt_AcceptRead,
   3016    pt_TransmitFile,
   3017    pt_GetSockName,
   3018    pt_GetPeerName,
   3019    (PRReservedFN)_PR_InvalidInt,
   3020    (PRReservedFN)_PR_InvalidInt,
   3021    pt_GetSocketOption,
   3022    pt_SetSocketOption,
   3023    pt_SendFile,
   3024    pt_ConnectContinue,
   3025    (PRReservedFN)_PR_InvalidInt,
   3026    (PRReservedFN)_PR_InvalidInt,
   3027    (PRReservedFN)_PR_InvalidInt,
   3028    (PRReservedFN)_PR_InvalidInt};
   3029 
   3030 static PRIOMethods _pr_udp_methods = {PR_DESC_SOCKET_UDP,
   3031                                      pt_Close,
   3032                                      pt_SocketRead,
   3033                                      pt_SocketWrite,
   3034                                      pt_Available_s,
   3035                                      pt_Available64_s,
   3036                                      pt_Synch,
   3037                                      (PRSeekFN)_PR_InvalidInt,
   3038                                      (PRSeek64FN)_PR_InvalidInt64,
   3039                                      (PRFileInfoFN)_PR_InvalidStatus,
   3040                                      (PRFileInfo64FN)_PR_InvalidStatus,
   3041                                      pt_Writev,
   3042                                      pt_Connect,
   3043                                      (PRAcceptFN)_PR_InvalidDesc,
   3044                                      pt_Bind,
   3045                                      pt_Listen,
   3046                                      pt_Shutdown,
   3047                                      pt_Recv,
   3048                                      pt_Send,
   3049                                      pt_RecvFrom,
   3050                                      pt_SendTo,
   3051                                      pt_Poll,
   3052                                      (PRAcceptreadFN)_PR_InvalidInt,
   3053                                      (PRTransmitfileFN)_PR_InvalidInt,
   3054                                      pt_GetSockName,
   3055                                      pt_GetPeerName,
   3056                                      (PRReservedFN)_PR_InvalidInt,
   3057                                      (PRReservedFN)_PR_InvalidInt,
   3058                                      pt_GetSocketOption,
   3059                                      pt_SetSocketOption,
   3060                                      (PRSendfileFN)_PR_InvalidInt,
   3061                                      (PRConnectcontinueFN)_PR_InvalidStatus,
   3062                                      (PRReservedFN)_PR_InvalidInt,
   3063                                      (PRReservedFN)_PR_InvalidInt,
   3064                                      (PRReservedFN)_PR_InvalidInt,
   3065                                      (PRReservedFN)_PR_InvalidInt};
   3066 
   3067 static PRIOMethods _pr_socketpollfd_methods = {
   3068    (PRDescType)0,
   3069    (PRCloseFN)_PR_InvalidStatus,
   3070    (PRReadFN)_PR_InvalidInt,
   3071    (PRWriteFN)_PR_InvalidInt,
   3072    (PRAvailableFN)_PR_InvalidInt,
   3073    (PRAvailable64FN)_PR_InvalidInt64,
   3074    (PRFsyncFN)_PR_InvalidStatus,
   3075    (PRSeekFN)_PR_InvalidInt,
   3076    (PRSeek64FN)_PR_InvalidInt64,
   3077    (PRFileInfoFN)_PR_InvalidStatus,
   3078    (PRFileInfo64FN)_PR_InvalidStatus,
   3079    (PRWritevFN)_PR_InvalidInt,
   3080    (PRConnectFN)_PR_InvalidStatus,
   3081    (PRAcceptFN)_PR_InvalidDesc,
   3082    (PRBindFN)_PR_InvalidStatus,
   3083    (PRListenFN)_PR_InvalidStatus,
   3084    (PRShutdownFN)_PR_InvalidStatus,
   3085    (PRRecvFN)_PR_InvalidInt,
   3086    (PRSendFN)_PR_InvalidInt,
   3087    (PRRecvfromFN)_PR_InvalidInt,
   3088    (PRSendtoFN)_PR_InvalidInt,
   3089    pt_Poll,
   3090    (PRAcceptreadFN)_PR_InvalidInt,
   3091    (PRTransmitfileFN)_PR_InvalidInt,
   3092    (PRGetsocknameFN)_PR_InvalidStatus,
   3093    (PRGetpeernameFN)_PR_InvalidStatus,
   3094    (PRReservedFN)_PR_InvalidInt,
   3095    (PRReservedFN)_PR_InvalidInt,
   3096    (PRGetsocketoptionFN)_PR_InvalidStatus,
   3097    (PRSetsocketoptionFN)_PR_InvalidStatus,
   3098    (PRSendfileFN)_PR_InvalidInt,
   3099    (PRConnectcontinueFN)_PR_InvalidStatus,
   3100    (PRReservedFN)_PR_InvalidInt,
   3101    (PRReservedFN)_PR_InvalidInt,
   3102    (PRReservedFN)_PR_InvalidInt,
   3103    (PRReservedFN)_PR_InvalidInt};
   3104 
   3105 #  if defined(SOLARIS) || defined(LINUX) ||     \
   3106      defined(__GNU__) || defined(__GLIBC__) || defined(AIX) ||  \
   3107      defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \
   3108      defined(NTO) || defined(DARWIN) || defined(RISCOS)
   3109 #    define _PR_FCNTL_FLAGS O_NONBLOCK
   3110 #  else
   3111 #    error "Can't determine architecture"
   3112 #  endif
   3113 
   3114 /*
   3115 * Put a Unix file descriptor in non-blocking mode.
   3116 */
   3117 static void pt_MakeFdNonblock(PRIntn osfd) {
   3118  PRIntn flags;
   3119  flags = fcntl(osfd, F_GETFL, 0);
   3120  flags |= _PR_FCNTL_FLAGS;
   3121  (void)fcntl(osfd, F_SETFL, flags);
   3122 }
   3123 
   3124 /*
   3125 * Put a Unix socket fd in non-blocking mode that can
   3126 * ideally be inherited by an accepted socket.
   3127 *
   3128 * Why doesn't pt_MakeFdNonblock do?  This is to deal with
   3129 * the special case of HP-UX.  HP-UX has three kinds of
   3130 * non-blocking modes for sockets: the fcntl() O_NONBLOCK
   3131 * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
   3132 * the ioctl() FIOSNBIO form of non-blocking mode is
   3133 * inherited by an accepted socket.
   3134 *
   3135 * Other platforms just use the generic pt_MakeFdNonblock
   3136 * to put a socket in non-blocking mode.
   3137 */
   3138 #    define pt_MakeSocketNonblock pt_MakeFdNonblock
   3139 
   3140 static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type,
   3141                                 PRBool isAcceptedSocket, PRBool imported) {
   3142  PRFileDesc* fd = _PR_Getfd();
   3143 
   3144  if (fd == NULL) {
   3145    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   3146  } else {
   3147    fd->secret->md.osfd = osfd;
   3148    fd->secret->state = _PR_FILEDESC_OPEN;
   3149    if (imported) {
   3150      fd->secret->inheritable = _PR_TRI_UNKNOWN;
   3151    } else {
   3152      /* By default, a Unix fd is not closed on exec. */
   3153 #  ifdef DEBUG
   3154      PRIntn flags;
   3155      flags = fcntl(osfd, F_GETFD, 0);
   3156      PR_ASSERT(0 == flags);
   3157 #  endif
   3158      fd->secret->inheritable = _PR_TRI_TRUE;
   3159    }
   3160    switch (type) {
   3161      case PR_DESC_FILE:
   3162        fd->methods = PR_GetFileMethods();
   3163        break;
   3164      case PR_DESC_SOCKET_TCP:
   3165        fd->methods = PR_GetTCPMethods();
   3166 #  ifdef _PR_ACCEPT_INHERIT_NONBLOCK
   3167        if (!isAcceptedSocket) {
   3168          pt_MakeSocketNonblock(osfd);
   3169        }
   3170 #  else
   3171        pt_MakeSocketNonblock(osfd);
   3172 #  endif
   3173        break;
   3174      case PR_DESC_SOCKET_UDP:
   3175        fd->methods = PR_GetUDPMethods();
   3176        pt_MakeFdNonblock(osfd);
   3177        break;
   3178      case PR_DESC_PIPE:
   3179        fd->methods = PR_GetPipeMethods();
   3180        pt_MakeFdNonblock(osfd);
   3181        break;
   3182      default:
   3183        break;
   3184    }
   3185  }
   3186  return fd;
   3187 } /* pt_SetMethods */
   3188 
   3189 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) {
   3190  return &_pr_file_methods;
   3191 } /* PR_GetFileMethods */
   3192 
   3193 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) {
   3194  return &_pr_pipe_methods;
   3195 } /* PR_GetPipeMethods */
   3196 
   3197 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void) {
   3198  return &_pr_tcp_methods;
   3199 } /* PR_GetTCPMethods */
   3200 
   3201 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void) {
   3202  return &_pr_udp_methods;
   3203 } /* PR_GetUDPMethods */
   3204 
   3205 static const PRIOMethods* PR_GetSocketPollFdMethods(void) {
   3206  return &_pr_socketpollfd_methods;
   3207 } /* PR_GetSocketPollFdMethods */
   3208 
   3209 PR_IMPLEMENT(PRFileDesc*)
   3210 PR_AllocFileDesc(PRInt32 osfd, const PRIOMethods* methods) {
   3211  PRFileDesc* fd = _PR_Getfd();
   3212 
   3213  if (NULL == fd) {
   3214    goto failed;
   3215  }
   3216 
   3217  fd->methods = methods;
   3218  fd->secret->md.osfd = osfd;
   3219  /* Make fd non-blocking */
   3220  if (osfd > 2) {
   3221    /* Don't mess around with stdin, stdout or stderr */
   3222    if (&_pr_tcp_methods == methods) {
   3223      pt_MakeSocketNonblock(osfd);
   3224    } else {
   3225      pt_MakeFdNonblock(osfd);
   3226    }
   3227  }
   3228  fd->secret->state = _PR_FILEDESC_OPEN;
   3229  fd->secret->inheritable = _PR_TRI_UNKNOWN;
   3230  return fd;
   3231 
   3232 failed:
   3233  PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   3234  return fd;
   3235 } /* PR_AllocFileDesc */
   3236 
   3237 #  if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
   3238 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd);
   3239 #    if defined(_PR_INET6_PROBE)
   3240 extern PRBool _pr_ipv6_is_present(void);
   3241 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() {
   3242  int osfd;
   3243 
   3244 #      if defined(DARWIN)
   3245  /*
   3246   * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
   3247   * lesser versions is not ready for general use (see bug 222031).
   3248   */
   3249  {
   3250    struct utsname u;
   3251    if (uname(&u) != 0 || atoi(u.release) < 7) {
   3252      return PR_FALSE;
   3253    }
   3254  }
   3255 #      endif
   3256 
   3257  /*
   3258   * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
   3259   * suggests that we call open("/dev/ip6", O_RDWR) to determine
   3260   * whether IPv6 APIs and the IPv6 stack are on the system.
   3261   * Our portable test below seems to work fine, so I am using it.
   3262   */
   3263  osfd = socket(AF_INET6, SOCK_STREAM, 0);
   3264  if (osfd != -1) {
   3265    close(osfd);
   3266    return PR_TRUE;
   3267  }
   3268  return PR_FALSE;
   3269 }
   3270 #    endif /* _PR_INET6_PROBE */
   3271 #  endif
   3272 
   3273 PR_IMPLEMENT(PRFileDesc*)
   3274 PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) {
   3275  PRIntn osfd;
   3276  PRDescType ftype;
   3277  PRFileDesc* fd = NULL;
   3278 #  if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
   3279  PRInt32 tmp_domain = domain;
   3280 #  endif
   3281 
   3282  if (!_pr_initialized) {
   3283    _PR_ImplicitInitialization();
   3284  }
   3285 
   3286  if (pt_TestAbort()) {
   3287    return NULL;
   3288  }
   3289 
   3290  if (PF_INET != domain && PR_AF_INET6 != domain
   3291 #  if defined(_PR_HAVE_SDP)
   3292      && PR_AF_INET_SDP != domain
   3293 #    if defined(SOLARIS)
   3294      && PR_AF_INET6_SDP != domain
   3295 #    endif /* SOLARIS */
   3296 #  endif   /* _PR_HAVE_SDP */
   3297      && PF_UNIX != domain) {
   3298    PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
   3299    return fd;
   3300  }
   3301  if (type == SOCK_STREAM) {
   3302    ftype = PR_DESC_SOCKET_TCP;
   3303  } else if (type == SOCK_DGRAM) {
   3304    ftype = PR_DESC_SOCKET_UDP;
   3305  } else {
   3306    (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
   3307    return fd;
   3308  }
   3309 #  if defined(_PR_HAVE_SDP)
   3310 #    if defined(LINUX)
   3311  if (PR_AF_INET_SDP == domain) {
   3312    domain = AF_INET_SDP;
   3313  }
   3314 #    elif defined(SOLARIS)
   3315  if (PR_AF_INET_SDP == domain) {
   3316    domain = AF_INET;
   3317    proto = PROTO_SDP;
   3318  } else if (PR_AF_INET6_SDP == domain) {
   3319    domain = AF_INET6;
   3320    proto = PROTO_SDP;
   3321  }
   3322 #    endif /* SOLARIS */
   3323 #  endif   /* _PR_HAVE_SDP */
   3324 #  if defined(_PR_INET6_PROBE)
   3325  if (PR_AF_INET6 == domain) {
   3326    domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
   3327  }
   3328 #  elif defined(_PR_INET6)
   3329  if (PR_AF_INET6 == domain) {
   3330    domain = AF_INET6;
   3331  }
   3332 #  else
   3333  if (PR_AF_INET6 == domain) {
   3334    domain = AF_INET;
   3335  }
   3336 #  endif
   3337 
   3338  osfd = socket(domain, type, proto);
   3339  if (osfd == -1) {
   3340    pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
   3341  } else {
   3342 #  ifdef _PR_IPV6_V6ONLY_PROBE
   3343    if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default) {
   3344      int on = 0;
   3345      (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
   3346    }
   3347 #  endif
   3348    fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
   3349    if (fd == NULL) {
   3350      close(osfd);
   3351    }
   3352  }
   3353 #  ifdef _PR_NEED_SECRET_AF
   3354  if (fd != NULL) {
   3355    fd->secret->af = domain;
   3356  }
   3357 #  endif
   3358 #  if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
   3359  if (fd != NULL) {
   3360    /*
   3361     * For platforms with no support for IPv6
   3362     * create layered socket for IPv4-mapped IPv6 addresses
   3363     */
   3364    if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
   3365      if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
   3366        PR_Close(fd);
   3367        fd = NULL;
   3368      }
   3369    }
   3370  }
   3371 #  endif
   3372  return fd;
   3373 } /* PR_Socket */
   3374 
   3375 /*****************************************************************************/
   3376 /****************************** I/O public methods ***************************/
   3377 /*****************************************************************************/
   3378 
   3379 PR_IMPLEMENT(PRFileDesc*)
   3380 PR_OpenFile(const char* name, PRIntn flags, PRIntn mode) {
   3381  PRFileDesc* fd = NULL;
   3382  PRIntn syserrno, osfd = -1, osflags = 0;
   3383  ;
   3384 
   3385  if (!_pr_initialized) {
   3386    _PR_ImplicitInitialization();
   3387  }
   3388 
   3389  if (pt_TestAbort()) {
   3390    return NULL;
   3391  }
   3392 
   3393  if (flags & PR_RDONLY) {
   3394    osflags |= O_RDONLY;
   3395  }
   3396  if (flags & PR_WRONLY) {
   3397    osflags |= O_WRONLY;
   3398  }
   3399  if (flags & PR_RDWR) {
   3400    osflags |= O_RDWR;
   3401  }
   3402  if (flags & PR_APPEND) {
   3403    osflags |= O_APPEND;
   3404  }
   3405  if (flags & PR_TRUNCATE) {
   3406    osflags |= O_TRUNC;
   3407  }
   3408  if (flags & PR_EXCL) {
   3409    osflags |= O_EXCL;
   3410  }
   3411  if (flags & PR_SYNC) {
   3412 #  if defined(O_SYNC)
   3413    osflags |= O_SYNC;
   3414 #  elif defined(O_FSYNC)
   3415    osflags |= O_FSYNC;
   3416 #  else
   3417 #    error "Neither O_SYNC nor O_FSYNC is defined on this platform"
   3418 #  endif
   3419  }
   3420 
   3421  /*
   3422  ** We have to hold the lock across the creation in order to
   3423  ** enforce the sematics of PR_Rename(). (see the latter for
   3424  ** more details)
   3425  */
   3426  if (flags & PR_CREATE_FILE) {
   3427    osflags |= O_CREAT;
   3428    if (NULL != _pr_rename_lock) {
   3429      PR_Lock(_pr_rename_lock);
   3430    }
   3431  }
   3432 
   3433  osfd = _md_iovector._open64(name, osflags, mode);
   3434  syserrno = errno;
   3435 
   3436  if ((flags & PR_CREATE_FILE) && (NULL != _pr_rename_lock)) {
   3437    PR_Unlock(_pr_rename_lock);
   3438  }
   3439 
   3440  if (osfd == -1) {
   3441    pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
   3442  } else {
   3443    fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
   3444    if (fd == NULL) {
   3445      close(osfd); /* $$$ whoops! this is bad $$$ */
   3446    }
   3447  }
   3448  return fd;
   3449 } /* PR_OpenFile */
   3450 
   3451 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char* name, PRIntn flags, PRIntn mode) {
   3452  return PR_OpenFile(name, flags, mode);
   3453 } /* PR_Open */
   3454 
   3455 PR_IMPLEMENT(PRStatus) PR_Delete(const char* name) {
   3456  PRIntn rv = -1;
   3457 
   3458  if (!_pr_initialized) {
   3459    _PR_ImplicitInitialization();
   3460  }
   3461 
   3462  if (pt_TestAbort()) {
   3463    return PR_FAILURE;
   3464  }
   3465 
   3466  rv = unlink(name);
   3467 
   3468  if (rv == -1) {
   3469    pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
   3470    return PR_FAILURE;
   3471  }
   3472  return PR_SUCCESS;
   3473 } /* PR_Delete */
   3474 
   3475 PR_IMPLEMENT(PRStatus) PR_Access(const char* name, PRAccessHow how) {
   3476  PRIntn rv;
   3477 
   3478  if (pt_TestAbort()) {
   3479    return PR_FAILURE;
   3480  }
   3481 
   3482  switch (how) {
   3483    case PR_ACCESS_READ_OK:
   3484      rv = access(name, R_OK);
   3485      break;
   3486    case PR_ACCESS_WRITE_OK:
   3487      rv = access(name, W_OK);
   3488      break;
   3489    case PR_ACCESS_EXISTS:
   3490    default:
   3491      rv = access(name, F_OK);
   3492  }
   3493  if (0 == rv) {
   3494    return PR_SUCCESS;
   3495  }
   3496  pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
   3497  return PR_FAILURE;
   3498 
   3499 } /* PR_Access */
   3500 
   3501 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char* fn, PRFileInfo* info) {
   3502  PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
   3503  return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
   3504 } /* PR_GetFileInfo */
   3505 
   3506 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char* fn, PRFileInfo64* info) {
   3507  PRInt32 rv;
   3508 
   3509  if (!_pr_initialized) {
   3510    _PR_ImplicitInitialization();
   3511  }
   3512  rv = _PR_MD_GETFILEINFO64(fn, info);
   3513  return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
   3514 } /* PR_GetFileInfo64 */
   3515 
   3516 PR_IMPLEMENT(PRStatus) PR_Rename(const char* from, const char* to) {
   3517  PRIntn rv = -1;
   3518 
   3519  if (pt_TestAbort()) {
   3520    return PR_FAILURE;
   3521  }
   3522 
   3523  /*
   3524  ** We have to acquire a lock here to stiffle anybody trying to create
   3525  ** a new file at the same time. And we have to hold that lock while we
   3526  ** test to see if the file exists and do the rename. The other place
   3527  ** where the lock is held is in PR_Open() when possibly creating a
   3528  ** new file.
   3529  */
   3530 
   3531  PR_Lock(_pr_rename_lock);
   3532  rv = access(to, F_OK);
   3533  if (0 == rv) {
   3534    PR_SetError(PR_FILE_EXISTS_ERROR, 0);
   3535    rv = -1;
   3536  } else {
   3537    rv = rename(from, to);
   3538    if (rv == -1) {
   3539      pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
   3540    }
   3541  }
   3542  PR_Unlock(_pr_rename_lock);
   3543  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   3544 } /* PR_Rename */
   3545 
   3546 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir* dir) {
   3547  if (pt_TestAbort()) {
   3548    return PR_FAILURE;
   3549  }
   3550 
   3551  if (NULL != dir->md.d) {
   3552    if (closedir(dir->md.d) == -1) {
   3553      _PR_MD_MAP_CLOSEDIR_ERROR(errno);
   3554      return PR_FAILURE;
   3555    }
   3556    dir->md.d = NULL;
   3557    PR_DELETE(dir);
   3558  }
   3559  return PR_SUCCESS;
   3560 } /* PR_CloseDir */
   3561 
   3562 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char* name, PRIntn mode) {
   3563  PRInt32 rv = -1;
   3564 
   3565  if (pt_TestAbort()) {
   3566    return PR_FAILURE;
   3567  }
   3568 
   3569  /*
   3570  ** This lock is used to enforce rename semantics as described
   3571  ** in PR_Rename.
   3572  */
   3573  if (NULL != _pr_rename_lock) {
   3574    PR_Lock(_pr_rename_lock);
   3575  }
   3576  rv = mkdir(name, mode);
   3577  if (-1 == rv) {
   3578    pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
   3579  }
   3580  if (NULL != _pr_rename_lock) {
   3581    PR_Unlock(_pr_rename_lock);
   3582  }
   3583 
   3584  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
   3585 } /* PR_Makedir */
   3586 
   3587 PR_IMPLEMENT(PRStatus) PR_MkDir(const char* name, PRIntn mode) {
   3588  return PR_MakeDir(name, mode);
   3589 } /* PR_Mkdir */
   3590 
   3591 PR_IMPLEMENT(PRStatus) PR_RmDir(const char* name) {
   3592  PRInt32 rv;
   3593 
   3594  if (pt_TestAbort()) {
   3595    return PR_FAILURE;
   3596  }
   3597 
   3598  rv = rmdir(name);
   3599  if (0 == rv) {
   3600    return PR_SUCCESS;
   3601  }
   3602  pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
   3603  return PR_FAILURE;
   3604 } /* PR_Rmdir */
   3605 
   3606 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char* name) {
   3607  DIR* osdir;
   3608  PRDir* dir = NULL;
   3609 
   3610  if (pt_TestAbort()) {
   3611    return dir;
   3612  }
   3613 
   3614  osdir = opendir(name);
   3615  if (osdir == NULL) {
   3616    pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
   3617  } else {
   3618    dir = PR_NEWZAP(PRDir);
   3619    if (dir) {
   3620      dir->md.d = osdir;
   3621    } else {
   3622      (void)closedir(osdir);
   3623    }
   3624  }
   3625  return dir;
   3626 } /* PR_OpenDir */
   3627 
   3628 static PRInt32 _pr_poll_with_poll(PRPollDesc* pds, PRIntn npds,
   3629                                  PRIntervalTime timeout) {
   3630  PRInt32 ready = 0;
   3631  /*
   3632   * For restarting poll() if it is interrupted by a signal.
   3633   * We use these variables to figure out how much time has
   3634   * elapsed and how much of the timeout still remains.
   3635   */
   3636  PRIntervalTime start = 0, elapsed, remaining;
   3637 
   3638  if (pt_TestAbort()) {
   3639    return -1;
   3640  }
   3641 
   3642  if (0 == npds) {
   3643    PR_Sleep(timeout);
   3644  } else {
   3645 #  define STACK_POLL_DESC_COUNT 64
   3646    struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
   3647    struct pollfd* syspoll;
   3648    PRIntn index, msecs;
   3649 
   3650    if (npds <= STACK_POLL_DESC_COUNT) {
   3651      syspoll = stack_syspoll;
   3652    } else {
   3653      PRThread* me = PR_GetCurrentThread();
   3654      if (npds > me->syspoll_count) {
   3655        PR_Free(me->syspoll_list);
   3656        me->syspoll_list =
   3657            (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
   3658        if (NULL == me->syspoll_list) {
   3659          me->syspoll_count = 0;
   3660          PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   3661          return -1;
   3662        }
   3663        me->syspoll_count = npds;
   3664      }
   3665      syspoll = me->syspoll_list;
   3666    }
   3667 
   3668    for (index = 0; index < npds; ++index) {
   3669      PRInt16 in_flags_read = 0, in_flags_write = 0;
   3670      PRInt16 out_flags_read = 0, out_flags_write = 0;
   3671 
   3672      if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
   3673        if (pds[index].in_flags & PR_POLL_READ) {
   3674          in_flags_read = (pds[index].fd->methods->poll)(
   3675              pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE,
   3676              &out_flags_read);
   3677        }
   3678        if (pds[index].in_flags & PR_POLL_WRITE) {
   3679          in_flags_write = (pds[index].fd->methods->poll)(
   3680              pds[index].fd, pds[index].in_flags & ~PR_POLL_READ,
   3681              &out_flags_write);
   3682        }
   3683        if ((0 != (in_flags_read & out_flags_read)) ||
   3684            (0 != (in_flags_write & out_flags_write))) {
   3685          /* this one is ready right now */
   3686          if (0 == ready) {
   3687            /*
   3688             * We will return without calling the system
   3689             * poll function.  So zero the out_flags
   3690             * fields of all the poll descriptors before
   3691             * this one.
   3692             */
   3693            int i;
   3694            for (i = 0; i < index; i++) {
   3695              pds[i].out_flags = 0;
   3696            }
   3697          }
   3698          ready += 1;
   3699          pds[index].out_flags = out_flags_read | out_flags_write;
   3700        } else {
   3701          /* now locate the NSPR layer at the bottom of the stack */
   3702          PRFileDesc* bottom =
   3703              PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER);
   3704          /* ignore a socket without PR_NSPR_IO_LAYER available */
   3705 
   3706          pds[index].out_flags = 0; /* pre-condition */
   3707          if ((NULL != bottom) &&
   3708              (_PR_FILEDESC_OPEN == bottom->secret->state)) {
   3709            if (0 == ready) {
   3710              syspoll[index].fd = bottom->secret->md.osfd;
   3711              syspoll[index].events = 0;
   3712              if (in_flags_read & PR_POLL_READ) {
   3713                pds[index].out_flags |= _PR_POLL_READ_SYS_READ;
   3714                syspoll[index].events |= POLLIN;
   3715              }
   3716              if (in_flags_read & PR_POLL_WRITE) {
   3717                pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE;
   3718                syspoll[index].events |= POLLOUT;
   3719              }
   3720              if (in_flags_write & PR_POLL_READ) {
   3721                pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ;
   3722                syspoll[index].events |= POLLIN;
   3723              }
   3724              if (in_flags_write & PR_POLL_WRITE) {
   3725                pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE;
   3726                syspoll[index].events |= POLLOUT;
   3727              }
   3728              if (pds[index].in_flags & PR_POLL_EXCEPT) {
   3729                syspoll[index].events |= POLLPRI;
   3730              }
   3731            }
   3732          } else {
   3733            if (0 == ready) {
   3734              int i;
   3735              for (i = 0; i < index; i++) {
   3736                pds[i].out_flags = 0;
   3737              }
   3738            }
   3739            ready += 1; /* this will cause an abrupt return */
   3740            pds[index].out_flags = PR_POLL_NVAL; /* bogii */
   3741          }
   3742        }
   3743      } else {
   3744        /* make poll() ignore this entry */
   3745        syspoll[index].fd = -1;
   3746        syspoll[index].events = 0;
   3747        pds[index].out_flags = 0;
   3748      }
   3749    }
   3750    if (0 == ready) {
   3751      switch (timeout) {
   3752        case PR_INTERVAL_NO_WAIT:
   3753          msecs = 0;
   3754          break;
   3755        case PR_INTERVAL_NO_TIMEOUT:
   3756          msecs = -1;
   3757          break;
   3758        default:
   3759          msecs = PR_IntervalToMilliseconds(timeout);
   3760          start = PR_IntervalNow();
   3761      }
   3762 
   3763    retry:
   3764      ready = poll(syspoll, npds, msecs);
   3765      if (-1 == ready) {
   3766        PRIntn oserror = errno;
   3767 
   3768        if (EINTR == oserror) {
   3769          if (timeout == PR_INTERVAL_NO_TIMEOUT) {
   3770            goto retry;
   3771          } else if (timeout == PR_INTERVAL_NO_WAIT) {
   3772            ready = 0; /* don't retry, just time out */
   3773          } else {
   3774            elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
   3775            if (elapsed > timeout) {
   3776              ready = 0; /* timed out */
   3777            } else {
   3778              remaining = timeout - elapsed;
   3779              msecs = PR_IntervalToMilliseconds(remaining);
   3780              goto retry;
   3781            }
   3782          }
   3783        } else {
   3784          _PR_MD_MAP_POLL_ERROR(oserror);
   3785        }
   3786      } else if (ready > 0) {
   3787        for (index = 0; index < npds; ++index) {
   3788          PRInt16 out_flags = 0;
   3789          if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
   3790            if (0 != syspoll[index].revents) {
   3791              if (syspoll[index].revents & POLLIN) {
   3792                if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) {
   3793                  out_flags |= PR_POLL_READ;
   3794                }
   3795                if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) {
   3796                  out_flags |= PR_POLL_WRITE;
   3797                }
   3798              }
   3799              if (syspoll[index].revents & POLLOUT) {
   3800                if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) {
   3801                  out_flags |= PR_POLL_READ;
   3802                }
   3803                if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) {
   3804                  out_flags |= PR_POLL_WRITE;
   3805                }
   3806              }
   3807              if (syspoll[index].revents & POLLPRI) {
   3808                out_flags |= PR_POLL_EXCEPT;
   3809              }
   3810              if (syspoll[index].revents & POLLERR) {
   3811                out_flags |= PR_POLL_ERR;
   3812              }
   3813              if (syspoll[index].revents & POLLNVAL) {
   3814                out_flags |= PR_POLL_NVAL;
   3815              }
   3816              if (syspoll[index].revents & POLLHUP) {
   3817                out_flags |= PR_POLL_HUP;
   3818              }
   3819            }
   3820          }
   3821          pds[index].out_flags = out_flags;
   3822        }
   3823      }
   3824    }
   3825  }
   3826  return ready;
   3827 
   3828 } /* _pr_poll_with_poll */
   3829 
   3830 
   3831 PR_IMPLEMENT(PRInt32)
   3832 PR_Poll(PRPollDesc* pds, PRIntn npds, PRIntervalTime timeout) {
   3833  return (_pr_poll_with_poll(pds, npds, timeout));
   3834 }
   3835 
   3836 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir* dir, PRDirFlags flags) {
   3837  struct dirent* dp;
   3838 
   3839  if (pt_TestAbort()) {
   3840    return NULL;
   3841  }
   3842 
   3843  for (;;) {
   3844    errno = 0;
   3845    dp = readdir(dir->md.d);
   3846    if (NULL == dp) {
   3847      pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
   3848      return NULL;
   3849    }
   3850    if ((flags & PR_SKIP_DOT) && ('.' == dp->d_name[0]) &&
   3851        (0 == dp->d_name[1])) {
   3852      continue;
   3853    }
   3854    if ((flags & PR_SKIP_DOT_DOT) && ('.' == dp->d_name[0]) &&
   3855        ('.' == dp->d_name[1]) && (0 == dp->d_name[2])) {
   3856      continue;
   3857    }
   3858    if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0])) {
   3859      continue;
   3860    }
   3861    break;
   3862  }
   3863  dir->d.name = dp->d_name;
   3864  return &dir->d;
   3865 } /* PR_ReadDir */
   3866 
   3867 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) {
   3868  PRIntn domain = PF_INET;
   3869 
   3870  return PR_Socket(domain, SOCK_DGRAM, 0);
   3871 } /* PR_NewUDPSocket */
   3872 
   3873 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) {
   3874  PRIntn domain = PF_INET;
   3875 
   3876  return PR_Socket(domain, SOCK_STREAM, 0);
   3877 } /* PR_NewTCPSocket */
   3878 
   3879 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) {
   3880  return PR_Socket(af, SOCK_DGRAM, 0);
   3881 } /* PR_NewUDPSocket */
   3882 
   3883 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) {
   3884  return PR_Socket(af, SOCK_STREAM, 0);
   3885 } /* PR_NewTCPSocket */
   3886 
   3887 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc* fds[2]) {
   3888  PRInt32 osfd[2];
   3889 
   3890  if (pt_TestAbort()) {
   3891    return PR_FAILURE;
   3892  }
   3893 
   3894  if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
   3895    pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
   3896    return PR_FAILURE;
   3897  }
   3898 
   3899  fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
   3900  if (fds[0] == NULL) {
   3901    close(osfd[0]);
   3902    close(osfd[1]);
   3903    return PR_FAILURE;
   3904  }
   3905  fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
   3906  if (fds[1] == NULL) {
   3907    PR_Close(fds[0]);
   3908    close(osfd[1]);
   3909    return PR_FAILURE;
   3910  }
   3911  return PR_SUCCESS;
   3912 } /* PR_NewTCPSocketPair */
   3913 
   3914 PR_IMPLEMENT(PRStatus)
   3915 PR_CreatePipe(PRFileDesc** readPipe, PRFileDesc** writePipe) {
   3916  int pipefd[2];
   3917 
   3918  if (pt_TestAbort()) {
   3919    return PR_FAILURE;
   3920  }
   3921 
   3922  if (pipe(pipefd) == -1) {
   3923    /* XXX map pipe error */
   3924    PR_SetError(PR_UNKNOWN_ERROR, errno);
   3925    return PR_FAILURE;
   3926  }
   3927  *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
   3928  if (NULL == *readPipe) {
   3929    close(pipefd[0]);
   3930    close(pipefd[1]);
   3931    return PR_FAILURE;
   3932  }
   3933  *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
   3934  if (NULL == *writePipe) {
   3935    PR_Close(*readPipe);
   3936    close(pipefd[1]);
   3937    return PR_FAILURE;
   3938  }
   3939  return PR_SUCCESS;
   3940 }
   3941 
   3942 /*
   3943 ** Set the inheritance attribute of a file descriptor.
   3944 */
   3945 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(PRFileDesc* fd, PRBool inheritable) {
   3946  /*
   3947   * Only a non-layered, NSPR file descriptor can be inherited
   3948   * by a child process.
   3949   */
   3950  if (fd->identity != PR_NSPR_IO_LAYER) {
   3951    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   3952    return PR_FAILURE;
   3953  }
   3954  if (fd->secret->inheritable != inheritable) {
   3955    if (fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC) ==
   3956        -1) {
   3957      _PR_MD_MAP_DEFAULT_ERROR(errno);
   3958      return PR_FAILURE;
   3959    }
   3960    fd->secret->inheritable = (_PRTriStateBool)inheritable;
   3961  }
   3962  return PR_SUCCESS;
   3963 }
   3964 
   3965 /*****************************************************************************/
   3966 /***************************** I/O friends methods ***************************/
   3967 /*****************************************************************************/
   3968 
   3969 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) {
   3970  PRFileDesc* fd;
   3971 
   3972  if (!_pr_initialized) {
   3973    _PR_ImplicitInitialization();
   3974  }
   3975  fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
   3976  if (NULL == fd) {
   3977    close(osfd);
   3978  }
   3979  return fd;
   3980 } /* PR_ImportFile */
   3981 
   3982 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) {
   3983  PRFileDesc* fd;
   3984 
   3985  if (!_pr_initialized) {
   3986    _PR_ImplicitInitialization();
   3987  }
   3988  fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
   3989  if (NULL == fd) {
   3990    close(osfd);
   3991  }
   3992  return fd;
   3993 } /* PR_ImportPipe */
   3994 
   3995 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd) {
   3996  PRFileDesc* fd;
   3997 
   3998  if (!_pr_initialized) {
   3999    _PR_ImplicitInitialization();
   4000  }
   4001  fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
   4002  if (NULL == fd) {
   4003    close(osfd);
   4004  }
   4005 #  ifdef _PR_NEED_SECRET_AF
   4006  if (NULL != fd) {
   4007    fd->secret->af = PF_INET;
   4008  }
   4009 #  endif
   4010  return fd;
   4011 } /* PR_ImportTCPSocket */
   4012 
   4013 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) {
   4014  PRFileDesc* fd;
   4015 
   4016  if (!_pr_initialized) {
   4017    _PR_ImplicitInitialization();
   4018  }
   4019  fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
   4020  if (NULL == fd) {
   4021    close(osfd);
   4022  }
   4023  return fd;
   4024 } /* PR_ImportUDPSocket */
   4025 
   4026 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd) {
   4027  PRFileDesc* fd;
   4028 
   4029  if (!_pr_initialized) {
   4030    _PR_ImplicitInitialization();
   4031  }
   4032 
   4033  fd = _PR_Getfd();
   4034 
   4035  if (fd == NULL) {
   4036    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   4037  } else {
   4038    fd->secret->md.osfd = osfd;
   4039    fd->secret->inheritable = _PR_TRI_FALSE;
   4040    fd->secret->state = _PR_FILEDESC_OPEN;
   4041    fd->methods = PR_GetSocketPollFdMethods();
   4042  }
   4043 
   4044  return fd;
   4045 } /* PR_CreateSocketPollFD */
   4046 
   4047 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) {
   4048  if (NULL == fd) {
   4049    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   4050    return PR_FAILURE;
   4051  }
   4052  fd->secret->state = _PR_FILEDESC_CLOSED;
   4053  _PR_Putfd(fd);
   4054  return PR_SUCCESS;
   4055 } /* PR_DestroySocketPollFd */
   4056 
   4057 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc* bottom) {
   4058  PRInt32 osfd = -1;
   4059  bottom =
   4060      (NULL == bottom) ? NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
   4061  if (NULL == bottom) {
   4062    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   4063  } else {
   4064    osfd = bottom->secret->md.osfd;
   4065  }
   4066  return osfd;
   4067 } /* PR_FileDesc2NativeHandle */
   4068 
   4069 PR_IMPLEMENT(void)
   4070 PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PRInt32 handle) {
   4071  if (fd) {
   4072    fd->secret->md.osfd = handle;
   4073  }
   4074 } /*  PR_ChangeFileDescNativeHandle*/
   4075 
   4076 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc* fd) {
   4077  PRStatus status = PR_SUCCESS;
   4078 
   4079  if (pt_TestAbort()) {
   4080    return PR_FAILURE;
   4081  }
   4082 
   4083  PR_Lock(_pr_flock_lock);
   4084  while (-1 == fd->secret->lockCount) {
   4085    PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
   4086  }
   4087  if (0 == fd->secret->lockCount) {
   4088    fd->secret->lockCount = -1;
   4089    PR_Unlock(_pr_flock_lock);
   4090    status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
   4091    PR_Lock(_pr_flock_lock);
   4092    fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
   4093    PR_NotifyAllCondVar(_pr_flock_cv);
   4094  } else {
   4095    fd->secret->lockCount += 1;
   4096  }
   4097  PR_Unlock(_pr_flock_lock);
   4098 
   4099  return status;
   4100 } /* PR_LockFile */
   4101 
   4102 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc* fd) {
   4103  PRStatus status = PR_SUCCESS;
   4104 
   4105  if (pt_TestAbort()) {
   4106    return PR_FAILURE;
   4107  }
   4108 
   4109  PR_Lock(_pr_flock_lock);
   4110  if (0 == fd->secret->lockCount) {
   4111    status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
   4112    if (PR_SUCCESS == status) {
   4113      fd->secret->lockCount = 1;
   4114    }
   4115  } else {
   4116    fd->secret->lockCount += 1;
   4117  }
   4118  PR_Unlock(_pr_flock_lock);
   4119 
   4120  return status;
   4121 } /* PR_TLockFile */
   4122 
   4123 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc* fd) {
   4124  PRStatus status = PR_SUCCESS;
   4125 
   4126  if (pt_TestAbort()) {
   4127    return PR_FAILURE;
   4128  }
   4129 
   4130  PR_Lock(_pr_flock_lock);
   4131  if (fd->secret->lockCount == 1) {
   4132    status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
   4133    if (PR_SUCCESS == status) {
   4134      fd->secret->lockCount = 0;
   4135    }
   4136  } else {
   4137    fd->secret->lockCount -= 1;
   4138  }
   4139  PR_Unlock(_pr_flock_lock);
   4140 
   4141  return status;
   4142 }
   4143 
   4144 /*
   4145 * The next two entry points should not be in the API, but they are
   4146 * defined here for historical (or hysterical) reasons.
   4147 */
   4148 
   4149 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void) {
   4150 #  if defined(AIX)
   4151  return sysconf(_SC_OPEN_MAX);
   4152 #  else
   4153  struct rlimit rlim;
   4154 
   4155  if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
   4156    return -1;
   4157  }
   4158 
   4159  return rlim.rlim_max;
   4160 #  endif
   4161 }
   4162 
   4163 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size) {
   4164 #  if defined(AIX)
   4165  return -1;
   4166 #  else
   4167  struct rlimit rlim;
   4168  PRInt32 tableMax = PR_GetSysfdTableMax();
   4169 
   4170  if (tableMax < 0) {
   4171    return -1;
   4172  }
   4173  rlim.rlim_max = tableMax;
   4174 
   4175  /* Grow as much as we can; even if too big */
   4176  if (rlim.rlim_max < table_size) {
   4177    rlim.rlim_cur = rlim.rlim_max;
   4178  } else {
   4179    rlim.rlim_cur = table_size;
   4180  }
   4181 
   4182  if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
   4183    return -1;
   4184  }
   4185 
   4186  return rlim.rlim_cur;
   4187 #  endif
   4188 }
   4189 
   4190 /*
   4191 * PR_Stat is supported for backward compatibility; some existing Java
   4192 * code uses it.  New code should use PR_GetFileInfo.
   4193 */
   4194 
   4195 #  ifndef NO_NSPR_10_SUPPORT
   4196 PR_IMPLEMENT(PRInt32) PR_Stat(const char* name, struct stat* buf) {
   4197  static PRBool unwarned = PR_TRUE;
   4198  if (unwarned) {
   4199    unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
   4200  }
   4201 
   4202  if (pt_TestAbort()) {
   4203    return -1;
   4204  }
   4205 
   4206  if (-1 == stat(name, buf)) {
   4207    pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
   4208    return -1;
   4209  } else {
   4210    return 0;
   4211  }
   4212 }
   4213 #  endif /* ! NO_NSPR_10_SUPPORT */
   4214 
   4215 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set* set) {
   4216  static PRBool unwarned = PR_TRUE;
   4217  if (unwarned) {
   4218    unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
   4219  }
   4220  memset(set, 0, sizeof(PR_fd_set));
   4221 }
   4222 
   4223 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc* fh, PR_fd_set* set) {
   4224  static PRBool unwarned = PR_TRUE;
   4225  if (unwarned) {
   4226    unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
   4227  }
   4228  PR_ASSERT(set->hsize < PR_MAX_SELECT_DESC);
   4229 
   4230  set->harray[set->hsize++] = fh;
   4231 }
   4232 
   4233 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc* fh, PR_fd_set* set) {
   4234  PRUint32 index, index2;
   4235  static PRBool unwarned = PR_TRUE;
   4236  if (unwarned) {
   4237    unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
   4238  }
   4239 
   4240  for (index = 0; index < set->hsize; index++)
   4241    if (set->harray[index] == fh) {
   4242      for (index2 = index; index2 < (set->hsize - 1); index2++) {
   4243        set->harray[index2] = set->harray[index2 + 1];
   4244      }
   4245      set->hsize--;
   4246      break;
   4247    }
   4248 }
   4249 
   4250 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) {
   4251  PRUint32 index;
   4252  static PRBool unwarned = PR_TRUE;
   4253  if (unwarned) {
   4254    unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
   4255  }
   4256  for (index = 0; index < set->hsize; index++)
   4257    if (set->harray[index] == fh) {
   4258      return 1;
   4259    }
   4260  return 0;
   4261 }
   4262 
   4263 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set* set) {
   4264  static PRBool unwarned = PR_TRUE;
   4265  if (unwarned) {
   4266    unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
   4267  }
   4268  PR_ASSERT(set->nsize < PR_MAX_SELECT_DESC);
   4269 
   4270  set->narray[set->nsize++] = fd;
   4271 }
   4272 
   4273 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set* set) {
   4274  PRUint32 index, index2;
   4275  static PRBool unwarned = PR_TRUE;
   4276  if (unwarned) {
   4277    unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
   4278  }
   4279 
   4280  for (index = 0; index < set->nsize; index++)
   4281    if (set->narray[index] == fd) {
   4282      for (index2 = index; index2 < (set->nsize - 1); index2++) {
   4283        set->narray[index2] = set->narray[index2 + 1];
   4284      }
   4285      set->nsize--;
   4286      break;
   4287    }
   4288 }
   4289 
   4290 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set* set) {
   4291  PRUint32 index;
   4292  static PRBool unwarned = PR_TRUE;
   4293  if (unwarned) {
   4294    unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
   4295  }
   4296  for (index = 0; index < set->nsize; index++)
   4297    if (set->narray[index] == fd) {
   4298      return 1;
   4299    }
   4300  return 0;
   4301 }
   4302 
   4303 #  include <sys/types.h>
   4304 #  include <sys/time.h>
   4305 #  if !defined(LINUX) && !defined(__GNU__) && \
   4306      !defined(__GLIBC__)
   4307 #    include <sys/select.h>
   4308 #  endif
   4309 
   4310 static PRInt32 _PR_getset(PR_fd_set* pr_set, fd_set* set) {
   4311  PRUint32 index;
   4312  PRInt32 max = 0;
   4313 
   4314  if (!pr_set) {
   4315    return 0;
   4316  }
   4317 
   4318  FD_ZERO(set);
   4319 
   4320  /* First set the pr file handle osfds */
   4321  for (index = 0; index < pr_set->hsize; index++) {
   4322    FD_SET(pr_set->harray[index]->secret->md.osfd, set);
   4323    if (pr_set->harray[index]->secret->md.osfd > max) {
   4324      max = pr_set->harray[index]->secret->md.osfd;
   4325    }
   4326  }
   4327  /* Second set the native osfds */
   4328  for (index = 0; index < pr_set->nsize; index++) {
   4329    FD_SET(pr_set->narray[index], set);
   4330    if (pr_set->narray[index] > max) {
   4331      max = pr_set->narray[index];
   4332    }
   4333  }
   4334  return max;
   4335 }
   4336 
   4337 static void _PR_setset(PR_fd_set* pr_set, fd_set* set) {
   4338  PRUint32 index, last_used;
   4339 
   4340  if (!pr_set) {
   4341    return;
   4342  }
   4343 
   4344  for (last_used = 0, index = 0; index < pr_set->hsize; index++) {
   4345    if (FD_ISSET(pr_set->harray[index]->secret->md.osfd, set)) {
   4346      pr_set->harray[last_used++] = pr_set->harray[index];
   4347    }
   4348  }
   4349  pr_set->hsize = last_used;
   4350 
   4351  for (last_used = 0, index = 0; index < pr_set->nsize; index++) {
   4352    if (FD_ISSET(pr_set->narray[index], set)) {
   4353      pr_set->narray[last_used++] = pr_set->narray[index];
   4354    }
   4355  }
   4356  pr_set->nsize = last_used;
   4357 }
   4358 
   4359 PR_IMPLEMENT(PRInt32)
   4360 PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex,
   4361          PRIntervalTime timeout) {
   4362  fd_set rd, wr, ex;
   4363  struct timeval tv, *tvp;
   4364  PRInt32 max, max_fd;
   4365  PRInt32 rv;
   4366  /*
   4367   * For restarting select() if it is interrupted by a Unix signal.
   4368   * We use these variables to figure out how much time has elapsed
   4369   * and how much of the timeout still remains.
   4370   */
   4371  PRIntervalTime start = 0, elapsed, remaining;
   4372 
   4373  static PRBool unwarned = PR_TRUE;
   4374  if (unwarned) {
   4375    unwarned = _PR_Obsolete("PR_Select", "PR_Poll");
   4376  }
   4377 
   4378  FD_ZERO(&rd);
   4379  FD_ZERO(&wr);
   4380  FD_ZERO(&ex);
   4381 
   4382  max_fd = _PR_getset(pr_rd, &rd);
   4383  max_fd = (max = _PR_getset(pr_wr, &wr)) > max_fd ? max : max_fd;
   4384  max_fd = (max = _PR_getset(pr_ex, &ex)) > max_fd ? max : max_fd;
   4385 
   4386  if (timeout == PR_INTERVAL_NO_TIMEOUT) {
   4387    tvp = NULL;
   4388  } else {
   4389    tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
   4390    tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
   4391        timeout - PR_SecondsToInterval(tv.tv_sec));
   4392    tvp = &tv;
   4393    start = PR_IntervalNow();
   4394  }
   4395 
   4396 retry:
   4397  rv = select(max_fd + 1, (_PRSelectFdSetArg_t)&rd, (_PRSelectFdSetArg_t)&wr,
   4398              (_PRSelectFdSetArg_t)&ex, tvp);
   4399 
   4400  if (rv == -1 && errno == EINTR) {
   4401    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
   4402      goto retry;
   4403    } else {
   4404      elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
   4405      if (elapsed > timeout) {
   4406        rv = 0; /* timed out */
   4407      } else {
   4408        remaining = timeout - elapsed;
   4409        tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
   4410        tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
   4411            remaining - PR_SecondsToInterval(tv.tv_sec));
   4412        goto retry;
   4413      }
   4414    }
   4415  }
   4416 
   4417  if (rv > 0) {
   4418    _PR_setset(pr_rd, &rd);
   4419    _PR_setset(pr_wr, &wr);
   4420    _PR_setset(pr_ex, &ex);
   4421  } else if (rv == -1) {
   4422    pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
   4423  }
   4424  return rv;
   4425 }
   4426 #endif /* defined(_PR_PTHREADS) */
   4427 
   4428 #ifdef MOZ_UNICODE
   4429 /* ================ UTF16 Interfaces ================================ */
   4430 PR_IMPLEMENT(PRFileDesc*)
   4431 PR_OpenFileUTF16(const PRUnichar* name, PRIntn flags, PRIntn mode) {
   4432  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   4433  return NULL;
   4434 }
   4435 
   4436 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir* dir) {
   4437  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   4438  return PR_FAILURE;
   4439 }
   4440 
   4441 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar* name) {
   4442  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   4443  return NULL;
   4444 }
   4445 
   4446 PR_IMPLEMENT(PRDirEntryUTF16*)
   4447 PR_ReadDirUTF16(PRDirUTF16* dir, PRDirFlags flags) {
   4448  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   4449  return NULL;
   4450 }
   4451 
   4452 PR_IMPLEMENT(PRStatus)
   4453 PR_GetFileInfo64UTF16(const PRUnichar* fn, PRFileInfo64* info) {
   4454  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   4455  return PR_FAILURE;
   4456 }
   4457 /* ================ UTF16 Interfaces ================================ */
   4458 #endif /* MOZ_UNICODE */
   4459 
   4460 /* ptio.c */