tor-browser

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

prsocket.c (53775B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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 #include "primpl.h"
      7 
      8 #include <string.h>
      9 
     10 #if defined(_WIN64)
     11 #  ifndef SO_UPDATE_CONNECT_CONTEXT
     12 #    define SO_UPDATE_CONNECT_CONTEXT 0x7010
     13 #  endif
     14 #endif
     15 
     16 /************************************************************************/
     17 
     18 /* These two functions are only used in assertions. */
     19 #if defined(DEBUG)
     20 
     21 PRBool IsValidNetAddr(const PRNetAddr* addr) {
     22  if ((addr != NULL)
     23 #  if defined(XP_UNIX)
     24      && (addr->raw.family != PR_AF_LOCAL)
     25 #  endif
     26      && (addr->raw.family != PR_AF_INET6) &&
     27      (addr->raw.family != PR_AF_INET)) {
     28    return PR_FALSE;
     29  }
     30  return PR_TRUE;
     31 }
     32 
     33 static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) {
     34  /*
     35   * The definition of the length of a Unix domain socket address
     36   * is not uniform, so we don't check it.
     37   */
     38  if ((addr != NULL)
     39 #  if defined(XP_UNIX)
     40      && (addr->raw.family != AF_UNIX)
     41 #  endif
     42      && (PR_NETADDR_SIZE(addr) != addr_len)) {
     43 #  if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
     44    /*
     45     * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
     46     * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
     47     * field and is 28 bytes.  It is possible for socket functions
     48     * to return an addr_len greater than sizeof(struct sockaddr_in6).
     49     * We need to allow that.  (Bugzilla bug #77264)
     50     */
     51    if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) {
     52      return PR_TRUE;
     53    }
     54 #  endif
     55    /*
     56     * The accept(), getsockname(), etc. calls on some platforms
     57     * do not set the actual socket address length on return.
     58     * In this case, we verifiy addr_len is still the value we
     59     * passed in (i.e., sizeof(PRNetAddr)).
     60     */
     61 #  if defined(QNX)
     62    if (sizeof(PRNetAddr) == addr_len) {
     63      return PR_TRUE;
     64    }
     65 #  endif
     66    return PR_FALSE;
     67  }
     68  return PR_TRUE;
     69 }
     70 
     71 #endif /* DEBUG */
     72 
     73 static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc* fd, const PRIOVec* iov,
     74                                        PRInt32 iov_size,
     75                                        PRIntervalTime timeout) {
     76  PRThread* me = _PR_MD_CURRENT_THREAD();
     77  int w = 0;
     78  const PRIOVec* tmp_iov;
     79 #define LOCAL_MAXIOV 8
     80  PRIOVec local_iov[LOCAL_MAXIOV];
     81  PRIOVec* iov_copy = NULL;
     82  int tmp_out;
     83  int index, iov_cnt;
     84  int count = 0, sz = 0; /* 'count' is the return value. */
     85 
     86  if (_PR_PENDING_INTERRUPT(me)) {
     87    me->flags &= ~_PR_INTERRUPT;
     88    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
     89    return -1;
     90  }
     91  if (_PR_IO_PENDING(me)) {
     92    PR_SetError(PR_IO_PENDING_ERROR, 0);
     93    return -1;
     94  }
     95 
     96  /*
     97   * Assume the first writev will succeed.  Copy iov's only on
     98   * failure.
     99   */
    100  tmp_iov = iov;
    101  for (index = 0; index < iov_size; index++) {
    102    sz += iov[index].iov_len;
    103  }
    104 
    105  iov_cnt = iov_size;
    106 
    107  while (sz > 0) {
    108    w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
    109    if (w < 0) {
    110      count = -1;
    111      break;
    112    }
    113    count += w;
    114    if (fd->secret->nonblocking) {
    115      break;
    116    }
    117    sz -= w;
    118 
    119    if (sz > 0) {
    120      /* find the next unwritten vector */
    121      for (index = 0, tmp_out = count; tmp_out >= iov[index].iov_len;
    122           tmp_out -= iov[index].iov_len, index++) {
    123        ;
    124      } /* nothing to execute */
    125 
    126      if (tmp_iov == iov) {
    127        /*
    128         * The first writev failed so we
    129         * must copy iov's around.
    130         * Avoid calloc/free if there
    131         * are few enough iov's.
    132         */
    133        if (iov_size - index <= LOCAL_MAXIOV) {
    134          iov_copy = local_iov;
    135        } else if ((iov_copy = (PRIOVec*)PR_CALLOC((iov_size - index) *
    136                                                   sizeof *iov_copy)) == NULL) {
    137          PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    138          return -1;
    139        }
    140        tmp_iov = iov_copy;
    141      }
    142 
    143      PR_ASSERT(tmp_iov == iov_copy);
    144 
    145      /* fill in the first partial read */
    146      iov_copy[0].iov_base = &(((char*)iov[index].iov_base)[tmp_out]);
    147      iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
    148      index++;
    149 
    150      /* copy the remaining vectors */
    151      for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
    152        iov_copy[iov_cnt].iov_base = iov[index].iov_base;
    153        iov_copy[iov_cnt].iov_len = iov[index].iov_len;
    154      }
    155    }
    156  }
    157 
    158  if (iov_copy != local_iov) {
    159    PR_DELETE(iov_copy);
    160  }
    161  return count;
    162 }
    163 
    164 /************************************************************************/
    165 
    166 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd) {
    167  PRFileDesc* fd;
    168 
    169  if (!_pr_initialized) {
    170    _PR_ImplicitInitialization();
    171  }
    172  fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
    173  if (fd != NULL) {
    174    _PR_MD_MAKE_NONBLOCK(fd);
    175    _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
    176 #ifdef _PR_NEED_SECRET_AF
    177    /* this means we can only import IPv4 sockets here.
    178     * but this is what the function in ptio.c does.
    179     * We need a way to import IPv6 sockets, too.
    180     */
    181    fd->secret->af = AF_INET;
    182 #endif
    183  } else {
    184    _PR_MD_CLOSE_SOCKET(osfd);
    185  }
    186  return (fd);
    187 }
    188 
    189 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd) {
    190  PRFileDesc* fd;
    191 
    192  if (!_pr_initialized) {
    193    _PR_ImplicitInitialization();
    194  }
    195  fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
    196  if (fd != NULL) {
    197    _PR_MD_MAKE_NONBLOCK(fd);
    198    _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
    199  } else {
    200    _PR_MD_CLOSE_SOCKET(osfd);
    201  }
    202  return (fd);
    203 }
    204 
    205 static const PRIOMethods* PR_GetSocketPollFdMethods(void);
    206 
    207 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd) {
    208  PRFileDesc* fd;
    209 
    210  if (!_pr_initialized) {
    211    _PR_ImplicitInitialization();
    212  }
    213 
    214  fd = _PR_Getfd();
    215 
    216  if (fd == NULL) {
    217    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    218  } else {
    219    fd->secret->md.osfd = osfd;
    220    fd->secret->inheritable = _PR_TRI_FALSE;
    221    fd->secret->state = _PR_FILEDESC_OPEN;
    222    fd->methods = PR_GetSocketPollFdMethods();
    223  }
    224 
    225  return fd;
    226 } /* PR_CreateSocketPollFD */
    227 
    228 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) {
    229  if (NULL == fd) {
    230    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    231    return PR_FAILURE;
    232  }
    233  fd->secret->state = _PR_FILEDESC_CLOSED;
    234  _PR_Putfd(fd);
    235  return PR_SUCCESS;
    236 } /* PR_DestroySocketPollFd */
    237 
    238 static PRStatus PR_CALLBACK SocketConnect(PRFileDesc* fd, const PRNetAddr* addr,
    239                                          PRIntervalTime timeout) {
    240  PRInt32 rv; /* Return value of _PR_MD_CONNECT */
    241  const PRNetAddr* addrp = addr;
    242 #if defined(_PR_INET6)
    243  PRNetAddr addrCopy;
    244 #endif
    245  PRThread* me = _PR_MD_CURRENT_THREAD();
    246 
    247  if (_PR_PENDING_INTERRUPT(me)) {
    248    me->flags &= ~_PR_INTERRUPT;
    249    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    250    return PR_FAILURE;
    251  }
    252 #if defined(_PR_INET6)
    253  if (addr->raw.family == PR_AF_INET6) {
    254    addrCopy = *addr;
    255    addrCopy.raw.family = AF_INET6;
    256    addrp = &addrCopy;
    257  }
    258 #endif
    259 
    260  rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
    261  PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
    262  if (rv == 0) {
    263    return PR_SUCCESS;
    264  } else {
    265    return PR_FAILURE;
    266  }
    267 }
    268 
    269 static PRStatus PR_CALLBACK SocketConnectContinue(PRFileDesc* fd,
    270                                                  PRInt16 out_flags) {
    271  PROsfd osfd;
    272  int err;
    273 
    274  if (out_flags & PR_POLL_NVAL) {
    275    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    276    return PR_FAILURE;
    277  }
    278  if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
    279    PR_ASSERT(out_flags == 0);
    280    PR_SetError(PR_IN_PROGRESS_ERROR, 0);
    281    return PR_FAILURE;
    282  }
    283 
    284  osfd = fd->secret->md.osfd;
    285 
    286 #if defined(XP_UNIX)
    287 
    288  err = _MD_unix_get_nonblocking_connect_error(osfd);
    289  if (err != 0) {
    290    _PR_MD_MAP_CONNECT_ERROR(err);
    291    return PR_FAILURE;
    292  }
    293  return PR_SUCCESS;
    294 
    295 #elif defined(WIN32)
    296 
    297  if (out_flags & PR_POLL_EXCEPT) {
    298    int len = sizeof(err);
    299    if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char*)&err, &len) ==
    300        SOCKET_ERROR) {
    301      _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
    302      return PR_FAILURE;
    303    }
    304    if (err != 0) {
    305      _PR_MD_MAP_CONNECT_ERROR(err);
    306    } else {
    307 #  if defined(_WIN64)
    308      if (fd->secret->overlappedActive) {
    309        PRInt32 rvSent;
    310        if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent,
    311                                FALSE) == FALSE) {
    312          err = WSAGetLastError();
    313          PR_LOG(
    314              _pr_io_lm, PR_LOG_MIN,
    315              ("SocketConnectContinue GetOverlappedResult failed %d\n", err));
    316          if (err != ERROR_IO_INCOMPLETE) {
    317            _PR_MD_MAP_CONNECT_ERROR(err);
    318            fd->secret->overlappedActive = PR_FALSE;
    319          }
    320        }
    321      }
    322      if (err == 0) {
    323        PR_SetError(PR_UNKNOWN_ERROR, 0);
    324      }
    325 #  else
    326      PR_SetError(PR_UNKNOWN_ERROR, 0);
    327 #  endif
    328    }
    329    return PR_FAILURE;
    330  }
    331 
    332  PR_ASSERT(out_flags & PR_POLL_WRITE);
    333 
    334 #  if defined(_WIN64)
    335  if (fd->secret->alreadyConnected) {
    336    fd->secret->alreadyConnected = PR_FALSE;
    337  }
    338  /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
    339   * input/output.
    340   * To get result we need to use GetOverlappedResult. */
    341  if (fd->secret->overlappedActive) {
    342    PR_ASSERT(fd->secret->nonblocking);
    343    PRInt32 rvSent;
    344    if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE) ==
    345        TRUE) {
    346      fd->secret->overlappedActive = PR_FALSE;
    347      PR_LOG(_pr_io_lm, PR_LOG_MIN,
    348             ("SocketConnectContinue GetOverlappedResult succeeded\n"));
    349      /* When ConnectEx is used, all previously set socket options and
    350       * property are not enabled and to enable them
    351       * SO_UPDATE_CONNECT_CONTEXT option need to be set. */
    352      if (setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL,
    353                     0) != 0) {
    354        err = WSAGetLastError();
    355        PR_LOG(_pr_io_lm, PR_LOG_MIN,
    356               ("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT "
    357                "failed %d\n",
    358                err));
    359        _PR_MD_MAP_SETSOCKOPT_ERROR(err);
    360        return PR_FAILURE;
    361      }
    362      return PR_SUCCESS;
    363    } else {
    364      err = WSAGetLastError();
    365      PR_LOG(_pr_io_lm, PR_LOG_MIN,
    366             ("SocketConnectContinue GetOverlappedResult failed %d\n", err));
    367      if (err != ERROR_IO_INCOMPLETE) {
    368        _PR_MD_MAP_CONNECT_ERROR(err);
    369        fd->secret->overlappedActive = PR_FALSE;
    370        return PR_FAILURE;
    371      } else {
    372        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
    373        return PR_FAILURE;
    374      }
    375    }
    376  }
    377 #  endif
    378 
    379  return PR_SUCCESS;
    380 
    381 #else
    382  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    383  return PR_FAILURE;
    384 #endif
    385 }
    386 
    387 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc* pd) {
    388  /* Find the NSPR layer and invoke its connectcontinue method */
    389  PRFileDesc* bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
    390 
    391  if (NULL == bottom) {
    392    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    393    return PR_FAILURE;
    394  }
    395  return SocketConnectContinue(bottom, pd->out_flags);
    396 }
    397 
    398 static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc* fd, PRNetAddr* addr,
    399                                            PRIntervalTime timeout) {
    400  PROsfd osfd;
    401  PRFileDesc* fd2;
    402  PRUint32 al;
    403  PRThread* me = _PR_MD_CURRENT_THREAD();
    404 #ifdef WINNT
    405  PRNetAddr addrCopy;
    406 #endif
    407 
    408  if (_PR_PENDING_INTERRUPT(me)) {
    409    me->flags &= ~_PR_INTERRUPT;
    410    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    411    return 0;
    412  }
    413  if (_PR_IO_PENDING(me)) {
    414    PR_SetError(PR_IO_PENDING_ERROR, 0);
    415    return 0;
    416  }
    417 
    418 #ifdef WINNT
    419  if (addr == NULL) {
    420    addr = &addrCopy;
    421  }
    422 #endif
    423  al = sizeof(PRNetAddr);
    424  osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
    425  if (osfd == -1) {
    426    return 0;
    427  }
    428 
    429  fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
    430  if (!fd2) {
    431    _PR_MD_CLOSE_SOCKET(osfd);
    432    return NULL;
    433  }
    434 
    435  fd2->secret->nonblocking = fd->secret->nonblocking;
    436  fd2->secret->inheritable = fd->secret->inheritable;
    437 #ifdef WINNT
    438  if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
    439    /*
    440     * The new socket has been associated with an I/O
    441     * completion port.  There is no going back.
    442     */
    443    fd2->secret->md.io_model_committed = PR_TRUE;
    444  }
    445  PR_ASSERT(al == PR_NETADDR_SIZE(addr));
    446  fd2->secret->md.accepted_socket = PR_TRUE;
    447  memcpy(&fd2->secret->md.peer_addr, addr, al);
    448 #endif
    449 
    450  /*
    451   * On some platforms, the new socket created by accept()
    452   * inherits the nonblocking (or overlapped io) attribute
    453   * of the listening socket.  As an optimization, these
    454   * platforms can skip the following _PR_MD_MAKE_NONBLOCK
    455   * call.
    456   */
    457 #if !defined(SOLARIS) && !defined(WINNT)
    458  _PR_MD_MAKE_NONBLOCK(fd2);
    459 #endif
    460 
    461 #ifdef _PR_INET6
    462  if (addr && (AF_INET6 == addr->raw.family)) {
    463    addr->raw.family = PR_AF_INET6;
    464  }
    465 #endif
    466  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    467  PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
    468 
    469  return fd2;
    470 }
    471 
    472 #ifdef WINNT
    473 PR_IMPLEMENT(PRFileDesc*)
    474 PR_NTFast_Accept(PRFileDesc* fd, PRNetAddr* addr, PRIntervalTime timeout) {
    475  PROsfd osfd;
    476  PRFileDesc* fd2;
    477  PRIntn al;
    478  PRThread* me = _PR_MD_CURRENT_THREAD();
    479  PRNetAddr addrCopy;
    480 
    481  if (_PR_PENDING_INTERRUPT(me)) {
    482    me->flags &= ~_PR_INTERRUPT;
    483    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    484    return 0;
    485  }
    486  if (_PR_IO_PENDING(me)) {
    487    PR_SetError(PR_IO_PENDING_ERROR, 0);
    488    return 0;
    489  }
    490 
    491  if (addr == NULL) {
    492    addr = &addrCopy;
    493  }
    494  al = PR_NETADDR_SIZE(addr);
    495  osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
    496  if (osfd == -1) {
    497    return 0;
    498  }
    499 
    500  fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
    501  if (!fd2) {
    502    _PR_MD_CLOSE_SOCKET(osfd);
    503  } else {
    504    fd2->secret->nonblocking = fd->secret->nonblocking;
    505    fd2->secret->md.io_model_committed = PR_TRUE;
    506    PR_ASSERT(al == PR_NETADDR_SIZE(addr));
    507    fd2->secret->md.accepted_socket = PR_TRUE;
    508    memcpy(&fd2->secret->md.peer_addr, addr, al);
    509 #  ifdef _PR_INET6
    510    if (AF_INET6 == addr->raw.family) {
    511      addr->raw.family = PR_AF_INET6;
    512    }
    513 #  endif
    514 #  ifdef _PR_NEED_SECRET_AF
    515    fd2->secret->af = fd->secret->af;
    516 #  endif
    517  }
    518  return fd2;
    519 }
    520 #endif /* WINNT */
    521 
    522 static PRStatus PR_CALLBACK SocketBind(PRFileDesc* fd, const PRNetAddr* addr) {
    523  PRInt32 result;
    524  const PRNetAddr* addrp = addr;
    525 #if defined(_PR_INET6)
    526  PRNetAddr addrCopy;
    527 #endif
    528 
    529  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    530 
    531 #ifdef XP_UNIX
    532  if (addr->raw.family == AF_UNIX) {
    533    /* Disallow relative pathnames */
    534    if (addr->local.path[0] != '/') {
    535      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    536      return PR_FAILURE;
    537    }
    538  }
    539 #endif /* XP_UNIX */
    540 
    541 #if defined(_PR_INET6)
    542  if (addr->raw.family == PR_AF_INET6) {
    543    addrCopy = *addr;
    544    addrCopy.raw.family = AF_INET6;
    545    addrp = &addrCopy;
    546  }
    547 #endif
    548  result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
    549  if (result < 0) {
    550    return PR_FAILURE;
    551  }
    552  return PR_SUCCESS;
    553 }
    554 
    555 static PRStatus PR_CALLBACK SocketListen(PRFileDesc* fd, PRIntn backlog) {
    556  PRInt32 result;
    557 
    558  result = _PR_MD_LISTEN(fd, backlog);
    559  if (result < 0) {
    560    return PR_FAILURE;
    561  }
    562  return PR_SUCCESS;
    563 }
    564 
    565 static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc* fd, PRIntn how) {
    566  PRInt32 result;
    567 
    568  result = _PR_MD_SHUTDOWN(fd, how);
    569  if (result < 0) {
    570    return PR_FAILURE;
    571  }
    572  return PR_SUCCESS;
    573 }
    574 
    575 static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc* fd, void* buf, PRInt32 amount,
    576                                      PRIntn flags, PRIntervalTime timeout) {
    577  PRInt32 rv;
    578  PRThread* me = _PR_MD_CURRENT_THREAD();
    579 
    580  if ((flags != 0) && (flags != PR_MSG_PEEK)) {
    581    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    582    return -1;
    583  }
    584  if (_PR_PENDING_INTERRUPT(me)) {
    585    me->flags &= ~_PR_INTERRUPT;
    586    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    587    return -1;
    588  }
    589  if (_PR_IO_PENDING(me)) {
    590    PR_SetError(PR_IO_PENDING_ERROR, 0);
    591    return -1;
    592  }
    593 
    594  PR_LOG(_pr_io_lm, PR_LOG_MAX,
    595         ("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d", fd,
    596          fd->secret->md.osfd, buf, amount, flags));
    597 
    598 #ifdef _PR_HAVE_PEEK_BUFFER
    599  if (fd->secret->peekBytes != 0) {
    600    rv = (amount < fd->secret->peekBytes) ? amount : fd->secret->peekBytes;
    601    memcpy(buf, fd->secret->peekBuffer, rv);
    602    if (flags == 0) {
    603      /* consume the bytes in the peek buffer */
    604      fd->secret->peekBytes -= rv;
    605      if (fd->secret->peekBytes != 0) {
    606        memmove(fd->secret->peekBuffer, fd->secret->peekBuffer + rv,
    607                fd->secret->peekBytes);
    608      }
    609    }
    610    return rv;
    611  }
    612 
    613  /* allocate peek buffer, if necessary */
    614  if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
    615    PR_ASSERT(0 == fd->secret->peekBytes);
    616    /* impose a max size on the peek buffer */
    617    if (amount > _PR_PEEK_BUFFER_MAX) {
    618      amount = _PR_PEEK_BUFFER_MAX;
    619    }
    620    if (fd->secret->peekBufSize < amount) {
    621      if (fd->secret->peekBuffer) {
    622        PR_Free(fd->secret->peekBuffer);
    623      }
    624      fd->secret->peekBufSize = amount;
    625      fd->secret->peekBuffer = PR_Malloc(amount);
    626      if (NULL == fd->secret->peekBuffer) {
    627        fd->secret->peekBufSize = 0;
    628        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    629        return -1;
    630      }
    631    }
    632  }
    633 #endif
    634 
    635  rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
    636  PR_LOG(_pr_io_lm, PR_LOG_MAX,
    637         ("recv -> %d, error = %d, os error = %d", rv, PR_GetError(),
    638          PR_GetOSError()));
    639 
    640 #ifdef _PR_HAVE_PEEK_BUFFER
    641  if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
    642    if (rv > 0) {
    643      memcpy(fd->secret->peekBuffer, buf, rv);
    644      fd->secret->peekBytes = rv;
    645    }
    646  }
    647 #endif
    648 
    649  return rv;
    650 }
    651 
    652 static PRInt32 PR_CALLBACK SocketRead(PRFileDesc* fd, void* buf,
    653                                      PRInt32 amount) {
    654  return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    655 }
    656 
    657 static PRInt32 PR_CALLBACK SocketSend(PRFileDesc* fd, const void* buf,
    658                                      PRInt32 amount, PRIntn flags,
    659                                      PRIntervalTime timeout) {
    660  PRInt32 temp, count;
    661  PRThread* me = _PR_MD_CURRENT_THREAD();
    662 
    663  if (_PR_PENDING_INTERRUPT(me)) {
    664    me->flags &= ~_PR_INTERRUPT;
    665    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    666    return -1;
    667  }
    668  if (_PR_IO_PENDING(me)) {
    669    PR_SetError(PR_IO_PENDING_ERROR, 0);
    670    return -1;
    671  }
    672 
    673  count = 0;
    674  while (amount > 0) {
    675    PR_LOG(_pr_io_lm, PR_LOG_MAX,
    676           ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d", fd,
    677            fd->secret->md.osfd, buf, amount));
    678    temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
    679    if (temp < 0) {
    680      count = -1;
    681      break;
    682    }
    683 
    684    count += temp;
    685    if (fd->secret->nonblocking) {
    686      break;
    687    }
    688    buf = (const void*)((const char*)buf + temp);
    689 
    690    amount -= temp;
    691  }
    692  PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
    693  return count;
    694 }
    695 
    696 static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc* fd, const void* buf,
    697                                       PRInt32 amount) {
    698  return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    699 }
    700 
    701 static PRStatus PR_CALLBACK SocketClose(PRFileDesc* fd) {
    702  if (!fd || !fd->secret ||
    703      (fd->secret->state != _PR_FILEDESC_OPEN &&
    704       fd->secret->state != _PR_FILEDESC_CLOSED)) {
    705    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    706    return PR_FAILURE;
    707  }
    708 
    709  if (fd->secret->state == _PR_FILEDESC_OPEN) {
    710 #if defined(_WIN64) && defined(WIN95)
    711    /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
    712     * input/output. Before closing such a socket we must cancelIO.
    713     */
    714    if (fd->secret->overlappedActive) {
    715      PR_ASSERT(fd->secret->nonblocking);
    716      if (CancelIo((HANDLE)fd->secret->md.osfd) == TRUE) {
    717        PR_LOG(_pr_io_lm, PR_LOG_MIN, ("SocketClose - CancelIo succeeded\n"));
    718      } else {
    719        DWORD err = WSAGetLastError();
    720        PR_LOG(_pr_io_lm, PR_LOG_MIN,
    721               ("SocketClose - CancelIo failed err=%x\n", err));
    722      }
    723 
    724      DWORD rvSent;
    725      if (GetOverlappedResult((HANDLE)fd->secret->md.osfd, &fd->secret->ol,
    726                              &rvSent, FALSE) == TRUE) {
    727        fd->secret->overlappedActive = PR_FALSE;
    728        PR_LOG(_pr_io_lm, PR_LOG_MIN,
    729               ("SocketClose GetOverlappedResult succeeded\n"));
    730      } else {
    731        DWORD err = WSAGetLastError();
    732        PR_LOG(_pr_io_lm, PR_LOG_MIN,
    733               ("SocketClose GetOverlappedResult failed %d\n", err));
    734        if (err != ERROR_IO_INCOMPLETE) {
    735          _PR_MD_MAP_CONNECT_ERROR(err);
    736          fd->secret->overlappedActive = PR_FALSE;
    737        }
    738      }
    739    }
    740 
    741    if (fd->secret->overlappedActive && _fd_waiting_for_overlapped_done_lock) {
    742      // Put osfd into the list to be checked later.
    743      PRFileDescList* forWaiting = PR_NEW(PRFileDescList);
    744      if (!forWaiting) {
    745        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    746        return PR_FAILURE;
    747      }
    748      forWaiting->fd = fd;
    749 
    750      PR_Lock(_fd_waiting_for_overlapped_done_lock);
    751      forWaiting->next = _fd_waiting_for_overlapped_done;
    752      _fd_waiting_for_overlapped_done = forWaiting;
    753      PR_Unlock(_fd_waiting_for_overlapped_done_lock);
    754 
    755      return PR_SUCCESS;
    756    }
    757 #endif
    758 
    759    if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
    760      return PR_FAILURE;
    761    }
    762    fd->secret->state = _PR_FILEDESC_CLOSED;
    763  }
    764 
    765 #ifdef _PR_HAVE_PEEK_BUFFER
    766  if (fd->secret->peekBuffer) {
    767    PR_ASSERT(fd->secret->peekBufSize > 0);
    768    PR_DELETE(fd->secret->peekBuffer);
    769    fd->secret->peekBufSize = 0;
    770    fd->secret->peekBytes = 0;
    771  }
    772 #endif
    773 
    774  PR_FreeFileDesc(fd);
    775  return PR_SUCCESS;
    776 }
    777 
    778 static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc* fd) {
    779  PRInt32 rv;
    780 #ifdef _PR_HAVE_PEEK_BUFFER
    781  if (fd->secret->peekBytes != 0) {
    782    return fd->secret->peekBytes;
    783  }
    784 #endif
    785  rv = _PR_MD_SOCKETAVAILABLE(fd);
    786  return rv;
    787 }
    788 
    789 static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc* fd) {
    790  PRInt64 rv;
    791 #ifdef _PR_HAVE_PEEK_BUFFER
    792  if (fd->secret->peekBytes != 0) {
    793    LL_I2L(rv, fd->secret->peekBytes);
    794    return rv;
    795  }
    796 #endif
    797  LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
    798  return rv;
    799 }
    800 
    801 static PRStatus PR_CALLBACK SocketSync(PRFileDesc* fd) { return PR_SUCCESS; }
    802 
    803 static PRInt32 PR_CALLBACK SocketSendTo(PRFileDesc* fd, const void* buf,
    804                                        PRInt32 amount, PRIntn flags,
    805                                        const PRNetAddr* addr,
    806                                        PRIntervalTime timeout) {
    807  PRInt32 temp, count;
    808  const PRNetAddr* addrp = addr;
    809 #if defined(_PR_INET6)
    810  PRNetAddr addrCopy;
    811 #endif
    812  PRThread* me = _PR_MD_CURRENT_THREAD();
    813 
    814  if (_PR_PENDING_INTERRUPT(me)) {
    815    me->flags &= ~_PR_INTERRUPT;
    816    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    817    return -1;
    818  }
    819  if (_PR_IO_PENDING(me)) {
    820    PR_SetError(PR_IO_PENDING_ERROR, 0);
    821    return -1;
    822  }
    823 
    824  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    825 #if defined(_PR_INET6)
    826  if (addr->raw.family == PR_AF_INET6) {
    827    addrCopy = *addr;
    828    addrCopy.raw.family = AF_INET6;
    829    addrp = &addrCopy;
    830  }
    831 #endif
    832 
    833  count = 0;
    834  do {
    835    temp = _PR_MD_SENDTO(fd, buf, amount, flags, addrp, PR_NETADDR_SIZE(addr),
    836                         timeout);
    837    if (temp < 0) {
    838      count = -1;
    839      break;
    840    }
    841    count += temp;
    842    if (fd->secret->nonblocking) {
    843      break;
    844    }
    845    buf = (const void*)((const char*)buf + temp);
    846    amount -= temp;
    847  } while (amount > 0);
    848  return count;
    849 }
    850 
    851 #if defined(_WIN64) && defined(WIN95)
    852 static PRInt32 PR_CALLBACK SocketTCPSendTo(PRFileDesc* fd, const void* buf,
    853                                           PRInt32 amount, PRIntn flags,
    854                                           const PRNetAddr* addr,
    855                                           PRIntervalTime timeout) {
    856  PRInt32 temp, count;
    857  const PRNetAddr* addrp = addr;
    858 #  if defined(_PR_INET6)
    859  PRNetAddr addrCopy;
    860 #  endif
    861  PRThread* me = _PR_MD_CURRENT_THREAD();
    862 
    863  if (_PR_PENDING_INTERRUPT(me)) {
    864    me->flags &= ~_PR_INTERRUPT;
    865    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    866    return -1;
    867  }
    868  if (_PR_IO_PENDING(me)) {
    869    PR_SetError(PR_IO_PENDING_ERROR, 0);
    870    return -1;
    871  }
    872 
    873  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    874 #  if defined(_PR_INET6)
    875  if (addr->raw.family == PR_AF_INET6) {
    876    addrCopy = *addr;
    877    addrCopy.raw.family = AF_INET6;
    878    addrp = &addrCopy;
    879  }
    880 #  endif
    881 
    882  count = 0;
    883  while (amount > 0) {
    884    temp = _PR_MD_TCPSENDTO(fd, buf, amount, flags, addrp,
    885                            PR_NETADDR_SIZE(addr), timeout);
    886    if (temp < 0) {
    887      count = -1;
    888      break;
    889    }
    890    count += temp;
    891    if (fd->secret->nonblocking) {
    892      break;
    893    }
    894    buf = (const void*)((const char*)buf + temp);
    895    amount -= temp;
    896  }
    897  return count;
    898 }
    899 #endif
    900 
    901 static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc* fd, void* buf,
    902                                          PRInt32 amount, PRIntn flags,
    903                                          PRNetAddr* addr,
    904                                          PRIntervalTime timeout) {
    905  PRInt32 rv;
    906  PRUint32 al;
    907  PRThread* me = _PR_MD_CURRENT_THREAD();
    908 
    909  if (_PR_PENDING_INTERRUPT(me)) {
    910    me->flags &= ~_PR_INTERRUPT;
    911    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    912    return -1;
    913  }
    914  if (_PR_IO_PENDING(me)) {
    915    PR_SetError(PR_IO_PENDING_ERROR, 0);
    916    return -1;
    917  }
    918 
    919  al = sizeof(PRNetAddr);
    920  rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
    921 #ifdef _PR_INET6
    922  if (addr && (AF_INET6 == addr->raw.family)) {
    923    addr->raw.family = PR_AF_INET6;
    924  }
    925 #endif
    926  return rv;
    927 }
    928 
    929 static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc* sd, PRFileDesc** nd,
    930                                            PRNetAddr** raddr, void* buf,
    931                                            PRInt32 amount,
    932                                            PRIntervalTime timeout) {
    933  PRInt32 rv;
    934  PRThread* me = _PR_MD_CURRENT_THREAD();
    935 
    936  if (_PR_PENDING_INTERRUPT(me)) {
    937    me->flags &= ~_PR_INTERRUPT;
    938    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    939    return -1;
    940  }
    941  if (_PR_IO_PENDING(me)) {
    942    PR_SetError(PR_IO_PENDING_ERROR, 0);
    943    return -1;
    944  }
    945  /* The socket must be in blocking mode. */
    946  if (sd->secret->nonblocking) {
    947    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    948    return -1;
    949  }
    950  *nd = NULL;
    951 
    952 #if defined(WINNT)
    953  {
    954    PROsfd newSock;
    955    PRNetAddr* raddrCopy;
    956 
    957    if (raddr == NULL) {
    958      raddr = &raddrCopy;
    959    }
    960    rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
    961    if (rv < 0) {
    962      rv = -1;
    963    } else {
    964      /* Successfully accepted and read; create the new PRFileDesc */
    965      *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
    966      if (*nd == 0) {
    967        _PR_MD_CLOSE_SOCKET(newSock);
    968        /* PR_AllocFileDesc() has invoked PR_SetError(). */
    969        rv = -1;
    970      } else {
    971        (*nd)->secret->md.io_model_committed = PR_TRUE;
    972        (*nd)->secret->md.accepted_socket = PR_TRUE;
    973        memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr));
    974 #  ifdef _PR_INET6
    975        if (AF_INET6 == *raddr->raw.family) {
    976          *raddr->raw.family = PR_AF_INET6;
    977        }
    978 #  endif
    979      }
    980    }
    981  }
    982 #else
    983  rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
    984 #endif
    985  return rv;
    986 }
    987 
    988 #ifdef WINNT
    989 PR_IMPLEMENT(PRInt32)
    990 PR_NTFast_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
    991                     void* buf, PRInt32 amount, PRIntervalTime timeout) {
    992  PRInt32 rv;
    993  PROsfd newSock;
    994  PRThread* me = _PR_MD_CURRENT_THREAD();
    995  PRNetAddr* raddrCopy;
    996 
    997  if (_PR_PENDING_INTERRUPT(me)) {
    998    me->flags &= ~_PR_INTERRUPT;
    999    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1000    return -1;
   1001  }
   1002  if (_PR_IO_PENDING(me)) {
   1003    PR_SetError(PR_IO_PENDING_ERROR, 0);
   1004    return -1;
   1005  }
   1006  *nd = NULL;
   1007 
   1008  if (raddr == NULL) {
   1009    raddr = &raddrCopy;
   1010  }
   1011  rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout,
   1012                               PR_TRUE, NULL, NULL);
   1013  if (rv < 0) {
   1014    rv = -1;
   1015  } else {
   1016    /* Successfully accepted and read; create the new PRFileDesc */
   1017    *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
   1018    if (*nd == 0) {
   1019      _PR_MD_CLOSE_SOCKET(newSock);
   1020      /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1021      rv = -1;
   1022    } else {
   1023      (*nd)->secret->md.io_model_committed = PR_TRUE;
   1024      (*nd)->secret->md.accepted_socket = PR_TRUE;
   1025      memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr));
   1026 #  ifdef _PR_INET6
   1027      if (AF_INET6 == *raddr->raw.family) {
   1028        *raddr->raw.family = PR_AF_INET6;
   1029      }
   1030 #  endif
   1031 #  ifdef _PR_NEED_SECRET_AF
   1032      (*nd)->secret->af = sd->secret->af;
   1033 #  endif
   1034    }
   1035  }
   1036  return rv;
   1037 }
   1038 
   1039 PR_IMPLEMENT(PRInt32)
   1040 PR_NTFast_AcceptRead_WithTimeoutCallback(PRFileDesc* sd, PRFileDesc** nd,
   1041                                         PRNetAddr** raddr, void* buf,
   1042                                         PRInt32 amount, PRIntervalTime timeout,
   1043                                         _PR_AcceptTimeoutCallback callback,
   1044                                         void* callbackArg) {
   1045  PRInt32 rv;
   1046  PROsfd newSock;
   1047  PRThread* me = _PR_MD_CURRENT_THREAD();
   1048  PRNetAddr* raddrCopy;
   1049 
   1050  if (_PR_PENDING_INTERRUPT(me)) {
   1051    me->flags &= ~_PR_INTERRUPT;
   1052    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1053    return -1;
   1054  }
   1055  if (_PR_IO_PENDING(me)) {
   1056    PR_SetError(PR_IO_PENDING_ERROR, 0);
   1057    return -1;
   1058  }
   1059  *nd = NULL;
   1060 
   1061  if (raddr == NULL) {
   1062    raddr = &raddrCopy;
   1063  }
   1064  rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout,
   1065                               PR_TRUE, callback, callbackArg);
   1066  if (rv < 0) {
   1067    rv = -1;
   1068  } else {
   1069    /* Successfully accepted and read; create the new PRFileDesc */
   1070    *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
   1071    if (*nd == 0) {
   1072      _PR_MD_CLOSE_SOCKET(newSock);
   1073      /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1074      rv = -1;
   1075    } else {
   1076      (*nd)->secret->md.io_model_committed = PR_TRUE;
   1077      (*nd)->secret->md.accepted_socket = PR_TRUE;
   1078      memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr));
   1079 #  ifdef _PR_INET6
   1080      if (AF_INET6 == *raddr->raw.family) {
   1081        *raddr->raw.family = PR_AF_INET6;
   1082      }
   1083 #  endif
   1084 #  ifdef _PR_NEED_SECRET_AF
   1085      (*nd)->secret->af = sd->secret->af;
   1086 #  endif
   1087    }
   1088  }
   1089  return rv;
   1090 }
   1091 #endif /* WINNT */
   1092 
   1093 #ifdef WINNT
   1094 PR_IMPLEMENT(void)
   1095 PR_NTFast_UpdateAcceptContext(PRFileDesc* socket, PRFileDesc* acceptSocket) {
   1096  _PR_MD_UPDATE_ACCEPT_CONTEXT(socket->secret->md.osfd,
   1097                               acceptSocket->secret->md.osfd);
   1098 }
   1099 #endif /* WINNT */
   1100 
   1101 static PRInt32 PR_CALLBACK SocketSendFile(PRFileDesc* sd, PRSendFileData* sfd,
   1102                                          PRTransmitFileFlags flags,
   1103                                          PRIntervalTime timeout) {
   1104  PRInt32 rv;
   1105  PRThread* me = _PR_MD_CURRENT_THREAD();
   1106 
   1107  if (_PR_PENDING_INTERRUPT(me)) {
   1108    me->flags &= ~_PR_INTERRUPT;
   1109    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1110    return -1;
   1111  }
   1112  if (_PR_IO_PENDING(me)) {
   1113    PR_SetError(PR_IO_PENDING_ERROR, 0);
   1114    return -1;
   1115  }
   1116  /* The socket must be in blocking mode. */
   1117  if (sd->secret->nonblocking) {
   1118    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1119    return -1;
   1120  }
   1121 #if defined(WINNT)
   1122  rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
   1123  if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
   1124    /*
   1125     * This should be kept the same as SocketClose, except
   1126     * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
   1127     * not be called because the socket will be recycled.
   1128     */
   1129    PR_FreeFileDesc(sd);
   1130  }
   1131 #else
   1132  rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
   1133 #endif /* WINNT */
   1134 
   1135  return rv;
   1136 }
   1137 
   1138 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc* sd, PRFileDesc* fd,
   1139                                              const void* headers, PRInt32 hlen,
   1140                                              PRTransmitFileFlags flags,
   1141                                              PRIntervalTime timeout) {
   1142  PRSendFileData sfd;
   1143 
   1144  sfd.fd = fd;
   1145  sfd.file_offset = 0;
   1146  sfd.file_nbytes = 0;
   1147  sfd.header = headers;
   1148  sfd.hlen = hlen;
   1149  sfd.trailer = NULL;
   1150  sfd.tlen = 0;
   1151 
   1152  return (SocketSendFile(sd, &sfd, flags, timeout));
   1153 }
   1154 
   1155 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc* fd, PRNetAddr* addr) {
   1156  PRInt32 result;
   1157  PRUint32 addrlen;
   1158 
   1159  addrlen = sizeof(PRNetAddr);
   1160  result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
   1161  if (result < 0) {
   1162    return PR_FAILURE;
   1163  }
   1164 #ifdef _PR_INET6
   1165  if (AF_INET6 == addr->raw.family) {
   1166    addr->raw.family = PR_AF_INET6;
   1167  }
   1168 #endif
   1169  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1170  PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
   1171  return PR_SUCCESS;
   1172 }
   1173 
   1174 static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
   1175  PRInt32 result;
   1176  PRUint32 addrlen;
   1177 
   1178  addrlen = sizeof(PRNetAddr);
   1179  result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
   1180  if (result < 0) {
   1181    return PR_FAILURE;
   1182  }
   1183 #ifdef _PR_INET6
   1184  if (AF_INET6 == addr->raw.family) {
   1185    addr->raw.family = PR_AF_INET6;
   1186  }
   1187 #endif
   1188  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1189  PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
   1190  return PR_SUCCESS;
   1191 }
   1192 
   1193 static PRInt16 PR_CALLBACK SocketPoll(PRFileDesc* fd, PRInt16 in_flags,
   1194                                      PRInt16* out_flags) {
   1195  *out_flags = 0;
   1196 
   1197 #if defined(_WIN64)
   1198  if (in_flags & PR_POLL_WRITE) {
   1199    if (fd->secret->alreadyConnected) {
   1200      *out_flags = PR_POLL_WRITE;
   1201      return PR_POLL_WRITE;
   1202    }
   1203  }
   1204 #endif
   1205  return in_flags;
   1206 } /* SocketPoll */
   1207 
   1208 static PRIOMethods tcpMethods = {
   1209    PR_DESC_SOCKET_TCP,
   1210    SocketClose,
   1211    SocketRead,
   1212    SocketWrite,
   1213    SocketAvailable,
   1214    SocketAvailable64,
   1215    SocketSync,
   1216    (PRSeekFN)_PR_InvalidInt,
   1217    (PRSeek64FN)_PR_InvalidInt64,
   1218    (PRFileInfoFN)_PR_InvalidStatus,
   1219    (PRFileInfo64FN)_PR_InvalidStatus,
   1220    SocketWritev,
   1221    SocketConnect,
   1222    SocketAccept,
   1223    SocketBind,
   1224    SocketListen,
   1225    SocketShutdown,
   1226    SocketRecv,
   1227    SocketSend,
   1228    (PRRecvfromFN)_PR_InvalidInt,
   1229 #if defined(_WIN64) && defined(WIN95)
   1230    SocketTCPSendTo, /* This is for fast open. We imitate Linux interface. */
   1231 #else
   1232    (PRSendtoFN)_PR_InvalidInt,
   1233 #endif
   1234    SocketPoll,
   1235    SocketAcceptRead,
   1236    SocketTransmitFile,
   1237    SocketGetName,
   1238    SocketGetPeerName,
   1239    (PRReservedFN)_PR_InvalidInt,
   1240    (PRReservedFN)_PR_InvalidInt,
   1241    _PR_SocketGetSocketOption,
   1242    _PR_SocketSetSocketOption,
   1243    SocketSendFile,
   1244    SocketConnectContinue,
   1245    (PRReservedFN)_PR_InvalidInt,
   1246    (PRReservedFN)_PR_InvalidInt,
   1247    (PRReservedFN)_PR_InvalidInt,
   1248    (PRReservedFN)_PR_InvalidInt};
   1249 
   1250 static PRIOMethods udpMethods = {PR_DESC_SOCKET_UDP,
   1251                                 SocketClose,
   1252                                 SocketRead,
   1253                                 SocketWrite,
   1254                                 SocketAvailable,
   1255                                 SocketAvailable64,
   1256                                 SocketSync,
   1257                                 (PRSeekFN)_PR_InvalidInt,
   1258                                 (PRSeek64FN)_PR_InvalidInt64,
   1259                                 (PRFileInfoFN)_PR_InvalidStatus,
   1260                                 (PRFileInfo64FN)_PR_InvalidStatus,
   1261                                 SocketWritev,
   1262                                 SocketConnect,
   1263                                 (PRAcceptFN)_PR_InvalidDesc,
   1264                                 SocketBind,
   1265                                 SocketListen,
   1266                                 SocketShutdown,
   1267                                 SocketRecv,
   1268                                 SocketSend,
   1269                                 SocketRecvFrom,
   1270                                 SocketSendTo,
   1271                                 SocketPoll,
   1272                                 (PRAcceptreadFN)_PR_InvalidInt,
   1273                                 (PRTransmitfileFN)_PR_InvalidInt,
   1274                                 SocketGetName,
   1275                                 SocketGetPeerName,
   1276                                 (PRReservedFN)_PR_InvalidInt,
   1277                                 (PRReservedFN)_PR_InvalidInt,
   1278                                 _PR_SocketGetSocketOption,
   1279                                 _PR_SocketSetSocketOption,
   1280                                 (PRSendfileFN)_PR_InvalidInt,
   1281                                 (PRConnectcontinueFN)_PR_InvalidStatus,
   1282                                 (PRReservedFN)_PR_InvalidInt,
   1283                                 (PRReservedFN)_PR_InvalidInt,
   1284                                 (PRReservedFN)_PR_InvalidInt,
   1285                                 (PRReservedFN)_PR_InvalidInt};
   1286 
   1287 static PRIOMethods socketpollfdMethods = {
   1288    (PRDescType)0,
   1289    (PRCloseFN)_PR_InvalidStatus,
   1290    (PRReadFN)_PR_InvalidInt,
   1291    (PRWriteFN)_PR_InvalidInt,
   1292    (PRAvailableFN)_PR_InvalidInt,
   1293    (PRAvailable64FN)_PR_InvalidInt64,
   1294    (PRFsyncFN)_PR_InvalidStatus,
   1295    (PRSeekFN)_PR_InvalidInt,
   1296    (PRSeek64FN)_PR_InvalidInt64,
   1297    (PRFileInfoFN)_PR_InvalidStatus,
   1298    (PRFileInfo64FN)_PR_InvalidStatus,
   1299    (PRWritevFN)_PR_InvalidInt,
   1300    (PRConnectFN)_PR_InvalidStatus,
   1301    (PRAcceptFN)_PR_InvalidDesc,
   1302    (PRBindFN)_PR_InvalidStatus,
   1303    (PRListenFN)_PR_InvalidStatus,
   1304    (PRShutdownFN)_PR_InvalidStatus,
   1305    (PRRecvFN)_PR_InvalidInt,
   1306    (PRSendFN)_PR_InvalidInt,
   1307    (PRRecvfromFN)_PR_InvalidInt,
   1308    (PRSendtoFN)_PR_InvalidInt,
   1309    SocketPoll,
   1310    (PRAcceptreadFN)_PR_InvalidInt,
   1311    (PRTransmitfileFN)_PR_InvalidInt,
   1312    (PRGetsocknameFN)_PR_InvalidStatus,
   1313    (PRGetpeernameFN)_PR_InvalidStatus,
   1314    (PRReservedFN)_PR_InvalidInt,
   1315    (PRReservedFN)_PR_InvalidInt,
   1316    (PRGetsocketoptionFN)_PR_InvalidStatus,
   1317    (PRSetsocketoptionFN)_PR_InvalidStatus,
   1318    (PRSendfileFN)_PR_InvalidInt,
   1319    (PRConnectcontinueFN)_PR_InvalidStatus,
   1320    (PRReservedFN)_PR_InvalidInt,
   1321    (PRReservedFN)_PR_InvalidInt,
   1322    (PRReservedFN)_PR_InvalidInt,
   1323    (PRReservedFN)_PR_InvalidInt};
   1324 
   1325 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods() { return &tcpMethods; }
   1326 
   1327 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() { return &udpMethods; }
   1328 
   1329 static const PRIOMethods* PR_GetSocketPollFdMethods() {
   1330  return &socketpollfdMethods;
   1331 } /* PR_GetSocketPollFdMethods */
   1332 
   1333 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
   1334 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd);
   1335 
   1336 #  if defined(_PR_INET6_PROBE)
   1337 
   1338 extern PRBool _pr_ipv6_is_present(void);
   1339 
   1340 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() {
   1341  PROsfd osfd;
   1342 
   1343  osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
   1344  if (osfd != -1) {
   1345    _PR_MD_CLOSE_SOCKET(osfd);
   1346    return PR_TRUE;
   1347  }
   1348  return PR_FALSE;
   1349 }
   1350 #  endif /* _PR_INET6_PROBE */
   1351 
   1352 #endif
   1353 
   1354 PR_IMPLEMENT(PRFileDesc*)
   1355 PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) {
   1356  PROsfd osfd;
   1357  PRFileDesc* fd;
   1358  PRInt32 tmp_domain = domain;
   1359 
   1360  if (!_pr_initialized) {
   1361    _PR_ImplicitInitialization();
   1362  }
   1363  if (PR_AF_INET != domain && PR_AF_INET6 != domain
   1364 #if defined(XP_UNIX)
   1365      && PR_AF_LOCAL != domain
   1366 #endif
   1367  ) {
   1368    PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
   1369    return NULL;
   1370  }
   1371 
   1372 #if defined(_PR_INET6_PROBE)
   1373  if (PR_AF_INET6 == domain) {
   1374    domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
   1375  }
   1376 #elif defined(_PR_INET6)
   1377  if (PR_AF_INET6 == domain) {
   1378    domain = AF_INET6;
   1379  }
   1380 #else
   1381  if (PR_AF_INET6 == domain) {
   1382    domain = AF_INET;
   1383  }
   1384 #endif /* _PR_INET6 */
   1385  osfd = _PR_MD_SOCKET(domain, type, proto);
   1386  if (osfd == -1) {
   1387    return 0;
   1388  }
   1389  if (type == SOCK_STREAM) {
   1390    fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
   1391  } else {
   1392    fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
   1393  }
   1394  /*
   1395   * Make the sockets non-blocking
   1396   */
   1397  if (fd != NULL) {
   1398    _PR_MD_MAKE_NONBLOCK(fd);
   1399    _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
   1400 #ifdef _PR_NEED_SECRET_AF
   1401    fd->secret->af = domain;
   1402 #endif
   1403 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
   1404    /*
   1405     * For platforms with no support for IPv6
   1406     * create layered socket for IPv4-mapped IPv6 addresses
   1407     */
   1408    if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
   1409      if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
   1410        PR_Close(fd);
   1411        fd = NULL;
   1412      }
   1413    }
   1414 #endif
   1415  } else {
   1416    _PR_MD_CLOSE_SOCKET(osfd);
   1417  }
   1418 
   1419  return fd;
   1420 }
   1421 
   1422 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) {
   1423  PRInt32 domain = AF_INET;
   1424 
   1425  return PR_Socket(domain, SOCK_STREAM, 0);
   1426 }
   1427 
   1428 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) {
   1429  PRInt32 domain = AF_INET;
   1430 
   1431  return PR_Socket(domain, SOCK_DGRAM, 0);
   1432 }
   1433 
   1434 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) {
   1435  return PR_Socket(af, SOCK_STREAM, 0);
   1436 }
   1437 
   1438 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) {
   1439  return PR_Socket(af, SOCK_DGRAM, 0);
   1440 }
   1441 
   1442 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc* f[]) {
   1443 #ifdef XP_UNIX
   1444  PRInt32 rv, osfd[2];
   1445 
   1446  if (!_pr_initialized) {
   1447    _PR_ImplicitInitialization();
   1448  }
   1449 
   1450  rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
   1451  if (rv == -1) {
   1452    return PR_FAILURE;
   1453  }
   1454 
   1455  f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
   1456  if (!f[0]) {
   1457    _PR_MD_CLOSE_SOCKET(osfd[0]);
   1458    _PR_MD_CLOSE_SOCKET(osfd[1]);
   1459    /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1460    return PR_FAILURE;
   1461  }
   1462  f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
   1463  if (!f[1]) {
   1464    PR_Close(f[0]);
   1465    _PR_MD_CLOSE_SOCKET(osfd[1]);
   1466    /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1467    return PR_FAILURE;
   1468  }
   1469  _PR_MD_MAKE_NONBLOCK(f[0]);
   1470  _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
   1471  _PR_MD_MAKE_NONBLOCK(f[1]);
   1472  _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
   1473  return PR_SUCCESS;
   1474 #elif defined(WINNT)
   1475  /*
   1476   * A socket pair is often used for interprocess communication,
   1477   * so we need to make sure neither socket is associated with
   1478   * the I/O completion port; otherwise it can't be used by a
   1479   * child process.
   1480   *
   1481   * The default implementation below cannot be used for NT
   1482   * because PR_Accept would have associated the I/O completion
   1483   * port with the listening and accepted sockets.
   1484   */
   1485  SOCKET listenSock;
   1486  SOCKET osfd[2];
   1487  struct sockaddr_in selfAddr, peerAddr;
   1488  int addrLen;
   1489 
   1490  if (!_pr_initialized) {
   1491    _PR_ImplicitInitialization();
   1492  }
   1493 
   1494  osfd[0] = osfd[1] = INVALID_SOCKET;
   1495  listenSock = socket(AF_INET, SOCK_STREAM, 0);
   1496  if (listenSock == INVALID_SOCKET) {
   1497    goto failed;
   1498  }
   1499  selfAddr.sin_family = AF_INET;
   1500  selfAddr.sin_port = 0;
   1501  selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
   1502  addrLen = sizeof(selfAddr);
   1503  if (bind(listenSock, (struct sockaddr*)&selfAddr, addrLen) == SOCKET_ERROR) {
   1504    goto failed;
   1505  }
   1506  if (getsockname(listenSock, (struct sockaddr*)&selfAddr, &addrLen) ==
   1507      SOCKET_ERROR) {
   1508    goto failed;
   1509  }
   1510  if (listen(listenSock, 5) == SOCKET_ERROR) {
   1511    goto failed;
   1512  }
   1513  osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
   1514  if (osfd[0] == INVALID_SOCKET) {
   1515    goto failed;
   1516  }
   1517  selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   1518 
   1519  /*
   1520   * Only a thread is used to do the connect and accept.
   1521   * I am relying on the fact that connect returns
   1522   * successfully as soon as the connect request is put
   1523   * into the listen queue (but before accept is called).
   1524   * This is the behavior of the BSD socket code.  If
   1525   * connect does not return until accept is called, we
   1526   * will need to create another thread to call connect.
   1527   */
   1528  if (connect(osfd[0], (struct sockaddr*)&selfAddr, addrLen) == SOCKET_ERROR) {
   1529    goto failed;
   1530  }
   1531  /*
   1532   * A malicious local process may connect to the listening
   1533   * socket, so we need to verify that the accepted connection
   1534   * is made from our own socket osfd[0].
   1535   */
   1536  if (getsockname(osfd[0], (struct sockaddr*)&selfAddr, &addrLen) ==
   1537      SOCKET_ERROR) {
   1538    goto failed;
   1539  }
   1540  osfd[1] = accept(listenSock, (struct sockaddr*)&peerAddr, &addrLen);
   1541  if (osfd[1] == INVALID_SOCKET) {
   1542    goto failed;
   1543  }
   1544  if (peerAddr.sin_port != selfAddr.sin_port) {
   1545    /* the connection we accepted is not from osfd[0] */
   1546    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   1547    goto failed;
   1548  }
   1549  closesocket(listenSock);
   1550 
   1551  f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
   1552  if (!f[0]) {
   1553    closesocket(osfd[0]);
   1554    closesocket(osfd[1]);
   1555    /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1556    return PR_FAILURE;
   1557  }
   1558  f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
   1559  if (!f[1]) {
   1560    PR_Close(f[0]);
   1561    closesocket(osfd[1]);
   1562    /* PR_AllocFileDesc() has invoked PR_SetError(). */
   1563    return PR_FAILURE;
   1564  }
   1565  _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
   1566  _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
   1567  return PR_SUCCESS;
   1568 
   1569 failed:
   1570  if (listenSock != INVALID_SOCKET) {
   1571    closesocket(listenSock);
   1572  }
   1573  if (osfd[0] != INVALID_SOCKET) {
   1574    closesocket(osfd[0]);
   1575  }
   1576  if (osfd[1] != INVALID_SOCKET) {
   1577    closesocket(osfd[1]);
   1578  }
   1579  return PR_FAILURE;
   1580 #else /* not Unix or NT */
   1581  /*
   1582   * default implementation
   1583   */
   1584  PRFileDesc* listenSock;
   1585  PRNetAddr selfAddr, peerAddr;
   1586  PRUint16 port;
   1587 
   1588  f[0] = f[1] = NULL;
   1589  listenSock = PR_NewTCPSocket();
   1590  if (listenSock == NULL) {
   1591    goto failed;
   1592  }
   1593  PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
   1594  if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
   1595    goto failed;
   1596  }
   1597  if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
   1598    goto failed;
   1599  }
   1600  port = ntohs(selfAddr.inet.port);
   1601  if (PR_Listen(listenSock, 5) == PR_FAILURE) {
   1602    goto failed;
   1603  }
   1604  f[0] = PR_NewTCPSocket();
   1605  if (f[0] == NULL) {
   1606    goto failed;
   1607  }
   1608 #  ifdef _PR_CONNECT_DOES_NOT_BIND
   1609  /*
   1610   * If connect does not implicitly bind the socket (e.g., on
   1611   * BeOS), we have to bind the socket so that we can get its
   1612   * port with getsockname later.
   1613   */
   1614  PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
   1615  if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
   1616    goto failed;
   1617  }
   1618 #  endif
   1619  PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
   1620 
   1621  /*
   1622   * Only a thread is used to do the connect and accept.
   1623   * I am relying on the fact that PR_Connect returns
   1624   * successfully as soon as the connect request is put
   1625   * into the listen queue (but before PR_Accept is called).
   1626   * This is the behavior of the BSD socket code.  If
   1627   * connect does not return until accept is called, we
   1628   * will need to create another thread to call connect.
   1629   */
   1630  if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
   1631    goto failed;
   1632  }
   1633  /*
   1634   * A malicious local process may connect to the listening
   1635   * socket, so we need to verify that the accepted connection
   1636   * is made from our own socket f[0].
   1637   */
   1638  if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
   1639    goto failed;
   1640  }
   1641  f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
   1642  if (f[1] == NULL) {
   1643    goto failed;
   1644  }
   1645  if (peerAddr.inet.port != selfAddr.inet.port) {
   1646    /* the connection we accepted is not from f[0] */
   1647    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   1648    goto failed;
   1649  }
   1650  PR_Close(listenSock);
   1651  return PR_SUCCESS;
   1652 
   1653 failed:
   1654  if (listenSock) {
   1655    PR_Close(listenSock);
   1656  }
   1657  if (f[0]) {
   1658    PR_Close(f[0]);
   1659  }
   1660  if (f[1]) {
   1661    PR_Close(f[1]);
   1662  }
   1663  return PR_FAILURE;
   1664 #endif
   1665 }
   1666 
   1667 PR_IMPLEMENT(PROsfd)
   1668 PR_FileDesc2NativeHandle(PRFileDesc* fd) {
   1669  if (fd) {
   1670    fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
   1671  }
   1672  if (!fd) {
   1673    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1674    return -1;
   1675  }
   1676  return fd->secret->md.osfd;
   1677 }
   1678 
   1679 PR_IMPLEMENT(void)
   1680 PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PROsfd handle) {
   1681  if (fd) {
   1682    fd->secret->md.osfd = handle;
   1683  }
   1684 }
   1685 
   1686 /*
   1687 ** Select compatibility
   1688 **
   1689 */
   1690 
   1691 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set* set) {
   1692  memset(set, 0, sizeof(PR_fd_set));
   1693 }
   1694 
   1695 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc* fh, PR_fd_set* set) {
   1696  PR_ASSERT(set->hsize < PR_MAX_SELECT_DESC);
   1697 
   1698  set->harray[set->hsize++] = fh;
   1699 }
   1700 
   1701 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc* fh, PR_fd_set* set) {
   1702  PRUint32 index, index2;
   1703 
   1704  for (index = 0; index < set->hsize; index++)
   1705    if (set->harray[index] == fh) {
   1706      for (index2 = index; index2 < (set->hsize - 1); index2++) {
   1707        set->harray[index2] = set->harray[index2 + 1];
   1708      }
   1709      set->hsize--;
   1710      break;
   1711    }
   1712 }
   1713 
   1714 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) {
   1715  PRUint32 index;
   1716  for (index = 0; index < set->hsize; index++)
   1717    if (set->harray[index] == fh) {
   1718      return 1;
   1719    }
   1720  return 0;
   1721 }
   1722 
   1723 PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set* set) {
   1724  PR_ASSERT(set->nsize < PR_MAX_SELECT_DESC);
   1725 
   1726  set->narray[set->nsize++] = fd;
   1727 }
   1728 
   1729 PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set* set) {
   1730  PRUint32 index, index2;
   1731 
   1732  for (index = 0; index < set->nsize; index++)
   1733    if (set->narray[index] == fd) {
   1734      for (index2 = index; index2 < (set->nsize - 1); index2++) {
   1735        set->narray[index2] = set->narray[index2 + 1];
   1736      }
   1737      set->nsize--;
   1738      break;
   1739    }
   1740 }
   1741 
   1742 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set* set) {
   1743  PRUint32 index;
   1744  for (index = 0; index < set->nsize; index++)
   1745    if (set->narray[index] == fd) {
   1746      return 1;
   1747    }
   1748  return 0;
   1749 }
   1750 
   1751 #if !defined(NEED_SELECT)
   1752 #  include "obsolete/probslet.h"
   1753 
   1754 #  define PD_INCR 20
   1755 
   1756 static PRPollDesc* _pr_setfd(PR_fd_set* set, PRInt16 flags,
   1757                             PRPollDesc* polldesc) {
   1758  PRUintn fsidx, pdidx;
   1759  PRPollDesc* poll = polldesc;
   1760 
   1761  if (NULL == set) {
   1762    return poll;
   1763  }
   1764 
   1765  /* First set the pr file handle osfds */
   1766  for (fsidx = 0; fsidx < set->hsize; fsidx++) {
   1767    for (pdidx = 0; 1; pdidx++) {
   1768      if ((PRFileDesc*)-1 == poll[pdidx].fd) {
   1769        /* our vector is full - extend and condition it */
   1770        poll = (PRPollDesc*)PR_Realloc(
   1771            poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
   1772        if (NULL == poll) {
   1773          goto out_of_memory;
   1774        }
   1775        memset(poll + pdidx * sizeof(PRPollDesc), 0,
   1776               PD_INCR * sizeof(PRPollDesc));
   1777        poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
   1778      }
   1779      if ((NULL == poll[pdidx].fd) || (poll[pdidx].fd == set->harray[fsidx])) {
   1780        /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
   1781        /* either empty or prevously defined */
   1782        poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */
   1783        poll[pdidx].in_flags |= flags;       /* possibly redundant */
   1784        break;
   1785      }
   1786    }
   1787  }
   1788 
   1789 #  if 0
   1790    /* Second set the native osfds */
   1791    for (fsidx = 0; fsidx < set->nsize; fsidx++)
   1792    {
   1793        for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
   1794        {
   1795            if ((PRFileDesc*)-1 == poll[pdidx].fd)
   1796            {
   1797                /* our vector is full - extend and condition it */
   1798                poll = PR_Realloc(
   1799                           poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
   1800                if (NULL == poll) {
   1801                    goto out_of_memory;
   1802                }
   1803                memset(
   1804                    poll + pdidx * sizeof(PRPollDesc),
   1805                    0, PD_INCR * sizeof(PRPollDesc));
   1806                poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
   1807            }
   1808            if ((NULL == poll[pdidx].fd)
   1809                || (poll[pdidx].fd == set->narray[fsidx]))
   1810            {
   1811                /* either empty or prevously defined */
   1812                poll[pdidx].fd = set->narray[fsidx];
   1813                PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
   1814                poll[pdidx].in_flags |= flags;
   1815                break;
   1816            }
   1817        }
   1818    }
   1819 #  endif /* 0 */
   1820 
   1821  return poll;
   1822 
   1823 out_of_memory:
   1824  if (NULL != polldesc) {
   1825    PR_DELETE(polldesc);
   1826  }
   1827  return NULL;
   1828 } /* _pr_setfd */
   1829 
   1830 #endif /* !defined(NEED_SELECT) */
   1831 
   1832 PR_IMPLEMENT(PRInt32)
   1833 PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex,
   1834          PRIntervalTime timeout) {
   1835 #if !defined(NEED_SELECT)
   1836  PRInt32 npds = 0;
   1837  /*
   1838  ** Find out how many fds are represented in the three lists.
   1839  ** Then allocate a polling descriptor for the logical union
   1840  ** (there can't be any overlapping) and call PR_Poll().
   1841  */
   1842 
   1843  PRPollDesc *copy, *poll;
   1844 
   1845  static PRBool warning = PR_TRUE;
   1846  if (warning) {
   1847    warning = _PR_Obsolete("PR_Select()", "PR_Poll()");
   1848  }
   1849 
   1850  /* try to get an initial guesss at how much space we need */
   1851  npds = 0;
   1852  if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0)) {
   1853    npds = pr_rd->hsize + pr_rd->nsize;
   1854  }
   1855  if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0)) {
   1856    npds = pr_wr->hsize + pr_wr->nsize;
   1857  }
   1858  if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0)) {
   1859    npds = pr_ex->hsize + pr_ex->nsize;
   1860  }
   1861 
   1862  if (0 == npds) {
   1863    PR_Sleep(timeout);
   1864    return 0;
   1865  }
   1866 
   1867  copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
   1868  if (NULL == poll) {
   1869    goto out_of_memory;
   1870  }
   1871  poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
   1872 
   1873  poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
   1874  if (NULL == poll) {
   1875    goto out_of_memory;
   1876  }
   1877  poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
   1878  if (NULL == poll) {
   1879    goto out_of_memory;
   1880  }
   1881  poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
   1882  if (NULL == poll) {
   1883    goto out_of_memory;
   1884  }
   1885  unused = 0;
   1886  while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) {
   1887    ++unused;
   1888  }
   1889 
   1890  PR_ASSERT(unused > 0);
   1891  npds = PR_Poll(poll, unused, timeout);
   1892 
   1893  if (npds > 0) {
   1894    /* Copy the results back into the fd sets */
   1895    if (NULL != pr_rd) {
   1896      pr_rd->nsize = pr_rd->hsize = 0;
   1897    }
   1898    if (NULL != pr_wr) {
   1899      pr_wr->nsize = pr_wr->hsize = 0;
   1900    }
   1901    if (NULL != pr_ex) {
   1902      pr_ex->nsize = pr_ex->hsize = 0;
   1903    }
   1904    for (copy = &poll[unused - 1]; copy >= poll; --copy) {
   1905      if (copy->out_flags & PR_POLL_NVAL) {
   1906        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1907        npds = -1;
   1908        break;
   1909      }
   1910      if (copy->out_flags & PR_POLL_READ)
   1911        if (NULL != pr_rd) {
   1912          pr_rd->harray[pr_rd->hsize++] = copy->fd;
   1913        }
   1914      if (copy->out_flags & PR_POLL_WRITE)
   1915        if (NULL != pr_wr) {
   1916          pr_wr->harray[pr_wr->hsize++] = copy->fd;
   1917        }
   1918      if (copy->out_flags & PR_POLL_EXCEPT)
   1919        if (NULL != pr_ex) {
   1920          pr_ex->harray[pr_ex->hsize++] = copy->fd;
   1921        }
   1922    }
   1923  }
   1924  PR_DELETE(poll);
   1925 
   1926  return npds;
   1927 out_of_memory:
   1928  PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1929  return -1;
   1930 
   1931 #endif /* !defined(NEED_SELECT) */
   1932 }