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