tor-browser

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

w95sock.c (21146B)


      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 /* Win95 Sockets module
      7 *
      8 */
      9 
     10 #if defined(_WIN64)
     11 #  include <winsock2.h>
     12 #endif
     13 #include "primpl.h"
     14 
     15 #define READ_FD 1
     16 #define WRITE_FD 2
     17 #define CONNECT_FD 3
     18 
     19 static PRInt32 socket_io_wait(PROsfd osfd, PRInt32 fd_type,
     20                              PRIntervalTime timeout);
     21 
     22 /* --- SOCKET IO --------------------------------------------------------- */
     23 
     24 static PRBool socketFixInet6RcvBuf = PR_FALSE;
     25 
     26 void _PR_MD_InitSockets(void) {
     27  OSVERSIONINFO osvi;
     28 
     29  memset(&osvi, 0, sizeof(osvi));
     30  osvi.dwOSVersionInfoSize = sizeof(osvi);
     31  GetVersionEx(&osvi);
     32 
     33  if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
     34    /* if Windows XP (32-bit) */
     35    socketFixInet6RcvBuf = PR_TRUE;
     36  }
     37 }
     38 
     39 void _PR_MD_CleanupSockets(void) { socketFixInet6RcvBuf = PR_FALSE; }
     40 
     41 PROsfd _PR_MD_SOCKET(int af, int type, int flags) {
     42  SOCKET sock;
     43  u_long one = 1;
     44 
     45  sock = socket(af, type, flags);
     46 
     47  if (sock == INVALID_SOCKET) {
     48    _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
     49    return (PROsfd)sock;
     50  }
     51 
     52  /*
     53  ** Make the socket Non-Blocking
     54  */
     55  if (ioctlsocket(sock, FIONBIO, &one) != 0) {
     56    PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
     57    closesocket(sock);
     58    return -1;
     59  }
     60 
     61  if (af == AF_INET6 && socketFixInet6RcvBuf) {
     62    int bufsize;
     63    int len = sizeof(bufsize);
     64    int rv;
     65 
     66    /* Windows XP 32-bit returns an error on getpeername() for AF_INET6
     67     * sockets if the receive buffer size is greater than 65535 before
     68     * the connection is initiated. The default receive buffer size may
     69     * be 128000 so fix it here to always be <= 65535. See bug 513659
     70     * and IBM DB2 support technote "Receive/Send IPv6 Socket Size
     71     * Problem in Windows XP SP2 & SP3".
     72     */
     73    rv = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, &len);
     74    if (rv == 0 && bufsize > 65535) {
     75      bufsize = 65535;
     76      setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, len);
     77    }
     78  }
     79 
     80  return (PROsfd)sock;
     81 }
     82 
     83 /*
     84 ** _MD_CloseSocket() -- Close a socket
     85 **
     86 */
     87 PRInt32 _MD_CloseSocket(PROsfd osfd) {
     88  PRInt32 rv;
     89 
     90  rv = closesocket((SOCKET)osfd);
     91  if (rv < 0) {
     92    _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
     93  }
     94 
     95  return rv;
     96 }
     97 
     98 PRInt32 _MD_SocketAvailable(PRFileDesc* fd) {
     99  PRInt32 result;
    100 
    101  if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
    102    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
    103    return -1;
    104  }
    105  return result;
    106 }
    107 
    108 PROsfd _MD_Accept(PRFileDesc* fd, PRNetAddr* raddr, PRUint32* rlen,
    109                  PRIntervalTime timeout) {
    110  PROsfd osfd = fd->secret->md.osfd;
    111  SOCKET sock;
    112  PRInt32 rv, err;
    113 
    114  while ((sock = accept(osfd, (struct sockaddr*)raddr, rlen)) == -1) {
    115    err = WSAGetLastError();
    116    if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) {
    117      if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
    118        break;
    119      }
    120    } else {
    121      _PR_MD_MAP_ACCEPT_ERROR(err);
    122      break;
    123    }
    124  }
    125  return (sock);
    126 } /* end _MD_accept() */
    127 
    128 PRInt32 _PR_MD_CONNECT(PRFileDesc* fd, const PRNetAddr* addr, PRUint32 addrlen,
    129                       PRIntervalTime timeout) {
    130  PROsfd osfd = fd->secret->md.osfd;
    131  PRInt32 rv;
    132  int err;
    133 
    134  if ((rv = connect(osfd, (struct sockaddr*)addr, addrlen)) == -1) {
    135    err = WSAGetLastError();
    136    if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK)) {
    137      rv = socket_io_wait(osfd, CONNECT_FD, timeout);
    138      if (rv < 0) {
    139        return (-1);
    140      } else {
    141        PR_ASSERT(rv > 0);
    142        /* it's connected */
    143        return (0);
    144      }
    145    }
    146    _PR_MD_MAP_CONNECT_ERROR(err);
    147  }
    148  return rv;
    149 }
    150 
    151 PRInt32 _PR_MD_BIND(PRFileDesc* fd, const PRNetAddr* addr, PRUint32 addrlen) {
    152  PRInt32 rv;
    153 
    154  rv =
    155      bind(fd->secret->md.osfd, (const struct sockaddr*)&(addr->inet), addrlen);
    156 
    157  if (rv == SOCKET_ERROR) {
    158    _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
    159    return -1;
    160  }
    161 
    162  return 0;
    163 }
    164 
    165 PRInt32 _PR_MD_LISTEN(PRFileDesc* fd, PRIntn backlog) {
    166  PRInt32 rv;
    167 
    168  rv = listen(fd->secret->md.osfd, backlog);
    169 
    170  if (rv == SOCKET_ERROR) {
    171    _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
    172    return -1;
    173  }
    174 
    175  return 0;
    176 }
    177 
    178 PRInt32 _PR_MD_RECV(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
    179                    PRIntervalTime timeout) {
    180  PROsfd osfd = fd->secret->md.osfd;
    181  PRInt32 rv, err;
    182  int osflags;
    183 
    184  if (0 == flags) {
    185    osflags = 0;
    186  } else {
    187    PR_ASSERT(PR_MSG_PEEK == flags);
    188    osflags = MSG_PEEK;
    189  }
    190  while ((rv = recv(osfd, buf, amount, osflags)) == -1) {
    191    if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) &&
    192        (!fd->secret->nonblocking)) {
    193      rv = socket_io_wait(osfd, READ_FD, timeout);
    194      if (rv < 0) {
    195        return -1;
    196      }
    197    } else {
    198      _PR_MD_MAP_RECV_ERROR(err);
    199      break;
    200    }
    201  } /* end while() */
    202  return (rv);
    203 }
    204 
    205 PRInt32 _PR_MD_SEND(PRFileDesc* fd, const void* buf, PRInt32 amount,
    206                    PRIntn flags, PRIntervalTime timeout) {
    207  PROsfd osfd = fd->secret->md.osfd;
    208  PRInt32 rv, err;
    209  PRInt32 bytesSent = 0;
    210 
    211  while (bytesSent < amount) {
    212    while ((rv = send(osfd, buf, amount, 0)) == -1) {
    213      if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) &&
    214          (!fd->secret->nonblocking)) {
    215        rv = socket_io_wait(osfd, WRITE_FD, timeout);
    216        if (rv < 0) {
    217          return -1;
    218        }
    219      } else {
    220        _PR_MD_MAP_SEND_ERROR(err);
    221        return -1;
    222      }
    223    }
    224    bytesSent += rv;
    225    if (fd->secret->nonblocking) {
    226      break;
    227    }
    228    if (bytesSent < amount) {
    229      rv = socket_io_wait(osfd, WRITE_FD, timeout);
    230      if (rv < 0) {
    231        return -1;
    232      }
    233    }
    234  }
    235  return bytesSent;
    236 }
    237 
    238 PRInt32 _PR_MD_SENDTO(PRFileDesc* fd, const void* buf, PRInt32 amount,
    239                      PRIntn flags, const PRNetAddr* addr, PRUint32 addrlen,
    240                      PRIntervalTime timeout) {
    241  PROsfd osfd = fd->secret->md.osfd;
    242  PRInt32 rv, err;
    243  PRInt32 bytesSent = 0;
    244 
    245  do {
    246    while ((rv = sendto(osfd, buf, amount, 0, (struct sockaddr*)addr,
    247                        addrlen)) == -1) {
    248      if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) &&
    249          (!fd->secret->nonblocking)) {
    250        rv = socket_io_wait(osfd, WRITE_FD, timeout);
    251        if (rv < 0) {
    252          return -1;
    253        }
    254      } else {
    255        _PR_MD_MAP_SENDTO_ERROR(err);
    256        return -1;
    257      }
    258    }
    259    bytesSent += rv;
    260    if (fd->secret->nonblocking) {
    261      break;
    262    }
    263    if (bytesSent < amount) {
    264      rv = socket_io_wait(osfd, WRITE_FD, timeout);
    265      if (rv < 0) {
    266        return -1;
    267      }
    268    }
    269  } while (bytesSent < amount);
    270  return bytesSent;
    271 }
    272 
    273 #if defined(_WIN64)
    274 
    275 static PRCallOnceType _pr_has_connectex_once;
    276 typedef BOOL(PASCAL FAR* _pr_win_connectex_ptr)(
    277    _In_ SOCKET s, _In_reads_bytes_(namelen) const struct sockaddr FAR* name,
    278    _In_ int namelen, _In_reads_bytes_opt_(dwSendDataLength) PVOID lpSendBuffer,
    279    _In_ DWORD dwSendDataLength, _Out_ LPDWORD lpdwBytesSent,
    280    _Inout_ LPOVERLAPPED lpOverlapped);
    281 
    282 #  ifndef WSAID_CONNECTEX
    283 #    define WSAID_CONNECTEX                              \
    284      {                                                  \
    285        0x25a207b9, 0xddf3, 0x4660, {                    \
    286          0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e \
    287        }                                                \
    288      }
    289 #  endif
    290 #  ifndef SIO_GET_EXTENSION_FUNCTION_POINTER
    291 #    define SIO_GET_EXTENSION_FUNCTION_POINTER 0xC8000006
    292 #  endif
    293 #  ifndef TCP_FASTOPEN
    294 #    define TCP_FASTOPEN 15
    295 #  endif
    296 
    297 #  ifndef SO_UPDATE_CONNECT_CONTEXT
    298 #    define SO_UPDATE_CONNECT_CONTEXT 0x7010
    299 #  endif
    300 
    301 static _pr_win_connectex_ptr _pr_win_connectex = NULL;
    302 
    303 static PRStatus PR_CALLBACK _pr_set_connectex(void) {
    304  _pr_win_connectex = NULL;
    305  SOCKET sock;
    306  PRInt32 dwBytes;
    307  int rc;
    308 
    309  /* Dummy socket needed for WSAIoctl */
    310  sock = socket(AF_INET, SOCK_STREAM, 0);
    311  if (sock == INVALID_SOCKET) {
    312    return PR_SUCCESS;
    313  }
    314 
    315  GUID guid = WSAID_CONNECTEX;
    316  rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
    317                &_pr_win_connectex, sizeof(_pr_win_connectex), &dwBytes, NULL,
    318                NULL);
    319  if (rc != 0) {
    320    _pr_win_connectex = NULL;
    321    return PR_SUCCESS;
    322  }
    323 
    324  rc = closesocket(sock);
    325  return PR_SUCCESS;
    326 }
    327 
    328 PRInt32 _PR_MD_TCPSENDTO(PRFileDesc* fd, const void* buf, PRInt32 amount,
    329                         PRIntn flags, const PRNetAddr* addr, PRUint32 addrlen,
    330                         PRIntervalTime timeout) {
    331  if (!_fd_waiting_for_overlapped_done_lock) {
    332    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    333    return PR_FAILURE;
    334  }
    335 
    336  if (PR_CallOnce(&_pr_has_connectex_once, _pr_set_connectex) != PR_SUCCESS) {
    337    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    338    return PR_FAILURE;
    339  }
    340 
    341  if (_pr_win_connectex == NULL) {
    342    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    343    return PR_FAILURE;
    344  }
    345 
    346  PROsfd osfd = fd->secret->md.osfd;
    347  PRInt32 rv, err;
    348  PRInt32 bytesSent = 0;
    349  DWORD rvSent;
    350 
    351  BOOL option = 1;
    352  rv = setsockopt((SOCKET)osfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&option,
    353                  sizeof(option));
    354  if (rv != 0) {
    355    err = WSAGetLastError();
    356    PR_LOG(_pr_io_lm, PR_LOG_MIN,
    357           ("_PR_MD_TCPSENDTO error set opt TCP_FASTOPEN failed %d\n", err));
    358    if (err == WSAENOPROTOOPT) {
    359      PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    360    } else {
    361      _PR_MD_MAP_SETSOCKOPT_ERROR(err);
    362    }
    363    return -1;
    364  }
    365 
    366  /* ConnectEx requires the socket to be initially bound. We will use
    367   * INADDR_ANY. */
    368  PRNetAddr bindAddr;
    369  memset(&bindAddr, 0, sizeof(bindAddr));
    370  bindAddr.raw.family = addr->raw.family;
    371 
    372  rv = bind((SOCKET)osfd, (const struct sockaddr*)&(bindAddr.inet),
    373            PR_NETADDR_SIZE(&bindAddr));
    374  if (rv != 0) {
    375    err = WSAGetLastError();
    376    PR_LOG(_pr_io_lm, PR_LOG_MIN,
    377           ("_PR_MD_TCPSENDTO error bind failed %d\n", err));
    378    _PR_MD_MAP_SETSOCKOPT_ERROR(err);
    379    return -1;
    380  }
    381 
    382  PR_LOG(_pr_io_lm, PR_LOG_MIN,
    383         ("_PR_MD_TCPSENDTO calling _pr_win_connectex  %d %p\n", amount,
    384          (char*)buf));
    385 
    386  rvSent = 0;
    387  memset(&fd->secret->ol, 0, sizeof(fd->secret->ol));
    388  /* ConnectEx return TRUE on a success and FALSE on an error. */
    389  if (_pr_win_connectex((SOCKET)osfd, (struct sockaddr*)addr, addrlen, buf,
    390                        amount, &rvSent, &fd->secret->ol) == TRUE) {
    391    /* When ConnectEx is used, all previously set socket options and
    392     * property are not enabled and to enable them
    393     * SO_UPDATE_CONNECT_CONTEXT option need to be set. */
    394    rv = setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL,
    395                    0);
    396    if (rv != 0) {
    397      err = WSAGetLastError();
    398      PR_LOG(_pr_io_lm, PR_LOG_MIN,
    399             ("_PR_MD_TCPSENDTO setting SO_UPDATE_CONNECT_CONTEXT failed %d\n",
    400              err));
    401      _PR_MD_MAP_SETSOCKOPT_ERROR(err);
    402      return -1;
    403    }
    404    /* We imitate Linux here. SendTo will return number of bytes send but
    405     * it can not return connection success at the same time, so we return
    406     * number of bytes send and "connection success" will be return on the
    407     * connectcontinue. */
    408    fd->secret->alreadyConnected = PR_TRUE;
    409    return rvSent;
    410  } else {
    411    err = WSAGetLastError();
    412    PR_LOG(_pr_io_lm, PR_LOG_MIN,
    413           ("_PR_MD_TCPSENDTO error _pr_win_connectex failed %d\n", err));
    414    if (err != ERROR_IO_PENDING) {
    415      _PR_MD_MAP_CONNECT_ERROR(err);
    416      return -1;
    417    } else if (fd->secret->nonblocking) {
    418      /* Remember that overlapped structure is set. We will need to get
    419       * the final result of ConnectEx call. */
    420      fd->secret->overlappedActive = PR_TRUE;
    421 
    422      /* ConnectEx will copy supplied data to a internal buffer and send
    423       * them during Fast Open or after connect. Therefore we can assumed
    424       * this data already send. */
    425      if (amount > 0) {
    426        return amount;
    427      }
    428 
    429      _PR_MD_MAP_CONNECT_ERROR(WSAEWOULDBLOCK);
    430      return -1;
    431    }
    432    // err is ERROR_IO_PENDING and socket is blocking, so query
    433    // GetOverlappedResult.
    434    err = ERROR_IO_INCOMPLETE;
    435    while (err == ERROR_IO_INCOMPLETE) {
    436      rv = socket_io_wait(osfd, WRITE_FD, timeout);
    437      if (rv < 0) {
    438        return -1;
    439      }
    440      rv = GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE);
    441      if (rv == TRUE) {
    442        return rvSent;
    443      } else {
    444        err = WSAGetLastError();
    445        if (err != ERROR_IO_INCOMPLETE) {
    446          _PR_MD_MAP_CONNECT_ERROR(err);
    447          return -1;
    448        }
    449      }
    450    }
    451  }
    452  return -1;
    453 }
    454 #endif
    455 
    456 PRInt32 _PR_MD_RECVFROM(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
    457                        PRNetAddr* addr, PRUint32* addrlen,
    458                        PRIntervalTime timeout) {
    459  PROsfd osfd = fd->secret->md.osfd;
    460  PRInt32 rv, err;
    461 
    462  while ((rv = recvfrom(osfd, buf, amount, 0, (struct sockaddr*)addr,
    463                        addrlen)) == -1) {
    464    if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) &&
    465        (!fd->secret->nonblocking)) {
    466      rv = socket_io_wait(osfd, READ_FD, timeout);
    467      if (rv < 0) {
    468        return -1;
    469      }
    470    } else {
    471      _PR_MD_MAP_RECVFROM_ERROR(err);
    472      break;
    473    }
    474  }
    475  return (rv);
    476 }
    477 
    478 PRInt32 _PR_MD_WRITEV(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_size,
    479                      PRIntervalTime timeout) {
    480  int index;
    481  int sent = 0;
    482  int rv;
    483 
    484  for (index = 0; index < iov_size; index++) {
    485    rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
    486    if (rv > 0) {
    487      sent += rv;
    488    }
    489    if (rv != iov[index].iov_len) {
    490      if (rv < 0) {
    491        if (fd->secret->nonblocking &&
    492            (PR_GetError() == PR_WOULD_BLOCK_ERROR) && (sent > 0)) {
    493          return sent;
    494        } else {
    495          return -1;
    496        }
    497      }
    498      /* Only a nonblocking socket can have partial sends */
    499      PR_ASSERT(fd->secret->nonblocking);
    500      return sent;
    501    }
    502  }
    503  return sent;
    504 }
    505 
    506 PRInt32 _PR_MD_SHUTDOWN(PRFileDesc* fd, PRIntn how) {
    507  PRInt32 rv;
    508 
    509  rv = shutdown(fd->secret->md.osfd, how);
    510  if (rv < 0) {
    511    _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
    512  }
    513  return rv;
    514 }
    515 
    516 PRStatus _PR_MD_GETSOCKNAME(PRFileDesc* fd, PRNetAddr* addr, PRUint32* len) {
    517  PRInt32 rv;
    518 
    519  rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr*)addr, len);
    520  if (rv == 0) {
    521    return PR_SUCCESS;
    522  } else {
    523    _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
    524    return PR_FAILURE;
    525  }
    526 }
    527 
    528 PRStatus _PR_MD_GETPEERNAME(PRFileDesc* fd, PRNetAddr* addr, PRUint32* len) {
    529  PRInt32 rv;
    530 
    531  rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr*)addr, len);
    532  if (rv == 0) {
    533    return PR_SUCCESS;
    534  } else {
    535    _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
    536    return PR_FAILURE;
    537  }
    538 }
    539 
    540 PRStatus _PR_MD_GETSOCKOPT(PRFileDesc* fd, PRInt32 level, PRInt32 optname,
    541                           char* optval, PRInt32* optlen) {
    542  PRInt32 rv;
    543 
    544  rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
    545  if (rv == 0) {
    546    return PR_SUCCESS;
    547  } else {
    548    _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
    549    return PR_FAILURE;
    550  }
    551 }
    552 
    553 PRStatus _PR_MD_SETSOCKOPT(PRFileDesc* fd, PRInt32 level, PRInt32 optname,
    554                           const char* optval, PRInt32 optlen) {
    555  PRInt32 rv;
    556 
    557  rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
    558  if (rv == 0) {
    559    return PR_SUCCESS;
    560  } else {
    561    _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
    562    return PR_FAILURE;
    563  }
    564 }
    565 
    566 void _MD_MakeNonblock(PRFileDesc* f) { return; /* do nothing */ }
    567 
    568 /*
    569 * socket_io_wait --
    570 *
    571 * Wait for socket i/o, periodically checking for interrupt.
    572 *
    573 * This function returns 1 on success.  On failure, it returns
    574 * -1 and sets the error codes.  It never returns 0.
    575 */
    576 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
    577 
    578 static PRInt32 socket_io_wait(PROsfd osfd, PRInt32 fd_type,
    579                              PRIntervalTime timeout) {
    580  PRInt32 rv = -1;
    581  struct timeval tv;
    582  PRThread* me = _PR_MD_CURRENT_THREAD();
    583  PRIntervalTime elapsed, remaining;
    584  PRBool wait_for_remaining;
    585  fd_set rd_wr, ex;
    586  int err, len;
    587 
    588  switch (timeout) {
    589    case PR_INTERVAL_NO_WAIT:
    590      PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
    591      break;
    592    case PR_INTERVAL_NO_TIMEOUT:
    593      /*
    594       * This is a special case of the 'default' case below.
    595       * Please see the comments there.
    596       */
    597      tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
    598      tv.tv_usec = 0;
    599      FD_ZERO(&rd_wr);
    600      FD_ZERO(&ex);
    601      do {
    602        FD_SET(osfd, &rd_wr);
    603        FD_SET(osfd, &ex);
    604        switch (fd_type) {
    605          case READ_FD:
    606            rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
    607            break;
    608          case WRITE_FD:
    609            rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
    610            break;
    611          case CONNECT_FD:
    612            rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
    613            break;
    614          default:
    615            PR_ASSERT(0);
    616            break;
    617        } /* end switch() */
    618        if (rv == -1) {
    619          _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
    620          break;
    621        }
    622        if (rv > 0 && fd_type == CONNECT_FD) {
    623          /*
    624           * Call Sleep(0) to work around a Winsock timing bug.
    625           */
    626          Sleep(0);
    627          if (FD_ISSET((SOCKET)osfd, &ex)) {
    628            len = sizeof(err);
    629            if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) ==
    630                SOCKET_ERROR) {
    631              _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
    632              return -1;
    633            }
    634            if (err != 0) {
    635              _PR_MD_MAP_CONNECT_ERROR(err);
    636            } else {
    637              PR_SetError(PR_UNKNOWN_ERROR, 0);
    638            }
    639            return -1;
    640          }
    641          if (FD_ISSET((SOCKET)osfd, &rd_wr)) {
    642            /* it's connected */
    643            return 1;
    644          }
    645          PR_ASSERT(0);
    646        }
    647        if (_PR_PENDING_INTERRUPT(me)) {
    648          me->flags &= ~_PR_INTERRUPT;
    649          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    650          rv = -1;
    651          break;
    652        }
    653      } while (rv == 0);
    654      break;
    655    default:
    656      remaining = timeout;
    657      FD_ZERO(&rd_wr);
    658      FD_ZERO(&ex);
    659      do {
    660        /*
    661         * We block in _MD_SELECT for at most
    662         * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
    663         * so that there is an upper limit on the delay
    664         * before the interrupt bit is checked.
    665         */
    666        wait_for_remaining = PR_TRUE;
    667        tv.tv_sec = PR_IntervalToSeconds(remaining);
    668        if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
    669          wait_for_remaining = PR_FALSE;
    670          tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
    671          tv.tv_usec = 0;
    672        } else {
    673          tv.tv_usec = PR_IntervalToMicroseconds(
    674              remaining - PR_SecondsToInterval(tv.tv_sec));
    675        }
    676        FD_SET(osfd, &rd_wr);
    677        FD_SET(osfd, &ex);
    678        switch (fd_type) {
    679          case READ_FD:
    680            rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
    681            break;
    682          case WRITE_FD:
    683            rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
    684            break;
    685          case CONNECT_FD:
    686            rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
    687            break;
    688          default:
    689            PR_ASSERT(0);
    690            break;
    691        } /* end switch() */
    692        if (rv == -1) {
    693          _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
    694          break;
    695        }
    696        if (rv > 0 && fd_type == CONNECT_FD) {
    697          /*
    698           * Call Sleep(0) to work around a Winsock timing bug.
    699           */
    700          Sleep(0);
    701          if (FD_ISSET((SOCKET)osfd, &ex)) {
    702            len = sizeof(err);
    703            if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) ==
    704                SOCKET_ERROR) {
    705              _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
    706              return -1;
    707            }
    708            if (err != 0) {
    709              _PR_MD_MAP_CONNECT_ERROR(err);
    710            } else {
    711              PR_SetError(PR_UNKNOWN_ERROR, 0);
    712            }
    713            return -1;
    714          }
    715          if (FD_ISSET((SOCKET)osfd, &rd_wr)) {
    716            /* it's connected */
    717            return 1;
    718          }
    719          PR_ASSERT(0);
    720        }
    721        if (_PR_PENDING_INTERRUPT(me)) {
    722          me->flags &= ~_PR_INTERRUPT;
    723          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    724          rv = -1;
    725          break;
    726        }
    727        /*
    728         * We loop again if _MD_SELECT timed out and the
    729         * timeout deadline has not passed yet.
    730         */
    731        if (rv == 0) {
    732          if (wait_for_remaining) {
    733            elapsed = remaining;
    734          } else {
    735            elapsed = PR_SecondsToInterval(tv.tv_sec) +
    736                      PR_MicrosecondsToInterval(tv.tv_usec);
    737          }
    738          if (elapsed >= remaining) {
    739            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
    740            rv = -1;
    741            break;
    742          } else {
    743            remaining = remaining - elapsed;
    744          }
    745        }
    746      } while (rv == 0);
    747      break;
    748  }
    749  return (rv);
    750 } /* end socket_io_wait() */