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