Back to index

lightning-sunbird  0.9+nobinonly
w95sock.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* Win95 Sockets module
00039  *
00040  */
00041 
00042 #include "primpl.h"
00043 
00044 #define READ_FD     1
00045 #define WRITE_FD    2
00046 #define CONNECT_FD  3
00047 
00048 static PRInt32 socket_io_wait(
00049     PRInt32 osfd, 
00050     PRInt32 fd_type,
00051     PRIntervalTime timeout);
00052 
00053 
00054 /* --- SOCKET IO --------------------------------------------------------- */
00055 
00056 /*
00057  * we only want to call WSAIoctl() on Vista and later
00058  * so don't pay for it at build time (and avoid including winsock2.h)
00059  */
00060 
00061 /* from ws2def.h */
00062 #define IOC_IN                      0x80000000      /* copy in parameters */
00063 #define IOC_VENDOR                  0x18000000
00064 #define _WSAIOW(x,y)                (IOC_IN|(x)|(y))
00065 /* from MSWSockDef.h */
00066 #define SIO_SET_COMPATIBILITY_MODE  _WSAIOW(IOC_VENDOR,300)
00067 
00068 typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
00069     WsaBehaviorAll = 0,
00070     WsaBehaviorReceiveBuffering,
00071     WsaBehaviorAutoTuning
00072 } WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
00073 
00074 /* from sdkddkver.h */
00075 #define NTDDI_LONGHORN                      0x06000000
00076 
00077 /* from winsock2.h */
00078 #define WSAEVENT                HANDLE
00079 
00080 #define WSAOVERLAPPED           OVERLAPPED
00081 typedef struct _OVERLAPPED *    LPWSAOVERLAPPED;
00082 
00083 typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
00084     IN DWORD dwError,
00085     IN DWORD cbTransferred,
00086     IN LPWSAOVERLAPPED lpOverlapped,
00087     IN DWORD dwFlags
00088 );
00089 
00090 typedef int (__stdcall * WSAIOCTLPROC) (
00091     SOCKET s,
00092     DWORD dwIoControlCode,
00093     LPVOID lpvInBuffer,
00094     DWORD cbInBuffer,
00095     LPVOID lpvOutBuffer,
00096     DWORD cbOutBuffer,
00097     LPDWORD lpcbBytesReturned,
00098     LPWSAOVERLAPPED lpOverlapped,
00099     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
00100 );
00101 
00102 typedef struct _WSA_COMPATIBILITY_MODE {
00103     WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId;
00104     ULONG TargetOsVersion;
00105 } WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE;
00106 
00107 static HMODULE libWinsock2 = NULL;
00108 static WSAIOCTLPROC wsaioctlProc = NULL;
00109 static PRBool socketSetCompatMode = PR_FALSE;
00110 
00111 void _PR_MD_InitSockets(void)
00112 {
00113     OSVERSIONINFO osvi;
00114 
00115     memset(&osvi, 0, sizeof(osvi));
00116     osvi.dwOSVersionInfoSize = sizeof(osvi);
00117     GetVersionEx(&osvi);
00118 
00119     /* if Vista or later... */
00120     if (osvi.dwMajorVersion >= 6)
00121     {
00122         libWinsock2 = LoadLibrary("Ws2_32.dll");
00123         if (libWinsock2)
00124         {
00125             wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, 
00126                                                         "WSAIoctl");
00127             if (wsaioctlProc)
00128             {
00129                 socketSetCompatMode = PR_TRUE;
00130             }
00131         }
00132     }
00133 }
00134 
00135 void _PR_MD_CleanupSockets(void)
00136 {
00137     socketSetCompatMode = PR_FALSE;
00138     wsaioctlProc = NULL;
00139     if (libWinsock2)
00140     {
00141         FreeLibrary(libWinsock2);
00142         libWinsock2 = NULL;
00143     }
00144 }
00145 
00146 PRInt32
00147 _PR_MD_SOCKET(int af, int type, int flags)
00148 {
00149     SOCKET sock;
00150     u_long one = 1;
00151 
00152     sock = socket(af, type, flags);
00153 
00154     if (sock == INVALID_SOCKET ) 
00155     {
00156         _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
00157         return (PRInt32)sock;
00158     }
00159 
00160     /*
00161     ** Make the socket Non-Blocking
00162     */
00163     if (ioctlsocket( sock, FIONBIO, &one) != 0)
00164     {
00165         PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
00166         closesocket(sock);
00167         return -1;
00168     }
00169 
00170     if ((af == AF_INET || af == AF_INET6) && 
00171         type == SOCK_STREAM && socketSetCompatMode)
00172     {
00173         WSA_COMPATIBILITY_MODE mode;
00174         char dummy[4];
00175         int ret_dummy;
00176 
00177         mode.BehaviorId = WsaBehaviorAutoTuning;
00178         mode.TargetOsVersion = NTDDI_LONGHORN;
00179         if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,  
00180                          (char *)&mode, sizeof(mode),
00181                          dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
00182         {
00183             int err = WSAGetLastError();
00184             PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
00185 
00186             /* SIO_SET_COMPATIBILITY_MODE may not be supported.
00187             ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP,
00188             ** don't close the socket.
00189             */ 
00190         }
00191     }
00192 
00193     return (PRInt32)sock;
00194 }
00195 
00196 /*
00197 ** _MD_CloseSocket() -- Close a socket
00198 **
00199 */
00200 PRInt32
00201 _MD_CloseSocket(PRInt32 osfd)
00202 {
00203     PRInt32 rv;
00204 
00205     rv = closesocket((SOCKET) osfd );
00206     if (rv < 0)
00207         _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
00208 
00209     return rv;
00210 }
00211 
00212 PRInt32
00213 _MD_SocketAvailable(PRFileDesc *fd)
00214 {
00215     PRInt32 result;
00216 
00217     if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
00218         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
00219         return -1;
00220     }
00221     return result;
00222 }
00223 
00224 PRInt32 _MD_Accept(
00225     PRFileDesc *fd, 
00226     PRNetAddr *raddr, 
00227     PRUint32 *rlen,
00228     PRIntervalTime timeout )
00229 {
00230     PRInt32 osfd = fd->secret->md.osfd;
00231     PRInt32 rv, err;
00232 
00233     while ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) 
00234     {
00235         err = WSAGetLastError();
00236         if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking))
00237         {
00238             if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00239             {
00240                 return(-1);
00241             }
00242         }
00243         else
00244         {
00245             _PR_MD_MAP_ACCEPT_ERROR(err);
00246             break;
00247         }
00248     }
00249     return(rv);
00250 } /* end _MD_accept() */
00251 
00252 PRInt32
00253 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, 
00254                PRIntervalTime timeout)
00255 {
00256     PRInt32 osfd = fd->secret->md.osfd;
00257     PRInt32 rv;
00258     int     err;
00259 
00260     if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) 
00261     {
00262         err = WSAGetLastError();
00263         if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK))
00264         {
00265             rv = socket_io_wait(osfd, CONNECT_FD, timeout);
00266             if ( rv < 0 )
00267             {
00268                 return(-1);
00269             }
00270             else
00271             {
00272                 PR_ASSERT(rv > 0);
00273                 /* it's connected */
00274                 return(0);
00275             } 
00276         }
00277         _PR_MD_MAP_CONNECT_ERROR(err);
00278     }
00279     return rv;
00280 }
00281 
00282 PRInt32
00283 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
00284 {
00285     PRInt32 rv;
00286 
00287     rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
00288 
00289     if (rv == SOCKET_ERROR)  {
00290         _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
00291         return -1;
00292     }
00293 
00294     return 0;
00295 }
00296 
00297 PRInt32
00298 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
00299 {
00300     PRInt32 rv;
00301 
00302     rv = listen(fd->secret->md.osfd, backlog);
00303 
00304     if (rv == SOCKET_ERROR)  {
00305         _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
00306         return -1;
00307     }
00308 
00309     return 0;
00310 }
00311 
00312 PRInt32
00313 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
00314             PRIntervalTime timeout)
00315 {
00316     PRInt32 osfd = fd->secret->md.osfd;
00317     PRInt32 rv, err;
00318     int osflags;
00319 
00320     if (0 == flags) {
00321         osflags = 0;
00322     } else {
00323         PR_ASSERT(PR_MSG_PEEK == flags);
00324         osflags = MSG_PEEK;
00325     }
00326     while ((rv = recv( osfd, buf, amount, osflags)) == -1) 
00327     {
00328         if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
00329             && (!fd->secret->nonblocking))
00330         {
00331             rv = socket_io_wait(osfd, READ_FD, timeout);
00332             if ( rv < 0 )
00333             {
00334                 return -1;
00335             } 
00336         } 
00337         else 
00338         {
00339             _PR_MD_MAP_RECV_ERROR(err);
00340             break;
00341         }
00342     } /* end while() */
00343     return(rv);
00344 }
00345 
00346 PRInt32
00347 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00348             PRIntervalTime timeout)
00349 {
00350     PRInt32 osfd = fd->secret->md.osfd;
00351     PRInt32 rv, err;
00352     PRInt32 bytesSent = 0;
00353 
00354     while(bytesSent < amount ) 
00355     {
00356         while ((rv = send( osfd, buf, amount, 0 )) == -1) 
00357         {
00358             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
00359                 && (!fd->secret->nonblocking))
00360             {
00361                 rv = socket_io_wait(osfd, WRITE_FD, timeout);
00362                 if ( rv < 0 )
00363                 {
00364                     return -1;
00365                 }
00366             } 
00367             else 
00368             {
00369                 _PR_MD_MAP_SEND_ERROR(err);
00370                 return -1;
00371             }
00372         }
00373         bytesSent += rv;
00374         if (fd->secret->nonblocking)
00375         {
00376             break;
00377         }
00378         if (bytesSent < amount) 
00379         {
00380             rv = socket_io_wait(osfd, WRITE_FD, timeout);
00381             if ( rv < 0 )
00382             {
00383                 return -1;
00384             }
00385         }
00386     }
00387     return bytesSent;
00388 }
00389 
00390 PRInt32
00391 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00392               const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
00393 {
00394     PRInt32 osfd = fd->secret->md.osfd;
00395     PRInt32 rv, err;
00396     PRInt32 bytesSent = 0;
00397 
00398     while(bytesSent < amount) 
00399     {
00400         while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr,
00401                 addrlen)) == -1) 
00402         {
00403             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
00404                 && (!fd->secret->nonblocking))
00405             {
00406                 rv = socket_io_wait(osfd, WRITE_FD, timeout);
00407                 if ( rv < 0 )
00408                 {
00409                     return -1;
00410                 }
00411             } 
00412             else 
00413             {
00414                 _PR_MD_MAP_SENDTO_ERROR(err);
00415                 return -1;
00416             }
00417         }
00418         bytesSent += rv;
00419         if (fd->secret->nonblocking)
00420         {
00421             break;
00422         }
00423         if (bytesSent < amount) 
00424         {
00425             rv = socket_io_wait(osfd, WRITE_FD, timeout);
00426             if (rv < 0) 
00427             {
00428                 return -1;
00429             }
00430         }
00431     }
00432     return bytesSent;
00433 }
00434 
00435 PRInt32
00436 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
00437                 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
00438 {
00439     PRInt32 osfd = fd->secret->md.osfd;
00440     PRInt32 rv, err;
00441 
00442     while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr,
00443             addrlen)) == -1) 
00444     {
00445         if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
00446             && (!fd->secret->nonblocking))
00447         {
00448             rv = socket_io_wait(osfd, READ_FD, timeout);
00449             if ( rv < 0)
00450             {
00451                 return -1;
00452             } 
00453         } 
00454         else 
00455         {
00456             _PR_MD_MAP_RECVFROM_ERROR(err);
00457             break;
00458         }
00459     }
00460     return(rv);
00461 }
00462 
00463 PRInt32
00464 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
00465 {
00466     int index;
00467     int sent = 0;
00468     int rv;
00469 
00470     for (index=0; index < iov_size; index++) 
00471     {
00472         rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
00473         if (rv > 0) 
00474             sent += rv;
00475         if ( rv != iov[index].iov_len ) 
00476         {
00477             if (rv < 0)
00478             {
00479                 if (fd->secret->nonblocking
00480                     && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
00481                     && (sent > 0))
00482                 {
00483                     return sent;
00484                 }
00485                 else
00486                 {
00487                     return -1;
00488                 }
00489             }
00490             /* Only a nonblocking socket can have partial sends */
00491             PR_ASSERT(fd->secret->nonblocking);
00492             return sent;
00493         }
00494     }
00495     return sent;
00496 }
00497 
00498 PRInt32
00499 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
00500 {
00501 PRInt32 rv;
00502 
00503     rv = shutdown(fd->secret->md.osfd, how);
00504     if (rv < 0)
00505         _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
00506     return rv;
00507 }
00508 
00509 PRStatus
00510 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
00511 {
00512     PRInt32 rv;
00513 
00514     rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
00515     if (rv==0) {
00516         return PR_SUCCESS;
00517     } else {
00518         _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
00519         return PR_FAILURE;
00520     }
00521 }
00522 
00523 PRStatus
00524 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
00525 {
00526     PRInt32 rv;
00527 
00528     rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
00529     if (rv==0) {
00530         return PR_SUCCESS;
00531     } else {
00532         _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
00533         return PR_FAILURE;
00534     }
00535 }
00536 
00537 PRStatus
00538 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
00539 {
00540     PRInt32 rv;
00541 
00542     rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
00543     if (rv==0) {
00544         return PR_SUCCESS;
00545     } else {
00546         _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
00547         return PR_FAILURE;
00548     }
00549 }
00550 
00551 PRStatus
00552 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
00553 {
00554     PRInt32 rv;
00555 
00556     rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
00557     if (rv==0) {
00558         return PR_SUCCESS;
00559     } else {
00560         _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
00561         return PR_FAILURE;
00562     }
00563 }
00564 
00565 void
00566 _MD_MakeNonblock(PRFileDesc *f)
00567 {
00568     return; /* do nothing */
00569 }
00570 
00571 
00572 
00573 /*
00574  * socket_io_wait --
00575  *
00576  * Wait for socket i/o, periodically checking for interrupt.
00577  *
00578  * This function returns 1 on success.  On failure, it returns
00579  * -1 and sets the error codes.  It never returns 0.
00580  */
00581 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
00582 
00583 static PRInt32 socket_io_wait(
00584     PRInt32 osfd, 
00585     PRInt32 fd_type,
00586     PRIntervalTime timeout)
00587 {
00588     PRInt32 rv = -1;
00589     struct timeval tv;
00590     PRThread *me = _PR_MD_CURRENT_THREAD();
00591     PRIntervalTime elapsed, remaining;
00592     PRBool wait_for_remaining;
00593     fd_set rd_wr, ex;
00594     int err, len;
00595 
00596     switch (timeout) {
00597         case PR_INTERVAL_NO_WAIT:
00598             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00599             break;
00600         case PR_INTERVAL_NO_TIMEOUT:
00601             /*
00602              * This is a special case of the 'default' case below.
00603              * Please see the comments there.
00604              */
00605             tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00606             tv.tv_usec = 0;
00607             FD_ZERO(&rd_wr);
00608             FD_ZERO(&ex);
00609             do {
00610                 FD_SET(osfd, &rd_wr);
00611                 FD_SET(osfd, &ex);
00612                 switch( fd_type )
00613                 {
00614                     case READ_FD:
00615                         rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00616                         break;
00617                     case WRITE_FD:
00618                         rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00619                         break;
00620                     case CONNECT_FD:
00621                         rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv);
00622                         break;
00623                     default:
00624                         PR_ASSERT(0);
00625                         break;
00626                 } /* end switch() */
00627                 if (rv == -1 )
00628                 {
00629                     _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
00630                     break;
00631                 }
00632                 if ( rv > 0 && fd_type == CONNECT_FD )
00633                 {
00634                     /*
00635                      * Call Sleep(0) to work around a Winsock timing bug.
00636                      */
00637                     Sleep(0);
00638                     if (FD_ISSET((SOCKET)osfd, &ex))
00639                     {
00640                         len = sizeof(err);
00641                         if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
00642                                 (char *) &err, &len) == SOCKET_ERROR)
00643                         {  
00644                             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
00645                             return -1;
00646                         }
00647                         if (err != 0)
00648                             _PR_MD_MAP_CONNECT_ERROR(err);
00649                         else
00650                             PR_SetError(PR_UNKNOWN_ERROR, 0);
00651                         return -1;
00652                     }
00653                     if (FD_ISSET((SOCKET)osfd, &rd_wr))
00654                     {
00655                         /* it's connected */
00656                         return 1;
00657                     }
00658                     PR_ASSERT(0);
00659                 }
00660                 if (_PR_PENDING_INTERRUPT(me)) {
00661                     me->flags &= ~_PR_INTERRUPT;
00662                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00663                     rv = -1;
00664                     break;
00665                 }
00666             } while (rv == 0);
00667             break;
00668         default:
00669             remaining = timeout;
00670             FD_ZERO(&rd_wr);
00671             FD_ZERO(&ex);
00672             do {
00673                 /*
00674                  * We block in _MD_SELECT for at most
00675                  * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
00676                  * so that there is an upper limit on the delay
00677                  * before the interrupt bit is checked.
00678                  */
00679                 wait_for_remaining = PR_TRUE;
00680                 tv.tv_sec = PR_IntervalToSeconds(remaining);
00681                 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
00682                     wait_for_remaining = PR_FALSE;
00683                     tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00684                     tv.tv_usec = 0;
00685                 } else {
00686                     tv.tv_usec = PR_IntervalToMicroseconds(
00687                         remaining -
00688                         PR_SecondsToInterval(tv.tv_sec));
00689                 }
00690                 FD_SET(osfd, &rd_wr);
00691                 FD_SET(osfd, &ex);
00692                 switch( fd_type )
00693                 {
00694                     case READ_FD:
00695                         rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00696                         break;
00697                     case WRITE_FD:
00698                         rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00699                         break;
00700                     case CONNECT_FD:
00701                         rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv);
00702                         break;
00703                     default:
00704                         PR_ASSERT(0);
00705                         break;
00706                 } /* end switch() */
00707                 if (rv == -1)
00708                 {
00709                     _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
00710                     break;
00711                 }
00712                 if ( rv > 0 && fd_type == CONNECT_FD )
00713                 {
00714                     /*
00715                      * Call Sleep(0) to work around a Winsock timing bug.
00716                      */
00717                     Sleep(0);
00718                     if (FD_ISSET((SOCKET)osfd, &ex))
00719                     {
00720                         len = sizeof(err);
00721                         if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
00722                                 (char *) &err, &len) == SOCKET_ERROR)
00723                         {  
00724                             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
00725                             return -1;
00726                         }
00727                         if (err != 0)
00728                             _PR_MD_MAP_CONNECT_ERROR(err);
00729                         else
00730                             PR_SetError(PR_UNKNOWN_ERROR, 0);
00731                         return -1;
00732                     }
00733                     if (FD_ISSET((SOCKET)osfd, &rd_wr))
00734                     {
00735                         /* it's connected */
00736                         return 1;
00737                     }
00738                     PR_ASSERT(0);
00739                 }
00740                 if (_PR_PENDING_INTERRUPT(me)) {
00741                     me->flags &= ~_PR_INTERRUPT;
00742                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00743                     rv = -1;
00744                     break;
00745                 }
00746                 /*
00747                  * We loop again if _MD_SELECT timed out and the
00748                  * timeout deadline has not passed yet.
00749                  */
00750                 if (rv == 0 )
00751                 {
00752                     if (wait_for_remaining) {
00753                         elapsed = remaining;
00754                     } else {
00755                         elapsed = PR_SecondsToInterval(tv.tv_sec) 
00756                                     + PR_MicrosecondsToInterval(tv.tv_usec);
00757                     }
00758                     if (elapsed >= remaining) {
00759                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00760                         rv = -1;
00761                         break;
00762                     } else {
00763                         remaining = remaining - elapsed;
00764                     }
00765                 }
00766             } while (rv == 0 );
00767             break;
00768     }
00769     return(rv);
00770 } /* end socket_io_wait() */