Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / src / md / windows / w95sock.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998-2000
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 /* Win95 Sockets module
39  *
40  */
41
42 #include "primpl.h"
43
44 #define READ_FD     1
45 #define WRITE_FD    2
46 #define CONNECT_FD  3
47
48 static PRInt32 socket_io_wait(
49     PROsfd osfd, 
50     PRInt32 fd_type,
51     PRIntervalTime timeout);
52
53
54 /* --- SOCKET IO --------------------------------------------------------- */
55
56 /*
57  * we only want to call WSAIoctl() on Vista and later
58  * so don't pay for it at build time (and avoid including winsock2.h)
59  */
60
61 /* from ws2def.h */
62 #define IOC_IN                      0x80000000      /* copy in parameters */
63 #define IOC_VENDOR                  0x18000000
64 #define _WSAIOW(x,y)                (IOC_IN|(x)|(y))
65 /* from MSWSockDef.h */
66 #define SIO_SET_COMPATIBILITY_MODE  _WSAIOW(IOC_VENDOR,300)
67
68 typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
69     WsaBehaviorAll = 0,
70     WsaBehaviorReceiveBuffering,
71     WsaBehaviorAutoTuning
72 } WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
73
74 /* from sdkddkver.h */
75 #define NTDDI_WIN6              0x06000000  /* Windows Vista */
76
77 /* from winsock2.h */
78 #define WSAEVENT                HANDLE
79
80 #define WSAOVERLAPPED           OVERLAPPED
81 typedef struct _OVERLAPPED *    LPWSAOVERLAPPED;
82
83 typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
84     IN DWORD dwError,
85     IN DWORD cbTransferred,
86     IN LPWSAOVERLAPPED lpOverlapped,
87     IN DWORD dwFlags
88 );
89
90 typedef int (__stdcall * WSAIOCTLPROC) (
91     SOCKET s,
92     DWORD dwIoControlCode,
93     LPVOID lpvInBuffer,
94     DWORD cbInBuffer,
95     LPVOID lpvOutBuffer,
96     DWORD cbOutBuffer,
97     LPDWORD lpcbBytesReturned,
98     LPWSAOVERLAPPED lpOverlapped,
99     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
100 );
101
102 typedef struct _WSA_COMPATIBILITY_MODE {
103     WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId;
104     ULONG TargetOsVersion;
105 } WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE;
106
107 static HMODULE libWinsock2 = NULL;
108 static WSAIOCTLPROC wsaioctlProc = NULL;
109 static PRBool socketSetCompatMode = PR_FALSE;
110
111 void _PR_MD_InitSockets(void)
112 {
113     OSVERSIONINFO osvi;
114
115     memset(&osvi, 0, sizeof(osvi));
116     osvi.dwOSVersionInfoSize = sizeof(osvi);
117     GetVersionEx(&osvi);
118
119     /* if Vista or later... */
120     if (osvi.dwMajorVersion >= 6)
121     {
122         libWinsock2 = LoadLibraryW(L"Ws2_32.dll");
123         if (libWinsock2)
124         {
125             wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, 
126                                                         "WSAIoctl");
127             if (wsaioctlProc)
128             {
129                 socketSetCompatMode = PR_TRUE;
130             }
131         }
132     }
133 }
134
135 void _PR_MD_CleanupSockets(void)
136 {
137     socketSetCompatMode = PR_FALSE;
138     wsaioctlProc = NULL;
139     if (libWinsock2)
140     {
141         FreeLibrary(libWinsock2);
142         libWinsock2 = NULL;
143     }
144 }
145
146 PROsfd
147 _PR_MD_SOCKET(int af, int type, int flags)
148 {
149     SOCKET sock;
150     u_long one = 1;
151
152     sock = socket(af, type, flags);
153
154     if (sock == INVALID_SOCKET ) 
155     {
156         _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
157         return (PROsfd)sock;
158     }
159
160     /*
161     ** Make the socket Non-Blocking
162     */
163     if (ioctlsocket( sock, FIONBIO, &one) != 0)
164     {
165         PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
166         closesocket(sock);
167         return -1;
168     }
169
170     if ((af == AF_INET || af == AF_INET6) && 
171         type == SOCK_STREAM && socketSetCompatMode)
172     {
173         WSA_COMPATIBILITY_MODE mode;
174         char dummy[4];
175         int ret_dummy;
176
177         mode.BehaviorId = WsaBehaviorAutoTuning;
178         mode.TargetOsVersion = NTDDI_WIN6;
179         if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,  
180                          (char *)&mode, sizeof(mode),
181                          dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
182         {
183             int err = WSAGetLastError();
184             PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
185
186             /* SIO_SET_COMPATIBILITY_MODE may not be supported.
187             ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP,
188             ** don't close the socket.
189             */ 
190         }
191     }
192
193     return (PROsfd)sock;
194 }
195
196 /*
197 ** _MD_CloseSocket() -- Close a socket
198 **
199 */
200 PRInt32
201 _MD_CloseSocket(PROsfd osfd)
202 {
203     PRInt32 rv;
204
205     rv = closesocket((SOCKET) osfd );
206     if (rv < 0)
207         _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
208
209     return rv;
210 }
211
212 PRInt32
213 _MD_SocketAvailable(PRFileDesc *fd)
214 {
215     PRInt32 result;
216
217     if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
218         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
219         return -1;
220     }
221     return result;
222 }
223
224 PROsfd _MD_Accept(
225     PRFileDesc *fd, 
226     PRNetAddr *raddr, 
227     PRUint32 *rlen,
228     PRIntervalTime timeout )
229 {
230     PROsfd osfd = fd->secret->md.osfd;
231     SOCKET sock;
232     PRInt32 rv, err;
233
234     while ((sock = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) 
235     {
236         err = WSAGetLastError();
237         if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking))
238         {
239             if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
240             {
241                 break;
242             }
243         }
244         else
245         {
246             _PR_MD_MAP_ACCEPT_ERROR(err);
247             break;
248         }
249     }
250     return(sock);
251 } /* end _MD_accept() */
252
253 PRInt32
254 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, 
255                PRIntervalTime timeout)
256 {
257     PROsfd osfd = fd->secret->md.osfd;
258     PRInt32 rv;
259     int     err;
260
261     if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) 
262     {
263         err = WSAGetLastError();
264         if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK))
265         {
266             rv = socket_io_wait(osfd, CONNECT_FD, timeout);
267             if ( rv < 0 )
268             {
269                 return(-1);
270             }
271             else
272             {
273                 PR_ASSERT(rv > 0);
274                 /* it's connected */
275                 return(0);
276             } 
277         }
278         _PR_MD_MAP_CONNECT_ERROR(err);
279     }
280     return rv;
281 }
282
283 PRInt32
284 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
285 {
286     PRInt32 rv;
287
288     rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
289
290     if (rv == SOCKET_ERROR)  {
291         _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
292         return -1;
293     }
294
295     return 0;
296 }
297
298 PRInt32
299 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
300 {
301     PRInt32 rv;
302
303     rv = listen(fd->secret->md.osfd, backlog);
304
305     if (rv == SOCKET_ERROR)  {
306         _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
307         return -1;
308     }
309
310     return 0;
311 }
312
313 PRInt32
314 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
315             PRIntervalTime timeout)
316 {
317     PROsfd osfd = fd->secret->md.osfd;
318     PRInt32 rv, err;
319     int osflags;
320
321     if (0 == flags) {
322         osflags = 0;
323     } else {
324         PR_ASSERT(PR_MSG_PEEK == flags);
325         osflags = MSG_PEEK;
326     }
327     while ((rv = recv( osfd, buf, amount, osflags)) == -1) 
328     {
329         if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
330             && (!fd->secret->nonblocking))
331         {
332             rv = socket_io_wait(osfd, READ_FD, timeout);
333             if ( rv < 0 )
334             {
335                 return -1;
336             } 
337         } 
338         else 
339         {
340             _PR_MD_MAP_RECV_ERROR(err);
341             break;
342         }
343     } /* end while() */
344     return(rv);
345 }
346
347 PRInt32
348 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
349             PRIntervalTime timeout)
350 {
351     PROsfd osfd = fd->secret->md.osfd;
352     PRInt32 rv, err;
353     PRInt32 bytesSent = 0;
354
355     while(bytesSent < amount ) 
356     {
357         while ((rv = send( osfd, buf, amount, 0 )) == -1) 
358         {
359             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
360                 && (!fd->secret->nonblocking))
361             {
362                 rv = socket_io_wait(osfd, WRITE_FD, timeout);
363                 if ( rv < 0 )
364                 {
365                     return -1;
366                 }
367             } 
368             else 
369             {
370                 _PR_MD_MAP_SEND_ERROR(err);
371                 return -1;
372             }
373         }
374         bytesSent += rv;
375         if (fd->secret->nonblocking)
376         {
377             break;
378         }
379         if (bytesSent < amount) 
380         {
381             rv = socket_io_wait(osfd, WRITE_FD, timeout);
382             if ( rv < 0 )
383             {
384                 return -1;
385             }
386         }
387     }
388     return bytesSent;
389 }
390
391 PRInt32
392 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
393               const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
394 {
395     PROsfd osfd = fd->secret->md.osfd;
396     PRInt32 rv, err;
397     PRInt32 bytesSent = 0;
398
399     while(bytesSent < amount) 
400     {
401         while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr,
402                 addrlen)) == -1) 
403         {
404             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
405                 && (!fd->secret->nonblocking))
406             {
407                 rv = socket_io_wait(osfd, WRITE_FD, timeout);
408                 if ( rv < 0 )
409                 {
410                     return -1;
411                 }
412             } 
413             else 
414             {
415                 _PR_MD_MAP_SENDTO_ERROR(err);
416                 return -1;
417             }
418         }
419         bytesSent += rv;
420         if (fd->secret->nonblocking)
421         {
422             break;
423         }
424         if (bytesSent < amount) 
425         {
426             rv = socket_io_wait(osfd, WRITE_FD, timeout);
427             if (rv < 0) 
428             {
429                 return -1;
430             }
431         }
432     }
433     return bytesSent;
434 }
435
436 PRInt32
437 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
438                 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
439 {
440     PROsfd osfd = fd->secret->md.osfd;
441     PRInt32 rv, err;
442
443     while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr,
444             addrlen)) == -1) 
445     {
446         if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) 
447             && (!fd->secret->nonblocking))
448         {
449             rv = socket_io_wait(osfd, READ_FD, timeout);
450             if ( rv < 0)
451             {
452                 return -1;
453             } 
454         } 
455         else 
456         {
457             _PR_MD_MAP_RECVFROM_ERROR(err);
458             break;
459         }
460     }
461     return(rv);
462 }
463
464 PRInt32
465 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
466 {
467     int index;
468     int sent = 0;
469     int rv;
470
471     for (index=0; index < iov_size; index++) 
472     {
473         rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
474         if (rv > 0) 
475             sent += rv;
476         if ( rv != iov[index].iov_len ) 
477         {
478             if (rv < 0)
479             {
480                 if (fd->secret->nonblocking
481                     && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
482                     && (sent > 0))
483                 {
484                     return sent;
485                 }
486                 else
487                 {
488                     return -1;
489                 }
490             }
491             /* Only a nonblocking socket can have partial sends */
492             PR_ASSERT(fd->secret->nonblocking);
493             return sent;
494         }
495     }
496     return sent;
497 }
498
499 PRInt32
500 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
501 {
502 PRInt32 rv;
503
504     rv = shutdown(fd->secret->md.osfd, how);
505     if (rv < 0)
506         _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
507     return rv;
508 }
509
510 PRStatus
511 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
512 {
513     PRInt32 rv;
514
515     rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
516     if (rv==0) {
517         return PR_SUCCESS;
518     } else {
519         _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
520         return PR_FAILURE;
521     }
522 }
523
524 PRStatus
525 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
526 {
527     PRInt32 rv;
528
529     rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
530     if (rv==0) {
531         return PR_SUCCESS;
532     } else {
533         _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
534         return PR_FAILURE;
535     }
536 }
537
538 PRStatus
539 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
540 {
541     PRInt32 rv;
542
543     rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
544     if (rv==0) {
545         return PR_SUCCESS;
546     } else {
547         _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
548         return PR_FAILURE;
549     }
550 }
551
552 PRStatus
553 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
554 {
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
567 _MD_MakeNonblock(PRFileDesc *f)
568 {
569     return; /* do nothing */
570 }
571
572
573
574 /*
575  * socket_io_wait --
576  *
577  * Wait for socket i/o, periodically checking for interrupt.
578  *
579  * This function returns 1 on success.  On failure, it returns
580  * -1 and sets the error codes.  It never returns 0.
581  */
582 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
583
584 static PRInt32 socket_io_wait(
585     PROsfd osfd, 
586     PRInt32 fd_type,
587     PRIntervalTime timeout)
588 {
589     PRInt32 rv = -1;
590     struct timeval tv;
591     PRThread *me = _PR_MD_CURRENT_THREAD();
592     PRIntervalTime elapsed, remaining;
593     PRBool wait_for_remaining;
594     fd_set rd_wr, ex;
595     int err, len;
596
597     switch (timeout) {
598         case PR_INTERVAL_NO_WAIT:
599             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
600             break;
601         case PR_INTERVAL_NO_TIMEOUT:
602             /*
603              * This is a special case of the 'default' case below.
604              * Please see the comments there.
605              */
606             tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
607             tv.tv_usec = 0;
608             FD_ZERO(&rd_wr);
609             FD_ZERO(&ex);
610             do {
611                 FD_SET(osfd, &rd_wr);
612                 FD_SET(osfd, &ex);
613                 switch( fd_type )
614                 {
615                     case READ_FD:
616                         rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
617                         break;
618                     case WRITE_FD:
619                         rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
620                         break;
621                     case CONNECT_FD:
622                         rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
623                         break;
624                     default:
625                         PR_ASSERT(0);
626                         break;
627                 } /* end switch() */
628                 if (rv == -1 )
629                 {
630                     _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
631                     break;
632                 }
633                 if ( rv > 0 && fd_type == CONNECT_FD )
634                 {
635                     /*
636                      * Call Sleep(0) to work around a Winsock timing bug.
637                      */
638                     Sleep(0);
639                     if (FD_ISSET((SOCKET)osfd, &ex))
640                     {
641                         len = sizeof(err);
642                         if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
643                                 (char *) &err, &len) == SOCKET_ERROR)
644                         {  
645                             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
646                             return -1;
647                         }
648                         if (err != 0)
649                             _PR_MD_MAP_CONNECT_ERROR(err);
650                         else
651                             PR_SetError(PR_UNKNOWN_ERROR, 0);
652                         return -1;
653                     }
654                     if (FD_ISSET((SOCKET)osfd, &rd_wr))
655                     {
656                         /* it's connected */
657                         return 1;
658                     }
659                     PR_ASSERT(0);
660                 }
661                 if (_PR_PENDING_INTERRUPT(me)) {
662                     me->flags &= ~_PR_INTERRUPT;
663                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
664                     rv = -1;
665                     break;
666                 }
667             } while (rv == 0);
668             break;
669         default:
670             remaining = timeout;
671             FD_ZERO(&rd_wr);
672             FD_ZERO(&ex);
673             do {
674                 /*
675                  * We block in _MD_SELECT for at most
676                  * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
677                  * so that there is an upper limit on the delay
678                  * before the interrupt bit is checked.
679                  */
680                 wait_for_remaining = PR_TRUE;
681                 tv.tv_sec = PR_IntervalToSeconds(remaining);
682                 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
683                     wait_for_remaining = PR_FALSE;
684                     tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
685                     tv.tv_usec = 0;
686                 } else {
687                     tv.tv_usec = PR_IntervalToMicroseconds(
688                         remaining -
689                         PR_SecondsToInterval(tv.tv_sec));
690                 }
691                 FD_SET(osfd, &rd_wr);
692                 FD_SET(osfd, &ex);
693                 switch( fd_type )
694                 {
695                     case READ_FD:
696                         rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
697                         break;
698                     case WRITE_FD:
699                         rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
700                         break;
701                     case CONNECT_FD:
702                         rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
703                         break;
704                     default:
705                         PR_ASSERT(0);
706                         break;
707                 } /* end switch() */
708                 if (rv == -1)
709                 {
710                     _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
711                     break;
712                 }
713                 if ( rv > 0 && fd_type == CONNECT_FD )
714                 {
715                     /*
716                      * Call Sleep(0) to work around a Winsock timing bug.
717                      */
718                     Sleep(0);
719                     if (FD_ISSET((SOCKET)osfd, &ex))
720                     {
721                         len = sizeof(err);
722                         if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
723                                 (char *) &err, &len) == SOCKET_ERROR)
724                         {  
725                             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
726                             return -1;
727                         }
728                         if (err != 0)
729                             _PR_MD_MAP_CONNECT_ERROR(err);
730                         else
731                             PR_SetError(PR_UNKNOWN_ERROR, 0);
732                         return -1;
733                     }
734                     if (FD_ISSET((SOCKET)osfd, &rd_wr))
735                     {
736                         /* it's connected */
737                         return 1;
738                     }
739                     PR_ASSERT(0);
740                 }
741                 if (_PR_PENDING_INTERRUPT(me)) {
742                     me->flags &= ~_PR_INTERRUPT;
743                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
744                     rv = -1;
745                     break;
746                 }
747                 /*
748                  * We loop again if _MD_SELECT timed out and the
749                  * timeout deadline has not passed yet.
750                  */
751                 if (rv == 0 )
752                 {
753                     if (wait_for_remaining) {
754                         elapsed = remaining;
755                     } else {
756                         elapsed = PR_SecondsToInterval(tv.tv_sec) 
757                                     + PR_MicrosecondsToInterval(tv.tv_usec);
758                     }
759                     if (elapsed >= remaining) {
760                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
761                         rv = -1;
762                         break;
763                     } else {
764                         remaining = remaining - elapsed;
765                     }
766                 }
767             } while (rv == 0 );
768             break;
769     }
770     return(rv);
771 } /* end socket_io_wait() */