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