prsocket.c (53775B)
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 #include "primpl.h" 7 8 #include <string.h> 9 10 #if defined(_WIN64) 11 # ifndef SO_UPDATE_CONNECT_CONTEXT 12 # define SO_UPDATE_CONNECT_CONTEXT 0x7010 13 # endif 14 #endif 15 16 /************************************************************************/ 17 18 /* These two functions are only used in assertions. */ 19 #if defined(DEBUG) 20 21 PRBool IsValidNetAddr(const PRNetAddr* addr) { 22 if ((addr != NULL) 23 # if defined(XP_UNIX) 24 && (addr->raw.family != PR_AF_LOCAL) 25 # endif 26 && (addr->raw.family != PR_AF_INET6) && 27 (addr->raw.family != PR_AF_INET)) { 28 return PR_FALSE; 29 } 30 return PR_TRUE; 31 } 32 33 static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) { 34 /* 35 * The definition of the length of a Unix domain socket address 36 * is not uniform, so we don't check it. 37 */ 38 if ((addr != NULL) 39 # if defined(XP_UNIX) 40 && (addr->raw.family != AF_UNIX) 41 # endif 42 && (PR_NETADDR_SIZE(addr) != addr_len)) { 43 # if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 44 /* 45 * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 46 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id 47 * field and is 28 bytes. It is possible for socket functions 48 * to return an addr_len greater than sizeof(struct sockaddr_in6). 49 * We need to allow that. (Bugzilla bug #77264) 50 */ 51 if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) { 52 return PR_TRUE; 53 } 54 # endif 55 /* 56 * The accept(), getsockname(), etc. calls on some platforms 57 * do not set the actual socket address length on return. 58 * In this case, we verifiy addr_len is still the value we 59 * passed in (i.e., sizeof(PRNetAddr)). 60 */ 61 # if defined(QNX) 62 if (sizeof(PRNetAddr) == addr_len) { 63 return PR_TRUE; 64 } 65 # endif 66 return PR_FALSE; 67 } 68 return PR_TRUE; 69 } 70 71 #endif /* DEBUG */ 72 73 static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc* fd, const PRIOVec* iov, 74 PRInt32 iov_size, 75 PRIntervalTime timeout) { 76 PRThread* me = _PR_MD_CURRENT_THREAD(); 77 int w = 0; 78 const PRIOVec* tmp_iov; 79 #define LOCAL_MAXIOV 8 80 PRIOVec local_iov[LOCAL_MAXIOV]; 81 PRIOVec* iov_copy = NULL; 82 int tmp_out; 83 int index, iov_cnt; 84 int count = 0, sz = 0; /* 'count' is the return value. */ 85 86 if (_PR_PENDING_INTERRUPT(me)) { 87 me->flags &= ~_PR_INTERRUPT; 88 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 89 return -1; 90 } 91 if (_PR_IO_PENDING(me)) { 92 PR_SetError(PR_IO_PENDING_ERROR, 0); 93 return -1; 94 } 95 96 /* 97 * Assume the first writev will succeed. Copy iov's only on 98 * failure. 99 */ 100 tmp_iov = iov; 101 for (index = 0; index < iov_size; index++) { 102 sz += iov[index].iov_len; 103 } 104 105 iov_cnt = iov_size; 106 107 while (sz > 0) { 108 w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); 109 if (w < 0) { 110 count = -1; 111 break; 112 } 113 count += w; 114 if (fd->secret->nonblocking) { 115 break; 116 } 117 sz -= w; 118 119 if (sz > 0) { 120 /* find the next unwritten vector */ 121 for (index = 0, tmp_out = count; tmp_out >= iov[index].iov_len; 122 tmp_out -= iov[index].iov_len, index++) { 123 ; 124 } /* nothing to execute */ 125 126 if (tmp_iov == iov) { 127 /* 128 * The first writev failed so we 129 * must copy iov's around. 130 * Avoid calloc/free if there 131 * are few enough iov's. 132 */ 133 if (iov_size - index <= LOCAL_MAXIOV) { 134 iov_copy = local_iov; 135 } else if ((iov_copy = (PRIOVec*)PR_CALLOC((iov_size - index) * 136 sizeof *iov_copy)) == NULL) { 137 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 138 return -1; 139 } 140 tmp_iov = iov_copy; 141 } 142 143 PR_ASSERT(tmp_iov == iov_copy); 144 145 /* fill in the first partial read */ 146 iov_copy[0].iov_base = &(((char*)iov[index].iov_base)[tmp_out]); 147 iov_copy[0].iov_len = iov[index].iov_len - tmp_out; 148 index++; 149 150 /* copy the remaining vectors */ 151 for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { 152 iov_copy[iov_cnt].iov_base = iov[index].iov_base; 153 iov_copy[iov_cnt].iov_len = iov[index].iov_len; 154 } 155 } 156 } 157 158 if (iov_copy != local_iov) { 159 PR_DELETE(iov_copy); 160 } 161 return count; 162 } 163 164 /************************************************************************/ 165 166 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd) { 167 PRFileDesc* fd; 168 169 if (!_pr_initialized) { 170 _PR_ImplicitInitialization(); 171 } 172 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); 173 if (fd != NULL) { 174 _PR_MD_MAKE_NONBLOCK(fd); 175 _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); 176 #ifdef _PR_NEED_SECRET_AF 177 /* this means we can only import IPv4 sockets here. 178 * but this is what the function in ptio.c does. 179 * We need a way to import IPv6 sockets, too. 180 */ 181 fd->secret->af = AF_INET; 182 #endif 183 } else { 184 _PR_MD_CLOSE_SOCKET(osfd); 185 } 186 return (fd); 187 } 188 189 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd) { 190 PRFileDesc* fd; 191 192 if (!_pr_initialized) { 193 _PR_ImplicitInitialization(); 194 } 195 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); 196 if (fd != NULL) { 197 _PR_MD_MAKE_NONBLOCK(fd); 198 _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); 199 } else { 200 _PR_MD_CLOSE_SOCKET(osfd); 201 } 202 return (fd); 203 } 204 205 static const PRIOMethods* PR_GetSocketPollFdMethods(void); 206 207 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd) { 208 PRFileDesc* fd; 209 210 if (!_pr_initialized) { 211 _PR_ImplicitInitialization(); 212 } 213 214 fd = _PR_Getfd(); 215 216 if (fd == NULL) { 217 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 218 } else { 219 fd->secret->md.osfd = osfd; 220 fd->secret->inheritable = _PR_TRI_FALSE; 221 fd->secret->state = _PR_FILEDESC_OPEN; 222 fd->methods = PR_GetSocketPollFdMethods(); 223 } 224 225 return fd; 226 } /* PR_CreateSocketPollFD */ 227 228 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) { 229 if (NULL == fd) { 230 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 231 return PR_FAILURE; 232 } 233 fd->secret->state = _PR_FILEDESC_CLOSED; 234 _PR_Putfd(fd); 235 return PR_SUCCESS; 236 } /* PR_DestroySocketPollFd */ 237 238 static PRStatus PR_CALLBACK SocketConnect(PRFileDesc* fd, const PRNetAddr* addr, 239 PRIntervalTime timeout) { 240 PRInt32 rv; /* Return value of _PR_MD_CONNECT */ 241 const PRNetAddr* addrp = addr; 242 #if defined(_PR_INET6) 243 PRNetAddr addrCopy; 244 #endif 245 PRThread* me = _PR_MD_CURRENT_THREAD(); 246 247 if (_PR_PENDING_INTERRUPT(me)) { 248 me->flags &= ~_PR_INTERRUPT; 249 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 250 return PR_FAILURE; 251 } 252 #if defined(_PR_INET6) 253 if (addr->raw.family == PR_AF_INET6) { 254 addrCopy = *addr; 255 addrCopy.raw.family = AF_INET6; 256 addrp = &addrCopy; 257 } 258 #endif 259 260 rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout); 261 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); 262 if (rv == 0) { 263 return PR_SUCCESS; 264 } else { 265 return PR_FAILURE; 266 } 267 } 268 269 static PRStatus PR_CALLBACK SocketConnectContinue(PRFileDesc* fd, 270 PRInt16 out_flags) { 271 PROsfd osfd; 272 int err; 273 274 if (out_flags & PR_POLL_NVAL) { 275 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 276 return PR_FAILURE; 277 } 278 if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { 279 PR_ASSERT(out_flags == 0); 280 PR_SetError(PR_IN_PROGRESS_ERROR, 0); 281 return PR_FAILURE; 282 } 283 284 osfd = fd->secret->md.osfd; 285 286 #if defined(XP_UNIX) 287 288 err = _MD_unix_get_nonblocking_connect_error(osfd); 289 if (err != 0) { 290 _PR_MD_MAP_CONNECT_ERROR(err); 291 return PR_FAILURE; 292 } 293 return PR_SUCCESS; 294 295 #elif defined(WIN32) 296 297 if (out_flags & PR_POLL_EXCEPT) { 298 int len = sizeof(err); 299 if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 300 SOCKET_ERROR) { 301 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); 302 return PR_FAILURE; 303 } 304 if (err != 0) { 305 _PR_MD_MAP_CONNECT_ERROR(err); 306 } else { 307 # if defined(_WIN64) 308 if (fd->secret->overlappedActive) { 309 PRInt32 rvSent; 310 if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, 311 FALSE) == FALSE) { 312 err = WSAGetLastError(); 313 PR_LOG( 314 _pr_io_lm, PR_LOG_MIN, 315 ("SocketConnectContinue GetOverlappedResult failed %d\n", err)); 316 if (err != ERROR_IO_INCOMPLETE) { 317 _PR_MD_MAP_CONNECT_ERROR(err); 318 fd->secret->overlappedActive = PR_FALSE; 319 } 320 } 321 } 322 if (err == 0) { 323 PR_SetError(PR_UNKNOWN_ERROR, 0); 324 } 325 # else 326 PR_SetError(PR_UNKNOWN_ERROR, 0); 327 # endif 328 } 329 return PR_FAILURE; 330 } 331 332 PR_ASSERT(out_flags & PR_POLL_WRITE); 333 334 # if defined(_WIN64) 335 if (fd->secret->alreadyConnected) { 336 fd->secret->alreadyConnected = PR_FALSE; 337 } 338 /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped 339 * input/output. 340 * To get result we need to use GetOverlappedResult. */ 341 if (fd->secret->overlappedActive) { 342 PR_ASSERT(fd->secret->nonblocking); 343 PRInt32 rvSent; 344 if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE) == 345 TRUE) { 346 fd->secret->overlappedActive = PR_FALSE; 347 PR_LOG(_pr_io_lm, PR_LOG_MIN, 348 ("SocketConnectContinue GetOverlappedResult succeeded\n")); 349 /* When ConnectEx is used, all previously set socket options and 350 * property are not enabled and to enable them 351 * SO_UPDATE_CONNECT_CONTEXT option need to be set. */ 352 if (setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 353 0) != 0) { 354 err = WSAGetLastError(); 355 PR_LOG(_pr_io_lm, PR_LOG_MIN, 356 ("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT " 357 "failed %d\n", 358 err)); 359 _PR_MD_MAP_SETSOCKOPT_ERROR(err); 360 return PR_FAILURE; 361 } 362 return PR_SUCCESS; 363 } else { 364 err = WSAGetLastError(); 365 PR_LOG(_pr_io_lm, PR_LOG_MIN, 366 ("SocketConnectContinue GetOverlappedResult failed %d\n", err)); 367 if (err != ERROR_IO_INCOMPLETE) { 368 _PR_MD_MAP_CONNECT_ERROR(err); 369 fd->secret->overlappedActive = PR_FALSE; 370 return PR_FAILURE; 371 } else { 372 PR_SetError(PR_IN_PROGRESS_ERROR, 0); 373 return PR_FAILURE; 374 } 375 } 376 } 377 # endif 378 379 return PR_SUCCESS; 380 381 #else 382 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 383 return PR_FAILURE; 384 #endif 385 } 386 387 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc* pd) { 388 /* Find the NSPR layer and invoke its connectcontinue method */ 389 PRFileDesc* bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 390 391 if (NULL == bottom) { 392 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 393 return PR_FAILURE; 394 } 395 return SocketConnectContinue(bottom, pd->out_flags); 396 } 397 398 static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc* fd, PRNetAddr* addr, 399 PRIntervalTime timeout) { 400 PROsfd osfd; 401 PRFileDesc* fd2; 402 PRUint32 al; 403 PRThread* me = _PR_MD_CURRENT_THREAD(); 404 #ifdef WINNT 405 PRNetAddr addrCopy; 406 #endif 407 408 if (_PR_PENDING_INTERRUPT(me)) { 409 me->flags &= ~_PR_INTERRUPT; 410 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 411 return 0; 412 } 413 if (_PR_IO_PENDING(me)) { 414 PR_SetError(PR_IO_PENDING_ERROR, 0); 415 return 0; 416 } 417 418 #ifdef WINNT 419 if (addr == NULL) { 420 addr = &addrCopy; 421 } 422 #endif 423 al = sizeof(PRNetAddr); 424 osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout); 425 if (osfd == -1) { 426 return 0; 427 } 428 429 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); 430 if (!fd2) { 431 _PR_MD_CLOSE_SOCKET(osfd); 432 return NULL; 433 } 434 435 fd2->secret->nonblocking = fd->secret->nonblocking; 436 fd2->secret->inheritable = fd->secret->inheritable; 437 #ifdef WINNT 438 if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) { 439 /* 440 * The new socket has been associated with an I/O 441 * completion port. There is no going back. 442 */ 443 fd2->secret->md.io_model_committed = PR_TRUE; 444 } 445 PR_ASSERT(al == PR_NETADDR_SIZE(addr)); 446 fd2->secret->md.accepted_socket = PR_TRUE; 447 memcpy(&fd2->secret->md.peer_addr, addr, al); 448 #endif 449 450 /* 451 * On some platforms, the new socket created by accept() 452 * inherits the nonblocking (or overlapped io) attribute 453 * of the listening socket. As an optimization, these 454 * platforms can skip the following _PR_MD_MAKE_NONBLOCK 455 * call. 456 */ 457 #if !defined(SOLARIS) && !defined(WINNT) 458 _PR_MD_MAKE_NONBLOCK(fd2); 459 #endif 460 461 #ifdef _PR_INET6 462 if (addr && (AF_INET6 == addr->raw.family)) { 463 addr->raw.family = PR_AF_INET6; 464 } 465 #endif 466 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 467 PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE); 468 469 return fd2; 470 } 471 472 #ifdef WINNT 473 PR_IMPLEMENT(PRFileDesc*) 474 PR_NTFast_Accept(PRFileDesc* fd, PRNetAddr* addr, PRIntervalTime timeout) { 475 PROsfd osfd; 476 PRFileDesc* fd2; 477 PRIntn al; 478 PRThread* me = _PR_MD_CURRENT_THREAD(); 479 PRNetAddr addrCopy; 480 481 if (_PR_PENDING_INTERRUPT(me)) { 482 me->flags &= ~_PR_INTERRUPT; 483 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 484 return 0; 485 } 486 if (_PR_IO_PENDING(me)) { 487 PR_SetError(PR_IO_PENDING_ERROR, 0); 488 return 0; 489 } 490 491 if (addr == NULL) { 492 addr = &addrCopy; 493 } 494 al = PR_NETADDR_SIZE(addr); 495 osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL); 496 if (osfd == -1) { 497 return 0; 498 } 499 500 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); 501 if (!fd2) { 502 _PR_MD_CLOSE_SOCKET(osfd); 503 } else { 504 fd2->secret->nonblocking = fd->secret->nonblocking; 505 fd2->secret->md.io_model_committed = PR_TRUE; 506 PR_ASSERT(al == PR_NETADDR_SIZE(addr)); 507 fd2->secret->md.accepted_socket = PR_TRUE; 508 memcpy(&fd2->secret->md.peer_addr, addr, al); 509 # ifdef _PR_INET6 510 if (AF_INET6 == addr->raw.family) { 511 addr->raw.family = PR_AF_INET6; 512 } 513 # endif 514 # ifdef _PR_NEED_SECRET_AF 515 fd2->secret->af = fd->secret->af; 516 # endif 517 } 518 return fd2; 519 } 520 #endif /* WINNT */ 521 522 static PRStatus PR_CALLBACK SocketBind(PRFileDesc* fd, const PRNetAddr* addr) { 523 PRInt32 result; 524 const PRNetAddr* addrp = addr; 525 #if defined(_PR_INET6) 526 PRNetAddr addrCopy; 527 #endif 528 529 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 530 531 #ifdef XP_UNIX 532 if (addr->raw.family == AF_UNIX) { 533 /* Disallow relative pathnames */ 534 if (addr->local.path[0] != '/') { 535 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 536 return PR_FAILURE; 537 } 538 } 539 #endif /* XP_UNIX */ 540 541 #if defined(_PR_INET6) 542 if (addr->raw.family == PR_AF_INET6) { 543 addrCopy = *addr; 544 addrCopy.raw.family = AF_INET6; 545 addrp = &addrCopy; 546 } 547 #endif 548 result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr)); 549 if (result < 0) { 550 return PR_FAILURE; 551 } 552 return PR_SUCCESS; 553 } 554 555 static PRStatus PR_CALLBACK SocketListen(PRFileDesc* fd, PRIntn backlog) { 556 PRInt32 result; 557 558 result = _PR_MD_LISTEN(fd, backlog); 559 if (result < 0) { 560 return PR_FAILURE; 561 } 562 return PR_SUCCESS; 563 } 564 565 static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc* fd, PRIntn how) { 566 PRInt32 result; 567 568 result = _PR_MD_SHUTDOWN(fd, how); 569 if (result < 0) { 570 return PR_FAILURE; 571 } 572 return PR_SUCCESS; 573 } 574 575 static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc* fd, void* buf, PRInt32 amount, 576 PRIntn flags, PRIntervalTime timeout) { 577 PRInt32 rv; 578 PRThread* me = _PR_MD_CURRENT_THREAD(); 579 580 if ((flags != 0) && (flags != PR_MSG_PEEK)) { 581 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 582 return -1; 583 } 584 if (_PR_PENDING_INTERRUPT(me)) { 585 me->flags &= ~_PR_INTERRUPT; 586 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 587 return -1; 588 } 589 if (_PR_IO_PENDING(me)) { 590 PR_SetError(PR_IO_PENDING_ERROR, 0); 591 return -1; 592 } 593 594 PR_LOG(_pr_io_lm, PR_LOG_MAX, 595 ("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d", fd, 596 fd->secret->md.osfd, buf, amount, flags)); 597 598 #ifdef _PR_HAVE_PEEK_BUFFER 599 if (fd->secret->peekBytes != 0) { 600 rv = (amount < fd->secret->peekBytes) ? amount : fd->secret->peekBytes; 601 memcpy(buf, fd->secret->peekBuffer, rv); 602 if (flags == 0) { 603 /* consume the bytes in the peek buffer */ 604 fd->secret->peekBytes -= rv; 605 if (fd->secret->peekBytes != 0) { 606 memmove(fd->secret->peekBuffer, fd->secret->peekBuffer + rv, 607 fd->secret->peekBytes); 608 } 609 } 610 return rv; 611 } 612 613 /* allocate peek buffer, if necessary */ 614 if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { 615 PR_ASSERT(0 == fd->secret->peekBytes); 616 /* impose a max size on the peek buffer */ 617 if (amount > _PR_PEEK_BUFFER_MAX) { 618 amount = _PR_PEEK_BUFFER_MAX; 619 } 620 if (fd->secret->peekBufSize < amount) { 621 if (fd->secret->peekBuffer) { 622 PR_Free(fd->secret->peekBuffer); 623 } 624 fd->secret->peekBufSize = amount; 625 fd->secret->peekBuffer = PR_Malloc(amount); 626 if (NULL == fd->secret->peekBuffer) { 627 fd->secret->peekBufSize = 0; 628 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 629 return -1; 630 } 631 } 632 } 633 #endif 634 635 rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); 636 PR_LOG(_pr_io_lm, PR_LOG_MAX, 637 ("recv -> %d, error = %d, os error = %d", rv, PR_GetError(), 638 PR_GetOSError())); 639 640 #ifdef _PR_HAVE_PEEK_BUFFER 641 if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { 642 if (rv > 0) { 643 memcpy(fd->secret->peekBuffer, buf, rv); 644 fd->secret->peekBytes = rv; 645 } 646 } 647 #endif 648 649 return rv; 650 } 651 652 static PRInt32 PR_CALLBACK SocketRead(PRFileDesc* fd, void* buf, 653 PRInt32 amount) { 654 return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); 655 } 656 657 static PRInt32 PR_CALLBACK SocketSend(PRFileDesc* fd, const void* buf, 658 PRInt32 amount, PRIntn flags, 659 PRIntervalTime timeout) { 660 PRInt32 temp, count; 661 PRThread* me = _PR_MD_CURRENT_THREAD(); 662 663 if (_PR_PENDING_INTERRUPT(me)) { 664 me->flags &= ~_PR_INTERRUPT; 665 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 666 return -1; 667 } 668 if (_PR_IO_PENDING(me)) { 669 PR_SetError(PR_IO_PENDING_ERROR, 0); 670 return -1; 671 } 672 673 count = 0; 674 while (amount > 0) { 675 PR_LOG(_pr_io_lm, PR_LOG_MAX, 676 ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d", fd, 677 fd->secret->md.osfd, buf, amount)); 678 temp = _PR_MD_SEND(fd, buf, amount, flags, timeout); 679 if (temp < 0) { 680 count = -1; 681 break; 682 } 683 684 count += temp; 685 if (fd->secret->nonblocking) { 686 break; 687 } 688 buf = (const void*)((const char*)buf + temp); 689 690 amount -= temp; 691 } 692 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count)); 693 return count; 694 } 695 696 static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc* fd, const void* buf, 697 PRInt32 amount) { 698 return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); 699 } 700 701 static PRStatus PR_CALLBACK SocketClose(PRFileDesc* fd) { 702 if (!fd || !fd->secret || 703 (fd->secret->state != _PR_FILEDESC_OPEN && 704 fd->secret->state != _PR_FILEDESC_CLOSED)) { 705 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 706 return PR_FAILURE; 707 } 708 709 if (fd->secret->state == _PR_FILEDESC_OPEN) { 710 #if defined(_WIN64) && defined(WIN95) 711 /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped 712 * input/output. Before closing such a socket we must cancelIO. 713 */ 714 if (fd->secret->overlappedActive) { 715 PR_ASSERT(fd->secret->nonblocking); 716 if (CancelIo((HANDLE)fd->secret->md.osfd) == TRUE) { 717 PR_LOG(_pr_io_lm, PR_LOG_MIN, ("SocketClose - CancelIo succeeded\n")); 718 } else { 719 DWORD err = WSAGetLastError(); 720 PR_LOG(_pr_io_lm, PR_LOG_MIN, 721 ("SocketClose - CancelIo failed err=%x\n", err)); 722 } 723 724 DWORD rvSent; 725 if (GetOverlappedResult((HANDLE)fd->secret->md.osfd, &fd->secret->ol, 726 &rvSent, FALSE) == TRUE) { 727 fd->secret->overlappedActive = PR_FALSE; 728 PR_LOG(_pr_io_lm, PR_LOG_MIN, 729 ("SocketClose GetOverlappedResult succeeded\n")); 730 } else { 731 DWORD err = WSAGetLastError(); 732 PR_LOG(_pr_io_lm, PR_LOG_MIN, 733 ("SocketClose GetOverlappedResult failed %d\n", err)); 734 if (err != ERROR_IO_INCOMPLETE) { 735 _PR_MD_MAP_CONNECT_ERROR(err); 736 fd->secret->overlappedActive = PR_FALSE; 737 } 738 } 739 } 740 741 if (fd->secret->overlappedActive && _fd_waiting_for_overlapped_done_lock) { 742 // Put osfd into the list to be checked later. 743 PRFileDescList* forWaiting = PR_NEW(PRFileDescList); 744 if (!forWaiting) { 745 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 746 return PR_FAILURE; 747 } 748 forWaiting->fd = fd; 749 750 PR_Lock(_fd_waiting_for_overlapped_done_lock); 751 forWaiting->next = _fd_waiting_for_overlapped_done; 752 _fd_waiting_for_overlapped_done = forWaiting; 753 PR_Unlock(_fd_waiting_for_overlapped_done_lock); 754 755 return PR_SUCCESS; 756 } 757 #endif 758 759 if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) { 760 return PR_FAILURE; 761 } 762 fd->secret->state = _PR_FILEDESC_CLOSED; 763 } 764 765 #ifdef _PR_HAVE_PEEK_BUFFER 766 if (fd->secret->peekBuffer) { 767 PR_ASSERT(fd->secret->peekBufSize > 0); 768 PR_DELETE(fd->secret->peekBuffer); 769 fd->secret->peekBufSize = 0; 770 fd->secret->peekBytes = 0; 771 } 772 #endif 773 774 PR_FreeFileDesc(fd); 775 return PR_SUCCESS; 776 } 777 778 static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc* fd) { 779 PRInt32 rv; 780 #ifdef _PR_HAVE_PEEK_BUFFER 781 if (fd->secret->peekBytes != 0) { 782 return fd->secret->peekBytes; 783 } 784 #endif 785 rv = _PR_MD_SOCKETAVAILABLE(fd); 786 return rv; 787 } 788 789 static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc* fd) { 790 PRInt64 rv; 791 #ifdef _PR_HAVE_PEEK_BUFFER 792 if (fd->secret->peekBytes != 0) { 793 LL_I2L(rv, fd->secret->peekBytes); 794 return rv; 795 } 796 #endif 797 LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd)); 798 return rv; 799 } 800 801 static PRStatus PR_CALLBACK SocketSync(PRFileDesc* fd) { return PR_SUCCESS; } 802 803 static PRInt32 PR_CALLBACK SocketSendTo(PRFileDesc* fd, const void* buf, 804 PRInt32 amount, PRIntn flags, 805 const PRNetAddr* addr, 806 PRIntervalTime timeout) { 807 PRInt32 temp, count; 808 const PRNetAddr* addrp = addr; 809 #if defined(_PR_INET6) 810 PRNetAddr addrCopy; 811 #endif 812 PRThread* me = _PR_MD_CURRENT_THREAD(); 813 814 if (_PR_PENDING_INTERRUPT(me)) { 815 me->flags &= ~_PR_INTERRUPT; 816 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 817 return -1; 818 } 819 if (_PR_IO_PENDING(me)) { 820 PR_SetError(PR_IO_PENDING_ERROR, 0); 821 return -1; 822 } 823 824 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 825 #if defined(_PR_INET6) 826 if (addr->raw.family == PR_AF_INET6) { 827 addrCopy = *addr; 828 addrCopy.raw.family = AF_INET6; 829 addrp = &addrCopy; 830 } 831 #endif 832 833 count = 0; 834 do { 835 temp = _PR_MD_SENDTO(fd, buf, amount, flags, addrp, PR_NETADDR_SIZE(addr), 836 timeout); 837 if (temp < 0) { 838 count = -1; 839 break; 840 } 841 count += temp; 842 if (fd->secret->nonblocking) { 843 break; 844 } 845 buf = (const void*)((const char*)buf + temp); 846 amount -= temp; 847 } while (amount > 0); 848 return count; 849 } 850 851 #if defined(_WIN64) && defined(WIN95) 852 static PRInt32 PR_CALLBACK SocketTCPSendTo(PRFileDesc* fd, const void* buf, 853 PRInt32 amount, PRIntn flags, 854 const PRNetAddr* addr, 855 PRIntervalTime timeout) { 856 PRInt32 temp, count; 857 const PRNetAddr* addrp = addr; 858 # if defined(_PR_INET6) 859 PRNetAddr addrCopy; 860 # endif 861 PRThread* me = _PR_MD_CURRENT_THREAD(); 862 863 if (_PR_PENDING_INTERRUPT(me)) { 864 me->flags &= ~_PR_INTERRUPT; 865 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 866 return -1; 867 } 868 if (_PR_IO_PENDING(me)) { 869 PR_SetError(PR_IO_PENDING_ERROR, 0); 870 return -1; 871 } 872 873 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 874 # if defined(_PR_INET6) 875 if (addr->raw.family == PR_AF_INET6) { 876 addrCopy = *addr; 877 addrCopy.raw.family = AF_INET6; 878 addrp = &addrCopy; 879 } 880 # endif 881 882 count = 0; 883 while (amount > 0) { 884 temp = _PR_MD_TCPSENDTO(fd, buf, amount, flags, addrp, 885 PR_NETADDR_SIZE(addr), timeout); 886 if (temp < 0) { 887 count = -1; 888 break; 889 } 890 count += temp; 891 if (fd->secret->nonblocking) { 892 break; 893 } 894 buf = (const void*)((const char*)buf + temp); 895 amount -= temp; 896 } 897 return count; 898 } 899 #endif 900 901 static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc* fd, void* buf, 902 PRInt32 amount, PRIntn flags, 903 PRNetAddr* addr, 904 PRIntervalTime timeout) { 905 PRInt32 rv; 906 PRUint32 al; 907 PRThread* me = _PR_MD_CURRENT_THREAD(); 908 909 if (_PR_PENDING_INTERRUPT(me)) { 910 me->flags &= ~_PR_INTERRUPT; 911 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 912 return -1; 913 } 914 if (_PR_IO_PENDING(me)) { 915 PR_SetError(PR_IO_PENDING_ERROR, 0); 916 return -1; 917 } 918 919 al = sizeof(PRNetAddr); 920 rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout); 921 #ifdef _PR_INET6 922 if (addr && (AF_INET6 == addr->raw.family)) { 923 addr->raw.family = PR_AF_INET6; 924 } 925 #endif 926 return rv; 927 } 928 929 static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc* sd, PRFileDesc** nd, 930 PRNetAddr** raddr, void* buf, 931 PRInt32 amount, 932 PRIntervalTime timeout) { 933 PRInt32 rv; 934 PRThread* me = _PR_MD_CURRENT_THREAD(); 935 936 if (_PR_PENDING_INTERRUPT(me)) { 937 me->flags &= ~_PR_INTERRUPT; 938 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 939 return -1; 940 } 941 if (_PR_IO_PENDING(me)) { 942 PR_SetError(PR_IO_PENDING_ERROR, 0); 943 return -1; 944 } 945 /* The socket must be in blocking mode. */ 946 if (sd->secret->nonblocking) { 947 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 948 return -1; 949 } 950 *nd = NULL; 951 952 #if defined(WINNT) 953 { 954 PROsfd newSock; 955 PRNetAddr* raddrCopy; 956 957 if (raddr == NULL) { 958 raddr = &raddrCopy; 959 } 960 rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout); 961 if (rv < 0) { 962 rv = -1; 963 } else { 964 /* Successfully accepted and read; create the new PRFileDesc */ 965 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); 966 if (*nd == 0) { 967 _PR_MD_CLOSE_SOCKET(newSock); 968 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 969 rv = -1; 970 } else { 971 (*nd)->secret->md.io_model_committed = PR_TRUE; 972 (*nd)->secret->md.accepted_socket = PR_TRUE; 973 memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr)); 974 # ifdef _PR_INET6 975 if (AF_INET6 == *raddr->raw.family) { 976 *raddr->raw.family = PR_AF_INET6; 977 } 978 # endif 979 } 980 } 981 } 982 #else 983 rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); 984 #endif 985 return rv; 986 } 987 988 #ifdef WINNT 989 PR_IMPLEMENT(PRInt32) 990 PR_NTFast_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr, 991 void* buf, PRInt32 amount, PRIntervalTime timeout) { 992 PRInt32 rv; 993 PROsfd newSock; 994 PRThread* me = _PR_MD_CURRENT_THREAD(); 995 PRNetAddr* raddrCopy; 996 997 if (_PR_PENDING_INTERRUPT(me)) { 998 me->flags &= ~_PR_INTERRUPT; 999 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1000 return -1; 1001 } 1002 if (_PR_IO_PENDING(me)) { 1003 PR_SetError(PR_IO_PENDING_ERROR, 0); 1004 return -1; 1005 } 1006 *nd = NULL; 1007 1008 if (raddr == NULL) { 1009 raddr = &raddrCopy; 1010 } 1011 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout, 1012 PR_TRUE, NULL, NULL); 1013 if (rv < 0) { 1014 rv = -1; 1015 } else { 1016 /* Successfully accepted and read; create the new PRFileDesc */ 1017 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); 1018 if (*nd == 0) { 1019 _PR_MD_CLOSE_SOCKET(newSock); 1020 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1021 rv = -1; 1022 } else { 1023 (*nd)->secret->md.io_model_committed = PR_TRUE; 1024 (*nd)->secret->md.accepted_socket = PR_TRUE; 1025 memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr)); 1026 # ifdef _PR_INET6 1027 if (AF_INET6 == *raddr->raw.family) { 1028 *raddr->raw.family = PR_AF_INET6; 1029 } 1030 # endif 1031 # ifdef _PR_NEED_SECRET_AF 1032 (*nd)->secret->af = sd->secret->af; 1033 # endif 1034 } 1035 } 1036 return rv; 1037 } 1038 1039 PR_IMPLEMENT(PRInt32) 1040 PR_NTFast_AcceptRead_WithTimeoutCallback(PRFileDesc* sd, PRFileDesc** nd, 1041 PRNetAddr** raddr, void* buf, 1042 PRInt32 amount, PRIntervalTime timeout, 1043 _PR_AcceptTimeoutCallback callback, 1044 void* callbackArg) { 1045 PRInt32 rv; 1046 PROsfd newSock; 1047 PRThread* me = _PR_MD_CURRENT_THREAD(); 1048 PRNetAddr* raddrCopy; 1049 1050 if (_PR_PENDING_INTERRUPT(me)) { 1051 me->flags &= ~_PR_INTERRUPT; 1052 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1053 return -1; 1054 } 1055 if (_PR_IO_PENDING(me)) { 1056 PR_SetError(PR_IO_PENDING_ERROR, 0); 1057 return -1; 1058 } 1059 *nd = NULL; 1060 1061 if (raddr == NULL) { 1062 raddr = &raddrCopy; 1063 } 1064 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout, 1065 PR_TRUE, callback, callbackArg); 1066 if (rv < 0) { 1067 rv = -1; 1068 } else { 1069 /* Successfully accepted and read; create the new PRFileDesc */ 1070 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); 1071 if (*nd == 0) { 1072 _PR_MD_CLOSE_SOCKET(newSock); 1073 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1074 rv = -1; 1075 } else { 1076 (*nd)->secret->md.io_model_committed = PR_TRUE; 1077 (*nd)->secret->md.accepted_socket = PR_TRUE; 1078 memcpy(&(*nd)->secret->md.peer_addr, *raddr, PR_NETADDR_SIZE(*raddr)); 1079 # ifdef _PR_INET6 1080 if (AF_INET6 == *raddr->raw.family) { 1081 *raddr->raw.family = PR_AF_INET6; 1082 } 1083 # endif 1084 # ifdef _PR_NEED_SECRET_AF 1085 (*nd)->secret->af = sd->secret->af; 1086 # endif 1087 } 1088 } 1089 return rv; 1090 } 1091 #endif /* WINNT */ 1092 1093 #ifdef WINNT 1094 PR_IMPLEMENT(void) 1095 PR_NTFast_UpdateAcceptContext(PRFileDesc* socket, PRFileDesc* acceptSocket) { 1096 _PR_MD_UPDATE_ACCEPT_CONTEXT(socket->secret->md.osfd, 1097 acceptSocket->secret->md.osfd); 1098 } 1099 #endif /* WINNT */ 1100 1101 static PRInt32 PR_CALLBACK SocketSendFile(PRFileDesc* sd, PRSendFileData* sfd, 1102 PRTransmitFileFlags flags, 1103 PRIntervalTime timeout) { 1104 PRInt32 rv; 1105 PRThread* me = _PR_MD_CURRENT_THREAD(); 1106 1107 if (_PR_PENDING_INTERRUPT(me)) { 1108 me->flags &= ~_PR_INTERRUPT; 1109 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1110 return -1; 1111 } 1112 if (_PR_IO_PENDING(me)) { 1113 PR_SetError(PR_IO_PENDING_ERROR, 0); 1114 return -1; 1115 } 1116 /* The socket must be in blocking mode. */ 1117 if (sd->secret->nonblocking) { 1118 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1119 return -1; 1120 } 1121 #if defined(WINNT) 1122 rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout); 1123 if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { 1124 /* 1125 * This should be kept the same as SocketClose, except 1126 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should 1127 * not be called because the socket will be recycled. 1128 */ 1129 PR_FreeFileDesc(sd); 1130 } 1131 #else 1132 rv = PR_EmulateSendFile(sd, sfd, flags, timeout); 1133 #endif /* WINNT */ 1134 1135 return rv; 1136 } 1137 1138 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc* sd, PRFileDesc* fd, 1139 const void* headers, PRInt32 hlen, 1140 PRTransmitFileFlags flags, 1141 PRIntervalTime timeout) { 1142 PRSendFileData sfd; 1143 1144 sfd.fd = fd; 1145 sfd.file_offset = 0; 1146 sfd.file_nbytes = 0; 1147 sfd.header = headers; 1148 sfd.hlen = hlen; 1149 sfd.trailer = NULL; 1150 sfd.tlen = 0; 1151 1152 return (SocketSendFile(sd, &sfd, flags, timeout)); 1153 } 1154 1155 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc* fd, PRNetAddr* addr) { 1156 PRInt32 result; 1157 PRUint32 addrlen; 1158 1159 addrlen = sizeof(PRNetAddr); 1160 result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen); 1161 if (result < 0) { 1162 return PR_FAILURE; 1163 } 1164 #ifdef _PR_INET6 1165 if (AF_INET6 == addr->raw.family) { 1166 addr->raw.family = PR_AF_INET6; 1167 } 1168 #endif 1169 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1170 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); 1171 return PR_SUCCESS; 1172 } 1173 1174 static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc* fd, PRNetAddr* addr) { 1175 PRInt32 result; 1176 PRUint32 addrlen; 1177 1178 addrlen = sizeof(PRNetAddr); 1179 result = _PR_MD_GETPEERNAME(fd, addr, &addrlen); 1180 if (result < 0) { 1181 return PR_FAILURE; 1182 } 1183 #ifdef _PR_INET6 1184 if (AF_INET6 == addr->raw.family) { 1185 addr->raw.family = PR_AF_INET6; 1186 } 1187 #endif 1188 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1189 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); 1190 return PR_SUCCESS; 1191 } 1192 1193 static PRInt16 PR_CALLBACK SocketPoll(PRFileDesc* fd, PRInt16 in_flags, 1194 PRInt16* out_flags) { 1195 *out_flags = 0; 1196 1197 #if defined(_WIN64) 1198 if (in_flags & PR_POLL_WRITE) { 1199 if (fd->secret->alreadyConnected) { 1200 *out_flags = PR_POLL_WRITE; 1201 return PR_POLL_WRITE; 1202 } 1203 } 1204 #endif 1205 return in_flags; 1206 } /* SocketPoll */ 1207 1208 static PRIOMethods tcpMethods = { 1209 PR_DESC_SOCKET_TCP, 1210 SocketClose, 1211 SocketRead, 1212 SocketWrite, 1213 SocketAvailable, 1214 SocketAvailable64, 1215 SocketSync, 1216 (PRSeekFN)_PR_InvalidInt, 1217 (PRSeek64FN)_PR_InvalidInt64, 1218 (PRFileInfoFN)_PR_InvalidStatus, 1219 (PRFileInfo64FN)_PR_InvalidStatus, 1220 SocketWritev, 1221 SocketConnect, 1222 SocketAccept, 1223 SocketBind, 1224 SocketListen, 1225 SocketShutdown, 1226 SocketRecv, 1227 SocketSend, 1228 (PRRecvfromFN)_PR_InvalidInt, 1229 #if defined(_WIN64) && defined(WIN95) 1230 SocketTCPSendTo, /* This is for fast open. We imitate Linux interface. */ 1231 #else 1232 (PRSendtoFN)_PR_InvalidInt, 1233 #endif 1234 SocketPoll, 1235 SocketAcceptRead, 1236 SocketTransmitFile, 1237 SocketGetName, 1238 SocketGetPeerName, 1239 (PRReservedFN)_PR_InvalidInt, 1240 (PRReservedFN)_PR_InvalidInt, 1241 _PR_SocketGetSocketOption, 1242 _PR_SocketSetSocketOption, 1243 SocketSendFile, 1244 SocketConnectContinue, 1245 (PRReservedFN)_PR_InvalidInt, 1246 (PRReservedFN)_PR_InvalidInt, 1247 (PRReservedFN)_PR_InvalidInt, 1248 (PRReservedFN)_PR_InvalidInt}; 1249 1250 static PRIOMethods udpMethods = {PR_DESC_SOCKET_UDP, 1251 SocketClose, 1252 SocketRead, 1253 SocketWrite, 1254 SocketAvailable, 1255 SocketAvailable64, 1256 SocketSync, 1257 (PRSeekFN)_PR_InvalidInt, 1258 (PRSeek64FN)_PR_InvalidInt64, 1259 (PRFileInfoFN)_PR_InvalidStatus, 1260 (PRFileInfo64FN)_PR_InvalidStatus, 1261 SocketWritev, 1262 SocketConnect, 1263 (PRAcceptFN)_PR_InvalidDesc, 1264 SocketBind, 1265 SocketListen, 1266 SocketShutdown, 1267 SocketRecv, 1268 SocketSend, 1269 SocketRecvFrom, 1270 SocketSendTo, 1271 SocketPoll, 1272 (PRAcceptreadFN)_PR_InvalidInt, 1273 (PRTransmitfileFN)_PR_InvalidInt, 1274 SocketGetName, 1275 SocketGetPeerName, 1276 (PRReservedFN)_PR_InvalidInt, 1277 (PRReservedFN)_PR_InvalidInt, 1278 _PR_SocketGetSocketOption, 1279 _PR_SocketSetSocketOption, 1280 (PRSendfileFN)_PR_InvalidInt, 1281 (PRConnectcontinueFN)_PR_InvalidStatus, 1282 (PRReservedFN)_PR_InvalidInt, 1283 (PRReservedFN)_PR_InvalidInt, 1284 (PRReservedFN)_PR_InvalidInt, 1285 (PRReservedFN)_PR_InvalidInt}; 1286 1287 static PRIOMethods socketpollfdMethods = { 1288 (PRDescType)0, 1289 (PRCloseFN)_PR_InvalidStatus, 1290 (PRReadFN)_PR_InvalidInt, 1291 (PRWriteFN)_PR_InvalidInt, 1292 (PRAvailableFN)_PR_InvalidInt, 1293 (PRAvailable64FN)_PR_InvalidInt64, 1294 (PRFsyncFN)_PR_InvalidStatus, 1295 (PRSeekFN)_PR_InvalidInt, 1296 (PRSeek64FN)_PR_InvalidInt64, 1297 (PRFileInfoFN)_PR_InvalidStatus, 1298 (PRFileInfo64FN)_PR_InvalidStatus, 1299 (PRWritevFN)_PR_InvalidInt, 1300 (PRConnectFN)_PR_InvalidStatus, 1301 (PRAcceptFN)_PR_InvalidDesc, 1302 (PRBindFN)_PR_InvalidStatus, 1303 (PRListenFN)_PR_InvalidStatus, 1304 (PRShutdownFN)_PR_InvalidStatus, 1305 (PRRecvFN)_PR_InvalidInt, 1306 (PRSendFN)_PR_InvalidInt, 1307 (PRRecvfromFN)_PR_InvalidInt, 1308 (PRSendtoFN)_PR_InvalidInt, 1309 SocketPoll, 1310 (PRAcceptreadFN)_PR_InvalidInt, 1311 (PRTransmitfileFN)_PR_InvalidInt, 1312 (PRGetsocknameFN)_PR_InvalidStatus, 1313 (PRGetpeernameFN)_PR_InvalidStatus, 1314 (PRReservedFN)_PR_InvalidInt, 1315 (PRReservedFN)_PR_InvalidInt, 1316 (PRGetsocketoptionFN)_PR_InvalidStatus, 1317 (PRSetsocketoptionFN)_PR_InvalidStatus, 1318 (PRSendfileFN)_PR_InvalidInt, 1319 (PRConnectcontinueFN)_PR_InvalidStatus, 1320 (PRReservedFN)_PR_InvalidInt, 1321 (PRReservedFN)_PR_InvalidInt, 1322 (PRReservedFN)_PR_InvalidInt, 1323 (PRReservedFN)_PR_InvalidInt}; 1324 1325 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods() { return &tcpMethods; } 1326 1327 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() { return &udpMethods; } 1328 1329 static const PRIOMethods* PR_GetSocketPollFdMethods() { 1330 return &socketpollfdMethods; 1331 } /* PR_GetSocketPollFdMethods */ 1332 1333 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) 1334 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd); 1335 1336 # if defined(_PR_INET6_PROBE) 1337 1338 extern PRBool _pr_ipv6_is_present(void); 1339 1340 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() { 1341 PROsfd osfd; 1342 1343 osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0); 1344 if (osfd != -1) { 1345 _PR_MD_CLOSE_SOCKET(osfd); 1346 return PR_TRUE; 1347 } 1348 return PR_FALSE; 1349 } 1350 # endif /* _PR_INET6_PROBE */ 1351 1352 #endif 1353 1354 PR_IMPLEMENT(PRFileDesc*) 1355 PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) { 1356 PROsfd osfd; 1357 PRFileDesc* fd; 1358 PRInt32 tmp_domain = domain; 1359 1360 if (!_pr_initialized) { 1361 _PR_ImplicitInitialization(); 1362 } 1363 if (PR_AF_INET != domain && PR_AF_INET6 != domain 1364 #if defined(XP_UNIX) 1365 && PR_AF_LOCAL != domain 1366 #endif 1367 ) { 1368 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 1369 return NULL; 1370 } 1371 1372 #if defined(_PR_INET6_PROBE) 1373 if (PR_AF_INET6 == domain) { 1374 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; 1375 } 1376 #elif defined(_PR_INET6) 1377 if (PR_AF_INET6 == domain) { 1378 domain = AF_INET6; 1379 } 1380 #else 1381 if (PR_AF_INET6 == domain) { 1382 domain = AF_INET; 1383 } 1384 #endif /* _PR_INET6 */ 1385 osfd = _PR_MD_SOCKET(domain, type, proto); 1386 if (osfd == -1) { 1387 return 0; 1388 } 1389 if (type == SOCK_STREAM) { 1390 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); 1391 } else { 1392 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); 1393 } 1394 /* 1395 * Make the sockets non-blocking 1396 */ 1397 if (fd != NULL) { 1398 _PR_MD_MAKE_NONBLOCK(fd); 1399 _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); 1400 #ifdef _PR_NEED_SECRET_AF 1401 fd->secret->af = domain; 1402 #endif 1403 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) 1404 /* 1405 * For platforms with no support for IPv6 1406 * create layered socket for IPv4-mapped IPv6 addresses 1407 */ 1408 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { 1409 if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { 1410 PR_Close(fd); 1411 fd = NULL; 1412 } 1413 } 1414 #endif 1415 } else { 1416 _PR_MD_CLOSE_SOCKET(osfd); 1417 } 1418 1419 return fd; 1420 } 1421 1422 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) { 1423 PRInt32 domain = AF_INET; 1424 1425 return PR_Socket(domain, SOCK_STREAM, 0); 1426 } 1427 1428 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) { 1429 PRInt32 domain = AF_INET; 1430 1431 return PR_Socket(domain, SOCK_DGRAM, 0); 1432 } 1433 1434 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) { 1435 return PR_Socket(af, SOCK_STREAM, 0); 1436 } 1437 1438 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) { 1439 return PR_Socket(af, SOCK_DGRAM, 0); 1440 } 1441 1442 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc* f[]) { 1443 #ifdef XP_UNIX 1444 PRInt32 rv, osfd[2]; 1445 1446 if (!_pr_initialized) { 1447 _PR_ImplicitInitialization(); 1448 } 1449 1450 rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd); 1451 if (rv == -1) { 1452 return PR_FAILURE; 1453 } 1454 1455 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); 1456 if (!f[0]) { 1457 _PR_MD_CLOSE_SOCKET(osfd[0]); 1458 _PR_MD_CLOSE_SOCKET(osfd[1]); 1459 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1460 return PR_FAILURE; 1461 } 1462 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); 1463 if (!f[1]) { 1464 PR_Close(f[0]); 1465 _PR_MD_CLOSE_SOCKET(osfd[1]); 1466 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1467 return PR_FAILURE; 1468 } 1469 _PR_MD_MAKE_NONBLOCK(f[0]); 1470 _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); 1471 _PR_MD_MAKE_NONBLOCK(f[1]); 1472 _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); 1473 return PR_SUCCESS; 1474 #elif defined(WINNT) 1475 /* 1476 * A socket pair is often used for interprocess communication, 1477 * so we need to make sure neither socket is associated with 1478 * the I/O completion port; otherwise it can't be used by a 1479 * child process. 1480 * 1481 * The default implementation below cannot be used for NT 1482 * because PR_Accept would have associated the I/O completion 1483 * port with the listening and accepted sockets. 1484 */ 1485 SOCKET listenSock; 1486 SOCKET osfd[2]; 1487 struct sockaddr_in selfAddr, peerAddr; 1488 int addrLen; 1489 1490 if (!_pr_initialized) { 1491 _PR_ImplicitInitialization(); 1492 } 1493 1494 osfd[0] = osfd[1] = INVALID_SOCKET; 1495 listenSock = socket(AF_INET, SOCK_STREAM, 0); 1496 if (listenSock == INVALID_SOCKET) { 1497 goto failed; 1498 } 1499 selfAddr.sin_family = AF_INET; 1500 selfAddr.sin_port = 0; 1501 selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */ 1502 addrLen = sizeof(selfAddr); 1503 if (bind(listenSock, (struct sockaddr*)&selfAddr, addrLen) == SOCKET_ERROR) { 1504 goto failed; 1505 } 1506 if (getsockname(listenSock, (struct sockaddr*)&selfAddr, &addrLen) == 1507 SOCKET_ERROR) { 1508 goto failed; 1509 } 1510 if (listen(listenSock, 5) == SOCKET_ERROR) { 1511 goto failed; 1512 } 1513 osfd[0] = socket(AF_INET, SOCK_STREAM, 0); 1514 if (osfd[0] == INVALID_SOCKET) { 1515 goto failed; 1516 } 1517 selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1518 1519 /* 1520 * Only a thread is used to do the connect and accept. 1521 * I am relying on the fact that connect returns 1522 * successfully as soon as the connect request is put 1523 * into the listen queue (but before accept is called). 1524 * This is the behavior of the BSD socket code. If 1525 * connect does not return until accept is called, we 1526 * will need to create another thread to call connect. 1527 */ 1528 if (connect(osfd[0], (struct sockaddr*)&selfAddr, addrLen) == SOCKET_ERROR) { 1529 goto failed; 1530 } 1531 /* 1532 * A malicious local process may connect to the listening 1533 * socket, so we need to verify that the accepted connection 1534 * is made from our own socket osfd[0]. 1535 */ 1536 if (getsockname(osfd[0], (struct sockaddr*)&selfAddr, &addrLen) == 1537 SOCKET_ERROR) { 1538 goto failed; 1539 } 1540 osfd[1] = accept(listenSock, (struct sockaddr*)&peerAddr, &addrLen); 1541 if (osfd[1] == INVALID_SOCKET) { 1542 goto failed; 1543 } 1544 if (peerAddr.sin_port != selfAddr.sin_port) { 1545 /* the connection we accepted is not from osfd[0] */ 1546 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1547 goto failed; 1548 } 1549 closesocket(listenSock); 1550 1551 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); 1552 if (!f[0]) { 1553 closesocket(osfd[0]); 1554 closesocket(osfd[1]); 1555 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1556 return PR_FAILURE; 1557 } 1558 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); 1559 if (!f[1]) { 1560 PR_Close(f[0]); 1561 closesocket(osfd[1]); 1562 /* PR_AllocFileDesc() has invoked PR_SetError(). */ 1563 return PR_FAILURE; 1564 } 1565 _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); 1566 _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); 1567 return PR_SUCCESS; 1568 1569 failed: 1570 if (listenSock != INVALID_SOCKET) { 1571 closesocket(listenSock); 1572 } 1573 if (osfd[0] != INVALID_SOCKET) { 1574 closesocket(osfd[0]); 1575 } 1576 if (osfd[1] != INVALID_SOCKET) { 1577 closesocket(osfd[1]); 1578 } 1579 return PR_FAILURE; 1580 #else /* not Unix or NT */ 1581 /* 1582 * default implementation 1583 */ 1584 PRFileDesc* listenSock; 1585 PRNetAddr selfAddr, peerAddr; 1586 PRUint16 port; 1587 1588 f[0] = f[1] = NULL; 1589 listenSock = PR_NewTCPSocket(); 1590 if (listenSock == NULL) { 1591 goto failed; 1592 } 1593 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ 1594 if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { 1595 goto failed; 1596 } 1597 if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { 1598 goto failed; 1599 } 1600 port = ntohs(selfAddr.inet.port); 1601 if (PR_Listen(listenSock, 5) == PR_FAILURE) { 1602 goto failed; 1603 } 1604 f[0] = PR_NewTCPSocket(); 1605 if (f[0] == NULL) { 1606 goto failed; 1607 } 1608 # ifdef _PR_CONNECT_DOES_NOT_BIND 1609 /* 1610 * If connect does not implicitly bind the socket (e.g., on 1611 * BeOS), we have to bind the socket so that we can get its 1612 * port with getsockname later. 1613 */ 1614 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); 1615 if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { 1616 goto failed; 1617 } 1618 # endif 1619 PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); 1620 1621 /* 1622 * Only a thread is used to do the connect and accept. 1623 * I am relying on the fact that PR_Connect returns 1624 * successfully as soon as the connect request is put 1625 * into the listen queue (but before PR_Accept is called). 1626 * This is the behavior of the BSD socket code. If 1627 * connect does not return until accept is called, we 1628 * will need to create another thread to call connect. 1629 */ 1630 if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { 1631 goto failed; 1632 } 1633 /* 1634 * A malicious local process may connect to the listening 1635 * socket, so we need to verify that the accepted connection 1636 * is made from our own socket f[0]. 1637 */ 1638 if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { 1639 goto failed; 1640 } 1641 f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); 1642 if (f[1] == NULL) { 1643 goto failed; 1644 } 1645 if (peerAddr.inet.port != selfAddr.inet.port) { 1646 /* the connection we accepted is not from f[0] */ 1647 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1648 goto failed; 1649 } 1650 PR_Close(listenSock); 1651 return PR_SUCCESS; 1652 1653 failed: 1654 if (listenSock) { 1655 PR_Close(listenSock); 1656 } 1657 if (f[0]) { 1658 PR_Close(f[0]); 1659 } 1660 if (f[1]) { 1661 PR_Close(f[1]); 1662 } 1663 return PR_FAILURE; 1664 #endif 1665 } 1666 1667 PR_IMPLEMENT(PROsfd) 1668 PR_FileDesc2NativeHandle(PRFileDesc* fd) { 1669 if (fd) { 1670 fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); 1671 } 1672 if (!fd) { 1673 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1674 return -1; 1675 } 1676 return fd->secret->md.osfd; 1677 } 1678 1679 PR_IMPLEMENT(void) 1680 PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PROsfd handle) { 1681 if (fd) { 1682 fd->secret->md.osfd = handle; 1683 } 1684 } 1685 1686 /* 1687 ** Select compatibility 1688 ** 1689 */ 1690 1691 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set* set) { 1692 memset(set, 0, sizeof(PR_fd_set)); 1693 } 1694 1695 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc* fh, PR_fd_set* set) { 1696 PR_ASSERT(set->hsize < PR_MAX_SELECT_DESC); 1697 1698 set->harray[set->hsize++] = fh; 1699 } 1700 1701 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc* fh, PR_fd_set* set) { 1702 PRUint32 index, index2; 1703 1704 for (index = 0; index < set->hsize; index++) 1705 if (set->harray[index] == fh) { 1706 for (index2 = index; index2 < (set->hsize - 1); index2++) { 1707 set->harray[index2] = set->harray[index2 + 1]; 1708 } 1709 set->hsize--; 1710 break; 1711 } 1712 } 1713 1714 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) { 1715 PRUint32 index; 1716 for (index = 0; index < set->hsize; index++) 1717 if (set->harray[index] == fh) { 1718 return 1; 1719 } 1720 return 0; 1721 } 1722 1723 PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set* set) { 1724 PR_ASSERT(set->nsize < PR_MAX_SELECT_DESC); 1725 1726 set->narray[set->nsize++] = fd; 1727 } 1728 1729 PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set* set) { 1730 PRUint32 index, index2; 1731 1732 for (index = 0; index < set->nsize; index++) 1733 if (set->narray[index] == fd) { 1734 for (index2 = index; index2 < (set->nsize - 1); index2++) { 1735 set->narray[index2] = set->narray[index2 + 1]; 1736 } 1737 set->nsize--; 1738 break; 1739 } 1740 } 1741 1742 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set* set) { 1743 PRUint32 index; 1744 for (index = 0; index < set->nsize; index++) 1745 if (set->narray[index] == fd) { 1746 return 1; 1747 } 1748 return 0; 1749 } 1750 1751 #if !defined(NEED_SELECT) 1752 # include "obsolete/probslet.h" 1753 1754 # define PD_INCR 20 1755 1756 static PRPollDesc* _pr_setfd(PR_fd_set* set, PRInt16 flags, 1757 PRPollDesc* polldesc) { 1758 PRUintn fsidx, pdidx; 1759 PRPollDesc* poll = polldesc; 1760 1761 if (NULL == set) { 1762 return poll; 1763 } 1764 1765 /* First set the pr file handle osfds */ 1766 for (fsidx = 0; fsidx < set->hsize; fsidx++) { 1767 for (pdidx = 0; 1; pdidx++) { 1768 if ((PRFileDesc*)-1 == poll[pdidx].fd) { 1769 /* our vector is full - extend and condition it */ 1770 poll = (PRPollDesc*)PR_Realloc( 1771 poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc)); 1772 if (NULL == poll) { 1773 goto out_of_memory; 1774 } 1775 memset(poll + pdidx * sizeof(PRPollDesc), 0, 1776 PD_INCR * sizeof(PRPollDesc)); 1777 poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1; 1778 } 1779 if ((NULL == poll[pdidx].fd) || (poll[pdidx].fd == set->harray[fsidx])) { 1780 /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */ 1781 /* either empty or prevously defined */ 1782 poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */ 1783 poll[pdidx].in_flags |= flags; /* possibly redundant */ 1784 break; 1785 } 1786 } 1787 } 1788 1789 # if 0 1790 /* Second set the native osfds */ 1791 for (fsidx = 0; fsidx < set->nsize; fsidx++) 1792 { 1793 for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++) 1794 { 1795 if ((PRFileDesc*)-1 == poll[pdidx].fd) 1796 { 1797 /* our vector is full - extend and condition it */ 1798 poll = PR_Realloc( 1799 poll, (pdidx + PD_INCR) * sizeof(PRPollDesc)); 1800 if (NULL == poll) { 1801 goto out_of_memory; 1802 } 1803 memset( 1804 poll + pdidx * sizeof(PRPollDesc), 1805 0, PD_INCR * sizeof(PRPollDesc)); 1806 poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1; 1807 } 1808 if ((NULL == poll[pdidx].fd) 1809 || (poll[pdidx].fd == set->narray[fsidx])) 1810 { 1811 /* either empty or prevously defined */ 1812 poll[pdidx].fd = set->narray[fsidx]; 1813 PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); 1814 poll[pdidx].in_flags |= flags; 1815 break; 1816 } 1817 } 1818 } 1819 # endif /* 0 */ 1820 1821 return poll; 1822 1823 out_of_memory: 1824 if (NULL != polldesc) { 1825 PR_DELETE(polldesc); 1826 } 1827 return NULL; 1828 } /* _pr_setfd */ 1829 1830 #endif /* !defined(NEED_SELECT) */ 1831 1832 PR_IMPLEMENT(PRInt32) 1833 PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex, 1834 PRIntervalTime timeout) { 1835 #if !defined(NEED_SELECT) 1836 PRInt32 npds = 0; 1837 /* 1838 ** Find out how many fds are represented in the three lists. 1839 ** Then allocate a polling descriptor for the logical union 1840 ** (there can't be any overlapping) and call PR_Poll(). 1841 */ 1842 1843 PRPollDesc *copy, *poll; 1844 1845 static PRBool warning = PR_TRUE; 1846 if (warning) { 1847 warning = _PR_Obsolete("PR_Select()", "PR_Poll()"); 1848 } 1849 1850 /* try to get an initial guesss at how much space we need */ 1851 npds = 0; 1852 if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0)) { 1853 npds = pr_rd->hsize + pr_rd->nsize; 1854 } 1855 if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0)) { 1856 npds = pr_wr->hsize + pr_wr->nsize; 1857 } 1858 if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0)) { 1859 npds = pr_ex->hsize + pr_ex->nsize; 1860 } 1861 1862 if (0 == npds) { 1863 PR_Sleep(timeout); 1864 return 0; 1865 } 1866 1867 copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc)); 1868 if (NULL == poll) { 1869 goto out_of_memory; 1870 } 1871 poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1; 1872 1873 poll = _pr_setfd(pr_rd, PR_POLL_READ, poll); 1874 if (NULL == poll) { 1875 goto out_of_memory; 1876 } 1877 poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll); 1878 if (NULL == poll) { 1879 goto out_of_memory; 1880 } 1881 poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll); 1882 if (NULL == poll) { 1883 goto out_of_memory; 1884 } 1885 unused = 0; 1886 while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) { 1887 ++unused; 1888 } 1889 1890 PR_ASSERT(unused > 0); 1891 npds = PR_Poll(poll, unused, timeout); 1892 1893 if (npds > 0) { 1894 /* Copy the results back into the fd sets */ 1895 if (NULL != pr_rd) { 1896 pr_rd->nsize = pr_rd->hsize = 0; 1897 } 1898 if (NULL != pr_wr) { 1899 pr_wr->nsize = pr_wr->hsize = 0; 1900 } 1901 if (NULL != pr_ex) { 1902 pr_ex->nsize = pr_ex->hsize = 0; 1903 } 1904 for (copy = &poll[unused - 1]; copy >= poll; --copy) { 1905 if (copy->out_flags & PR_POLL_NVAL) { 1906 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 1907 npds = -1; 1908 break; 1909 } 1910 if (copy->out_flags & PR_POLL_READ) 1911 if (NULL != pr_rd) { 1912 pr_rd->harray[pr_rd->hsize++] = copy->fd; 1913 } 1914 if (copy->out_flags & PR_POLL_WRITE) 1915 if (NULL != pr_wr) { 1916 pr_wr->harray[pr_wr->hsize++] = copy->fd; 1917 } 1918 if (copy->out_flags & PR_POLL_EXCEPT) 1919 if (NULL != pr_ex) { 1920 pr_ex->harray[pr_ex->hsize++] = copy->fd; 1921 } 1922 } 1923 } 1924 PR_DELETE(poll); 1925 1926 return npds; 1927 out_of_memory: 1928 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1929 return -1; 1930 1931 #endif /* !defined(NEED_SELECT) */ 1932 }