ptio.c (130033B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 /* 7 ** File: ptio.c 8 ** Descritpion: Implemenation of I/O methods for pthreads 9 */ 10 11 #if defined(_PR_PTHREADS) 12 13 14 # include <pthread.h> 15 # include <string.h> /* for memset() */ 16 # include <sys/types.h> 17 # include <dirent.h> 18 # include <fcntl.h> 19 # include <unistd.h> 20 # include <sys/socket.h> 21 # include <sys/stat.h> 22 # include <sys/uio.h> 23 # include <sys/file.h> 24 # include <sys/ioctl.h> 25 # if defined(DARWIN) 26 # include <sys/utsname.h> /* for uname */ 27 # endif 28 # if defined(SOLARIS) 29 # include <sys/filio.h> /* to pick up FIONREAD */ 30 # endif 31 # ifdef _PR_POLL_AVAILABLE 32 # include <poll.h> 33 # endif 34 # ifdef AIX 35 /* To pick up sysconf() */ 36 # include <unistd.h> 37 # include <dlfcn.h> /* for dlopen */ 38 # else 39 /* To pick up getrlimit() etc. */ 40 # include <sys/time.h> 41 # include <sys/resource.h> 42 # endif 43 44 # ifdef SOLARIS 45 /* 46 * Define HAVE_SENDFILEV if the system has the sendfilev() system call. 47 * Code built this way won't run on a system without sendfilev(). 48 * We can define HAVE_SENDFILEV by default when the minimum release 49 * of Solaris that NSPR supports has sendfilev(). 50 */ 51 # ifdef HAVE_SENDFILEV 52 53 # include <sys/sendfile.h> 54 55 # define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d)) 56 57 # else 58 59 # include <dlfcn.h> /* for dlopen */ 60 61 /* 62 * Match the definitions in <sys/sendfile.h>. 63 */ 64 typedef struct sendfilevec { 65 int sfv_fd; /* input fd */ 66 uint_t sfv_flag; /* flags */ 67 off_t sfv_off; /* offset to start reading from */ 68 size_t sfv_len; /* amount of data */ 69 } sendfilevec_t; 70 71 # define SFV_FD_SELF (-2) 72 73 /* 74 * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *); 75 */ 76 static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL; 77 78 # define SOLARIS_SENDFILEV(a, b, c, d) \ 79 (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d)) 80 81 # endif /* HAVE_SENDFILEV */ 82 # endif /* SOLARIS */ 83 84 /* 85 * The send_file() system call is available in AIX 4.3.2 or later. 86 * If this file is compiled on an older AIX system, it attempts to 87 * look up the send_file symbol at run time to determine whether 88 * we can use the faster PR_SendFile/PR_TransmitFile implementation based on 89 * send_file(). On AIX 4.3.2 or later, we can safely skip this 90 * runtime function dispatching and just use the send_file based 91 * implementation. 92 */ 93 # ifdef AIX 94 # ifdef SF_CLOSE 95 # define HAVE_SEND_FILE 96 # endif 97 98 # ifdef HAVE_SEND_FILE 99 100 # define AIX_SEND_FILE(a, b, c) send_file(a, b, c) 101 102 # else /* HAVE_SEND_FILE */ 103 104 /* 105 * The following definitions match those in <sys/socket.h> 106 * on AIX 4.3.2. 107 */ 108 109 /* 110 * Structure for the send_file() system call 111 */ 112 struct sf_parms { 113 /* --------- header parms ---------- */ 114 void* header_data; /* Input/Output. Points to header buf */ 115 uint_t header_length; /* Input/Output. Length of the header */ 116 /* --------- file parms ------------ */ 117 int file_descriptor; /* Input. File descriptor of the file */ 118 unsigned long long file_size; /* Output. Size of the file */ 119 unsigned long long file_offset; /* Input/Output. Starting offset */ 120 long long file_bytes; /* Input/Output. no. of bytes to send */ 121 /* --------- trailer parms --------- */ 122 void* trailer_data; /* Input/Output. Points to trailer buf */ 123 uint_t trailer_length; /* Input/Output. Length of the trailer */ 124 /* --------- return info ----------- */ 125 unsigned long long bytes_sent; /* Output. no. of bytes sent */ 126 }; 127 128 /* 129 * Flags for the send_file() system call 130 */ 131 # define SF_CLOSE 0x00000001 /* close the socket after completion */ 132 # define SF_REUSE 0x00000002 /* reuse socket. not supported */ 133 # define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */ 134 # define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */ 135 136 /* 137 * prototype: size_t send_file(int *, struct sf_parms *, uint_t); 138 */ 139 static ssize_t (*pt_aix_sendfile_fptr)() = NULL; 140 141 # define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c) 142 143 # endif /* HAVE_SEND_FILE */ 144 # endif /* AIX */ 145 146 # ifdef LINUX 147 # include <sys/sendfile.h> 148 # endif 149 150 # include "primpl.h" 151 152 # if defined(LINUX) || defined(ANDROID) 153 # include <netinet/in.h> 154 # endif 155 156 # ifdef DARWIN 157 # include <netinet/in.h> 158 # include <netinet/ip.h> 159 # endif 160 161 # ifdef HAVE_NETINET_TCP_H 162 # include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */ 163 # endif 164 165 # ifdef LINUX 166 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */ 167 # ifndef TCP_CORK 168 # define TCP_CORK 3 169 # endif 170 # ifndef MSG_FASTOPEN 171 # define MSG_FASTOPEN 0x20000000 172 # endif 173 # endif 174 175 # ifdef _PR_IPV6_V6ONLY_PROBE 176 static PRBool _pr_ipv6_v6only_on_by_default; 177 # endif 178 179 # if defined(AIX4_1) 180 # define _PRSelectFdSetArg_t void* 181 # elif (defined(AIX) && !defined(AIX4_1)) || defined(SOLARIS) || \ 182 defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) || \ 183 defined(__GNU__) || defined(__GLIBC__) || defined(FREEBSD) || \ 184 defined(NETBSD) || defined(OPENBSD) || defined(NTO) || \ 185 defined(DARWIN) || defined(RISCOS) 186 # define _PRSelectFdSetArg_t fd_set* 187 # else 188 # error "Cannot determine architecture" 189 # endif 190 191 # if defined(SOLARIS) 192 # ifndef PROTO_SDP 193 /* on solaris, SDP is a new type of protocol */ 194 # define PROTO_SDP 257 195 # endif 196 # define _PR_HAVE_SDP 197 # elif defined(LINUX) 198 # ifndef AF_INET_SDP 199 /* on linux, SDP is a new type of address family */ 200 # define AF_INET_SDP 27 201 # endif 202 # define _PR_HAVE_SDP 203 # endif /* LINUX */ 204 205 static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type, 206 PRBool isAcceptedSocket, PRBool imported); 207 208 static PRLock* _pr_flock_lock; /* For PR_LockFile() etc. */ 209 static PRCondVar* _pr_flock_cv; /* For PR_LockFile() etc. */ 210 static PRLock* _pr_rename_lock; /* For PR_Rename() */ 211 212 /**************************************************************************/ 213 214 /* These two functions are only used in assertions. */ 215 # if defined(DEBUG) 216 217 PRBool IsValidNetAddr(const PRNetAddr* addr) { 218 if ((addr != NULL) && (addr->raw.family != AF_UNIX) && 219 (addr->raw.family != PR_AF_INET6) && (addr->raw.family != AF_INET)) { 220 return PR_FALSE; 221 } 222 return PR_TRUE; 223 } 224 225 static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) { 226 /* 227 * The definition of the length of a Unix domain socket address 228 * is not uniform, so we don't check it. 229 */ 230 if ((addr != NULL) && (addr->raw.family != AF_UNIX) && 231 (PR_NETADDR_SIZE(addr) != addr_len)) { 232 # if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 233 /* 234 * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 235 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id 236 * field and is 28 bytes. It is possible for socket functions 237 * to return an addr_len greater than sizeof(struct sockaddr_in6). 238 * We need to allow that. (Bugzilla bug #77264) 239 */ 240 if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) { 241 return PR_TRUE; 242 } 243 # endif 244 return PR_FALSE; 245 } 246 return PR_TRUE; 247 } 248 249 # endif /* DEBUG */ 250 251 /*****************************************************************************/ 252 /************************* I/O Continuation machinery ************************/ 253 /*****************************************************************************/ 254 255 /* 256 * The polling interval defines the maximum amount of time that a thread 257 * might hang up before an interrupt is noticed. 258 */ 259 # define PT_DEFAULT_POLL_MSEC 5000 260 261 /* 262 * pt_SockLen is the type for the length of a socket address 263 * structure, used in the address length argument to bind, 264 * connect, accept, getsockname, getpeername, etc. Posix.1g 265 * defines this type as socklen_t. It is size_t or int on 266 * most current systems. 267 */ 268 # if defined(HAVE_SOCKLEN_T) || (defined(__GLIBC__) && __GLIBC__ >= 2) 269 typedef socklen_t pt_SockLen; 270 # elif (defined(AIX) && !defined(AIX4_1)) 271 typedef PRSize pt_SockLen; 272 # else 273 typedef PRIntn pt_SockLen; 274 # endif 275 276 typedef struct pt_Continuation pt_Continuation; 277 typedef PRBool (*ContinuationFn)(pt_Continuation* op, PRInt16 revents); 278 279 typedef enum pr_ContuationStatus { 280 pt_continuation_pending, 281 pt_continuation_done 282 } pr_ContuationStatus; 283 284 struct pt_Continuation { 285 /* The building of the continuation operation */ 286 ContinuationFn function; /* what function to continue */ 287 union { 288 PRIntn osfd; 289 } arg1; /* #1 - the op's fd */ 290 union { 291 void* buffer; 292 } arg2; /* #2 - primary transfer buffer */ 293 union { 294 PRSize amount; /* #3 - size of 'buffer', or */ 295 pt_SockLen* addr_len; /* - length of address */ 296 # ifdef HPUX11 297 /* 298 * For sendfile() 299 */ 300 struct file_spec { 301 off_t offset; /* offset in file to send */ 302 size_t nbytes; /* length of file data to send */ 303 size_t st_size; /* file size */ 304 } file_spec; 305 # endif 306 } arg3; 307 union { 308 PRIntn flags; 309 } arg4; /* #4 - read/write flags */ 310 union { 311 PRNetAddr* addr; 312 } arg5; /* #5 - send/recv address */ 313 314 # ifdef HPUX11 315 /* 316 * For sendfile() 317 */ 318 int filedesc; /* descriptor of file to send */ 319 int nbytes_to_send; /* size of header and file */ 320 # endif /* HPUX11 */ 321 322 # ifdef SOLARIS 323 /* 324 * For sendfilev() 325 */ 326 int nbytes_to_send; /* size of header and file */ 327 # endif /* SOLARIS */ 328 329 # ifdef LINUX 330 /* 331 * For sendfile() 332 */ 333 int in_fd; /* descriptor of file to send */ 334 off_t offset; 335 size_t count; 336 # endif /* LINUX */ 337 338 PRIntervalTime timeout; /* client (relative) timeout */ 339 340 PRInt16 event; /* flags for poll()'s events */ 341 342 /* 343 ** The representation and notification of the results of the operation. 344 ** These function can either return an int return code or a pointer to 345 ** some object. 346 */ 347 union { 348 PRSize code; 349 void* object; 350 } result; 351 352 PRIntn syserrno; /* in case it failed, why (errno) */ 353 pr_ContuationStatus status; /* the status of the operation */ 354 }; 355 356 # if defined(DEBUG) 357 358 PTDebug pt_debug; /* this is shared between several modules */ 359 360 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) { 361 PTDebug stats; 362 char buffer[100]; 363 PRExplodedTime tod; 364 PRInt64 elapsed, aMil; 365 stats = pt_debug; /* a copy */ 366 PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod); 367 (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); 368 369 LL_SUB(elapsed, PR_Now(), stats.timeStarted); 370 LL_I2L(aMil, 1000000); 371 LL_DIV(elapsed, elapsed, aMil); 372 373 if (NULL != msg) { 374 PR_fprintf(debug_out, "%s", msg); 375 } 376 PR_fprintf(debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed); 377 PR_fprintf(debug_out, "\tlocks [created: %u, destroyed: %u]\n", 378 stats.locks_created, stats.locks_destroyed); 379 PR_fprintf(debug_out, "\tlocks [acquired: %u, released: %u]\n", 380 stats.locks_acquired, stats.locks_released); 381 PR_fprintf(debug_out, "\tcvars [created: %u, destroyed: %u]\n", 382 stats.cvars_created, stats.cvars_destroyed); 383 PR_fprintf(debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n", 384 stats.cvars_notified, stats.delayed_cv_deletes); 385 } /* PT_FPrintStats */ 386 387 # else 388 389 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) { 390 /* do nothing */ 391 } /* PT_FPrintStats */ 392 393 # endif /* DEBUG */ 394 395 396 static void pt_poll_now(pt_Continuation* op) { 397 PRInt32 msecs; 398 PRIntervalTime epoch, now, elapsed, remaining; 399 PRBool wait_for_remaining; 400 PRThread* self = PR_GetCurrentThread(); 401 402 PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); 403 404 switch (op->timeout) { 405 case PR_INTERVAL_NO_TIMEOUT: 406 msecs = PT_DEFAULT_POLL_MSEC; 407 do { 408 PRIntn rv; 409 struct pollfd tmp_pfd; 410 411 tmp_pfd.revents = 0; 412 tmp_pfd.fd = op->arg1.osfd; 413 tmp_pfd.events = op->event; 414 415 rv = poll(&tmp_pfd, 1, msecs); 416 417 if (_PT_THREAD_INTERRUPTED(self)) { 418 self->state &= ~PT_THREAD_ABORTED; 419 op->result.code = -1; 420 op->syserrno = EINTR; 421 op->status = pt_continuation_done; 422 return; 423 } 424 425 if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) { 426 continue; /* go around the loop again */ 427 } 428 429 if (rv > 0) { 430 PRInt16 events = tmp_pfd.events; 431 PRInt16 revents = tmp_pfd.revents; 432 433 if ((revents & POLLNVAL) /* busted in all cases */ 434 || ((events & POLLOUT) && (revents & POLLHUP))) 435 /* write op & hup */ 436 { 437 op->result.code = -1; 438 if (POLLNVAL & revents) { 439 op->syserrno = EBADF; 440 } else if (POLLHUP & revents) { 441 op->syserrno = EPIPE; 442 } 443 op->status = pt_continuation_done; 444 } else { 445 if (op->function(op, revents)) { 446 op->status = pt_continuation_done; 447 } 448 } 449 } else if (rv == -1) { 450 op->result.code = -1; 451 op->syserrno = errno; 452 op->status = pt_continuation_done; 453 } 454 /* else, poll timed out */ 455 } while (pt_continuation_done != op->status); 456 break; 457 default: 458 now = epoch = PR_IntervalNow(); 459 remaining = op->timeout; 460 do { 461 PRIntn rv; 462 struct pollfd tmp_pfd; 463 464 tmp_pfd.revents = 0; 465 tmp_pfd.fd = op->arg1.osfd; 466 tmp_pfd.events = op->event; 467 468 wait_for_remaining = PR_TRUE; 469 msecs = (PRInt32)PR_IntervalToMilliseconds(remaining); 470 if (msecs > PT_DEFAULT_POLL_MSEC) { 471 wait_for_remaining = PR_FALSE; 472 msecs = PT_DEFAULT_POLL_MSEC; 473 } 474 rv = poll(&tmp_pfd, 1, msecs); 475 476 if (_PT_THREAD_INTERRUPTED(self)) { 477 self->state &= ~PT_THREAD_ABORTED; 478 op->result.code = -1; 479 op->syserrno = EINTR; 480 op->status = pt_continuation_done; 481 return; 482 } 483 484 if (rv > 0) { 485 PRInt16 events = tmp_pfd.events; 486 PRInt16 revents = tmp_pfd.revents; 487 488 if ((revents & POLLNVAL) /* busted in all cases */ 489 || ((events & POLLOUT) && (revents & POLLHUP))) 490 /* write op & hup */ 491 { 492 op->result.code = -1; 493 if (POLLNVAL & revents) { 494 op->syserrno = EBADF; 495 } else if (POLLHUP & revents) { 496 op->syserrno = EPIPE; 497 } 498 op->status = pt_continuation_done; 499 } else { 500 if (op->function(op, revents)) { 501 op->status = pt_continuation_done; 502 } 503 } 504 } else if ((rv == 0) || ((errno == EINTR) || (errno == EAGAIN))) { 505 if (rv == 0) /* poll timed out */ 506 { 507 if (wait_for_remaining) { 508 now += remaining; 509 } else { 510 now += PR_MillisecondsToInterval(msecs); 511 } 512 } else { 513 now = PR_IntervalNow(); 514 } 515 elapsed = (PRIntervalTime)(now - epoch); 516 if (elapsed >= op->timeout) { 517 op->result.code = -1; 518 op->syserrno = ETIMEDOUT; 519 op->status = pt_continuation_done; 520 } else { 521 remaining = op->timeout - elapsed; 522 } 523 } else { 524 op->result.code = -1; 525 op->syserrno = errno; 526 op->status = pt_continuation_done; 527 } 528 } while (pt_continuation_done != op->status); 529 break; 530 } 531 532 } /* pt_poll_now */ 533 534 static PRIntn pt_Continue(pt_Continuation* op) { 535 op->status = pt_continuation_pending; /* set default value */ 536 /* 537 * let each thread call poll directly 538 */ 539 pt_poll_now(op); 540 PR_ASSERT(pt_continuation_done == op->status); 541 return op->result.code; 542 } /* pt_Continue */ 543 544 /*****************************************************************************/ 545 /*********************** specific continuation functions *********************/ 546 /*****************************************************************************/ 547 static PRBool pt_connect_cont(pt_Continuation* op, PRInt16 revents) { 548 op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd); 549 if (op->syserrno != 0) { 550 op->result.code = -1; 551 } else { 552 op->result.code = 0; 553 } 554 return PR_TRUE; /* this one is cooked */ 555 } /* pt_connect_cont */ 556 557 static PRBool pt_accept_cont(pt_Continuation* op, PRInt16 revents) { 558 op->syserrno = 0; 559 op->result.code = accept(op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len); 560 if (-1 == op->result.code) { 561 op->syserrno = errno; 562 if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno) { 563 return PR_FALSE; /* do nothing - this one ain't finished */ 564 } 565 } 566 return PR_TRUE; 567 } /* pt_accept_cont */ 568 569 static PRBool pt_read_cont(pt_Continuation* op, PRInt16 revents) { 570 /* 571 * Any number of bytes will complete the operation. It need 572 * not (and probably will not) satisfy the request. The only 573 * error we continue is EWOULDBLOCK|EAGAIN. 574 */ 575 op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); 576 op->syserrno = errno; 577 return ((-1 == op->result.code) && 578 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) 579 ? PR_FALSE 580 : PR_TRUE; 581 } /* pt_read_cont */ 582 583 static PRBool pt_recv_cont(pt_Continuation* op, PRInt16 revents) { 584 /* 585 * Any number of bytes will complete the operation. It need 586 * not (and probably will not) satisfy the request. The only 587 * error we continue is EWOULDBLOCK|EAGAIN. 588 */ 589 # if defined(SOLARIS) 590 if (0 == op->arg4.flags) 591 op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); 592 else 593 op->result.code = 594 recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); 595 # else 596 op->result.code = 597 recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); 598 # endif 599 op->syserrno = errno; 600 return ((-1 == op->result.code) && 601 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) 602 ? PR_FALSE 603 : PR_TRUE; 604 } /* pt_recv_cont */ 605 606 static PRBool pt_send_cont(pt_Continuation* op, PRInt16 revents) { 607 PRIntn bytes; 608 # if defined(SOLARIS) 609 PRInt32 tmp_amount = op->arg3.amount; 610 # endif 611 /* 612 * We want to write the entire amount out, no matter how many 613 * tries it takes. Keep advancing the buffer and the decrementing 614 * the amount until the amount goes away. Return the total bytes 615 * (which should be the original amount) when finished (or an 616 * error). 617 */ 618 # if defined(SOLARIS) 619 retry: 620 bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount); 621 # else 622 bytes = send(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); 623 # endif 624 op->syserrno = errno; 625 626 # if defined(SOLARIS) 627 /* 628 * The write system call has been reported to return the ERANGE error 629 * on occasion. Try to write in smaller chunks to workaround this bug. 630 */ 631 if ((bytes == -1) && (op->syserrno == ERANGE)) { 632 if (tmp_amount > 1) { 633 tmp_amount = tmp_amount / 2; /* half the bytes */ 634 goto retry; 635 } 636 } 637 # endif 638 639 if (bytes >= 0) /* this is progress */ 640 { 641 char* bp = (char*)op->arg2.buffer; 642 bp += bytes; /* adjust the buffer pointer */ 643 op->arg2.buffer = bp; 644 op->result.code += bytes; /* accumulate the number sent */ 645 op->arg3.amount -= bytes; /* and reduce the required count */ 646 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; 647 } 648 if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) { 649 op->result.code = -1; 650 return PR_TRUE; 651 } else { 652 return PR_FALSE; 653 } 654 } /* pt_send_cont */ 655 656 static PRBool pt_write_cont(pt_Continuation* op, PRInt16 revents) { 657 PRIntn bytes; 658 /* 659 * We want to write the entire amount out, no matter how many 660 * tries it takes. Keep advancing the buffer and the decrementing 661 * the amount until the amount goes away. Return the total bytes 662 * (which should be the original amount) when finished (or an 663 * error). 664 */ 665 bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); 666 op->syserrno = errno; 667 if (bytes >= 0) /* this is progress */ 668 { 669 char* bp = (char*)op->arg2.buffer; 670 bp += bytes; /* adjust the buffer pointer */ 671 op->arg2.buffer = bp; 672 op->result.code += bytes; /* accumulate the number sent */ 673 op->arg3.amount -= bytes; /* and reduce the required count */ 674 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; 675 } 676 if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) { 677 op->result.code = -1; 678 return PR_TRUE; 679 } else { 680 return PR_FALSE; 681 } 682 } /* pt_write_cont */ 683 684 static PRBool pt_writev_cont(pt_Continuation* op, PRInt16 revents) { 685 PRIntn bytes; 686 struct iovec* iov = (struct iovec*)op->arg2.buffer; 687 /* 688 * Same rules as write, but continuing seems to be a bit more 689 * complicated. As the number of bytes sent grows, we have to 690 * redefine the vector we're pointing at. We might have to 691 * modify an individual vector parms or we might have to eliminate 692 * a pair altogether. 693 */ 694 bytes = writev(op->arg1.osfd, iov, op->arg3.amount); 695 op->syserrno = errno; 696 if (bytes >= 0) /* this is progress */ 697 { 698 PRIntn iov_index; 699 op->result.code += bytes; /* accumulate the number sent */ 700 for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index) { 701 /* how much progress did we make in the i/o vector? */ 702 if (bytes < iov[iov_index].iov_len) { 703 /* this element's not done yet */ 704 char** bp = (char**)&(iov[iov_index].iov_base); 705 iov[iov_index].iov_len -= bytes; /* there's that much left */ 706 *bp += bytes; /* starting there */ 707 break; /* go off and do that */ 708 } 709 bytes -= iov[iov_index].iov_len; /* that element's consumed */ 710 } 711 op->arg2.buffer = &iov[iov_index]; /* new start of array */ 712 op->arg3.amount -= iov_index; /* and array length */ 713 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; 714 } 715 if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) { 716 op->result.code = -1; 717 return PR_TRUE; 718 } else { 719 return PR_FALSE; 720 } 721 } /* pt_writev_cont */ 722 723 static PRBool pt_sendto_cont(pt_Continuation* op, PRInt16 revents) { 724 PRIntn bytes = 725 sendto(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, 726 (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr)); 727 op->syserrno = errno; 728 if (bytes >= 0) /* this is progress */ 729 { 730 char* bp = (char*)op->arg2.buffer; 731 bp += bytes; /* adjust the buffer pointer */ 732 op->arg2.buffer = bp; 733 op->result.code += bytes; /* accumulate the number sent */ 734 op->arg3.amount -= bytes; /* and reduce the required count */ 735 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; 736 } 737 if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) { 738 op->result.code = -1; 739 return PR_TRUE; 740 } else { 741 return PR_FALSE; 742 } 743 } /* pt_sendto_cont */ 744 745 static PRBool pt_recvfrom_cont(pt_Continuation* op, PRInt16 revents) { 746 pt_SockLen addr_len = sizeof(PRNetAddr); 747 op->result.code = 748 recvfrom(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, 749 (struct sockaddr*)op->arg5.addr, &addr_len); 750 op->syserrno = errno; 751 return ((-1 == op->result.code) && 752 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) 753 ? PR_FALSE 754 : PR_TRUE; 755 } /* pt_recvfrom_cont */ 756 757 # ifdef AIX 758 static PRBool pt_aix_sendfile_cont(pt_Continuation* op, PRInt16 revents) { 759 struct sf_parms* sf_struct = (struct sf_parms*)op->arg2.buffer; 760 ssize_t rv; 761 unsigned long long saved_file_offset; 762 long long saved_file_bytes; 763 764 saved_file_offset = sf_struct->file_offset; 765 saved_file_bytes = sf_struct->file_bytes; 766 sf_struct->bytes_sent = 0; 767 768 if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0)) 769 PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <= 770 sf_struct->file_size); 771 rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags); 772 op->syserrno = errno; 773 774 if (rv != -1) { 775 op->result.code += sf_struct->bytes_sent; 776 /* 777 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from 778 * being updated. So, 'file_bytes' is maintained by NSPR to 779 * avoid conflict when this bug is fixed in AIX, in the future. 780 */ 781 if (saved_file_bytes != -1) { 782 saved_file_bytes -= (sf_struct->file_offset - saved_file_offset); 783 } 784 sf_struct->file_bytes = saved_file_bytes; 785 } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { 786 op->result.code = -1; 787 } else { 788 return PR_FALSE; 789 } 790 791 if (rv == 1) { /* more data to send */ 792 return PR_FALSE; 793 } 794 795 return PR_TRUE; 796 } 797 # endif /* AIX */ 798 799 # ifdef HPUX11 800 static PRBool pt_hpux_sendfile_cont(pt_Continuation* op, PRInt16 revents) { 801 struct iovec* hdtrl = (struct iovec*)op->arg2.buffer; 802 int count; 803 804 count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset, 805 op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags); 806 PR_ASSERT(count <= op->nbytes_to_send); 807 op->syserrno = errno; 808 809 if (count != -1) { 810 op->result.code += count; 811 } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { 812 op->result.code = -1; 813 } else { 814 return PR_FALSE; 815 } 816 if (count != -1 && count < op->nbytes_to_send) { 817 if (count < hdtrl[0].iov_len) { 818 /* header not sent */ 819 820 hdtrl[0].iov_base = ((char*)hdtrl[0].iov_base) + count; 821 hdtrl[0].iov_len -= count; 822 823 } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) { 824 /* header sent, file not sent */ 825 PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len; 826 827 hdtrl[0].iov_base = NULL; 828 hdtrl[0].iov_len = 0; 829 830 op->arg3.file_spec.offset += file_nbytes_sent; 831 op->arg3.file_spec.nbytes -= file_nbytes_sent; 832 } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes + 833 hdtrl[1].iov_len)) { 834 PRUint32 trailer_nbytes_sent = 835 count - (hdtrl[0].iov_len + op->arg3.file_spec.nbytes); 836 837 /* header sent, file sent, trailer not sent */ 838 839 hdtrl[0].iov_base = NULL; 840 hdtrl[0].iov_len = 0; 841 /* 842 * set file offset and len so that no more file data is 843 * sent 844 */ 845 op->arg3.file_spec.offset = op->arg3.file_spec.st_size; 846 op->arg3.file_spec.nbytes = 0; 847 848 hdtrl[1].iov_base = ((char*)hdtrl[1].iov_base) + trailer_nbytes_sent; 849 hdtrl[1].iov_len -= trailer_nbytes_sent; 850 } 851 op->nbytes_to_send -= count; 852 return PR_FALSE; 853 } 854 855 return PR_TRUE; 856 } 857 # endif /* HPUX11 */ 858 859 # ifdef SOLARIS 860 static PRBool pt_solaris_sendfile_cont(pt_Continuation* op, PRInt16 revents) { 861 struct sendfilevec* vec = (struct sendfilevec*)op->arg2.buffer; 862 size_t xferred; 863 ssize_t count; 864 865 count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred); 866 op->syserrno = errno; 867 PR_ASSERT((count == -1) || (count == xferred)); 868 869 if (count == -1) { 870 if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN && 871 op->syserrno != EINTR) { 872 op->result.code = -1; 873 return PR_TRUE; 874 } 875 count = xferred; 876 } else if (count == 0) { 877 /* 878 * We are now at EOF. The file was truncated. Solaris sendfile is 879 * supposed to return 0 and no error in this case, though some versions 880 * may return -1 and EINVAL . 881 */ 882 op->result.code = -1; 883 op->syserrno = 0; /* will be treated as EOF */ 884 return PR_TRUE; 885 } 886 PR_ASSERT(count <= op->nbytes_to_send); 887 888 op->result.code += count; 889 if (count < op->nbytes_to_send) { 890 op->nbytes_to_send -= count; 891 892 while (count >= vec->sfv_len) { 893 count -= vec->sfv_len; 894 vec++; 895 op->arg3.amount--; 896 } 897 PR_ASSERT(op->arg3.amount > 0); 898 899 vec->sfv_off += count; 900 vec->sfv_len -= count; 901 PR_ASSERT(vec->sfv_len > 0); 902 op->arg2.buffer = vec; 903 904 return PR_FALSE; 905 } 906 907 return PR_TRUE; 908 } 909 # endif /* SOLARIS */ 910 911 # ifdef LINUX 912 static PRBool pt_linux_sendfile_cont(pt_Continuation* op, PRInt16 revents) { 913 ssize_t rv; 914 off_t oldoffset; 915 916 oldoffset = op->offset; 917 rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count); 918 op->syserrno = errno; 919 920 if (rv == -1) { 921 if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { 922 op->result.code = -1; 923 return PR_TRUE; 924 } 925 rv = 0; 926 } 927 PR_ASSERT(rv == op->offset - oldoffset); 928 op->result.code += rv; 929 if (rv < op->count) { 930 op->count -= rv; 931 return PR_FALSE; 932 } 933 return PR_TRUE; 934 } 935 # endif /* LINUX */ 936 937 void _PR_InitIO(void) { 938 # if defined(DEBUG) 939 memset(&pt_debug, 0, sizeof(PTDebug)); 940 pt_debug.timeStarted = PR_Now(); 941 # endif 942 943 _pr_flock_lock = PR_NewLock(); 944 PR_ASSERT(NULL != _pr_flock_lock); 945 _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); 946 PR_ASSERT(NULL != _pr_flock_cv); 947 _pr_rename_lock = PR_NewLock(); 948 PR_ASSERT(NULL != _pr_rename_lock); 949 950 _PR_InitFdCache(); /* do that */ 951 952 _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE); 953 _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE); 954 _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE); 955 PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr); 956 957 # ifdef _PR_IPV6_V6ONLY_PROBE 958 /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option 959 * is turned on by default, contrary to what RFC 3493, Section 960 * 5.3 says. So we have to turn it off. Find out whether we 961 * are running on such a system. 962 */ 963 { 964 int osfd; 965 osfd = socket(AF_INET6, SOCK_STREAM, 0); 966 if (osfd != -1) { 967 int on; 968 socklen_t optlen = sizeof(on); 969 if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, &optlen) == 0) { 970 _pr_ipv6_v6only_on_by_default = on; 971 } 972 close(osfd); 973 } 974 } 975 # endif 976 } /* _PR_InitIO */ 977 978 void _PR_CleanupIO(void) { 979 _PR_Putfd(_pr_stdin); 980 _pr_stdin = NULL; 981 _PR_Putfd(_pr_stdout); 982 _pr_stdout = NULL; 983 _PR_Putfd(_pr_stderr); 984 _pr_stderr = NULL; 985 986 _PR_CleanupFdCache(); 987 988 if (_pr_flock_cv) { 989 PR_DestroyCondVar(_pr_flock_cv); 990 _pr_flock_cv = NULL; 991 } 992 if (_pr_flock_lock) { 993 PR_DestroyLock(_pr_flock_lock); 994 _pr_flock_lock = NULL; 995 } 996 if (_pr_rename_lock) { 997 PR_DestroyLock(_pr_rename_lock); 998 _pr_rename_lock = NULL; 999 } 1000 } /* _PR_CleanupIO */ 1001 1002 PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) { 1003 PRFileDesc* result = NULL; 1004 PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError); 1005 1006 if (!_pr_initialized) { 1007 _PR_ImplicitInitialization(); 1008 } 1009 1010 switch (osfd) { 1011 case PR_StandardInput: 1012 result = _pr_stdin; 1013 break; 1014 case PR_StandardOutput: 1015 result = _pr_stdout; 1016 break; 1017 case PR_StandardError: 1018 result = _pr_stderr; 1019 break; 1020 default: 1021 (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1022 } 1023 return result; 1024 } /* PR_GetSpecialFD */ 1025 1026 /*****************************************************************************/ 1027 /***************************** I/O private methods ***************************/ 1028 /*****************************************************************************/ 1029 1030 static PRBool pt_TestAbort(void) { 1031 PRThread* me = PR_GetCurrentThread(); 1032 if (_PT_THREAD_INTERRUPTED(me)) { 1033 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1034 me->state &= ~PT_THREAD_ABORTED; 1035 return PR_TRUE; 1036 } 1037 return PR_FALSE; 1038 } /* pt_TestAbort */ 1039 1040 static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) { 1041 switch (syserrno) { 1042 case EINTR: 1043 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1044 break; 1045 case ETIMEDOUT: 1046 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); 1047 break; 1048 default: 1049 mapper(syserrno); 1050 } 1051 } /* pt_MapError */ 1052 1053 static PRStatus pt_Close(PRFileDesc* fd) { 1054 if ((NULL == fd) || (NULL == fd->secret) || 1055 ((_PR_FILEDESC_OPEN != fd->secret->state) && 1056 (_PR_FILEDESC_CLOSED != fd->secret->state))) { 1057 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 1058 return PR_FAILURE; 1059 } 1060 if (pt_TestAbort()) { 1061 return PR_FAILURE; 1062 } 1063 1064 if (_PR_FILEDESC_OPEN == fd->secret->state) { 1065 if (-1 == close(fd->secret->md.osfd)) { 1066 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); 1067 return PR_FAILURE; 1068 } 1069 fd->secret->state = _PR_FILEDESC_CLOSED; 1070 } 1071 _PR_Putfd(fd); 1072 return PR_SUCCESS; 1073 } /* pt_Close */ 1074 1075 static PRInt32 pt_Read(PRFileDesc* fd, void* buf, PRInt32 amount) { 1076 PRInt32 syserrno, bytes = -1; 1077 1078 if (pt_TestAbort()) { 1079 return bytes; 1080 } 1081 1082 bytes = read(fd->secret->md.osfd, buf, amount); 1083 syserrno = errno; 1084 1085 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1086 (!fd->secret->nonblocking)) { 1087 pt_Continuation op; 1088 op.arg1.osfd = fd->secret->md.osfd; 1089 op.arg2.buffer = buf; 1090 op.arg3.amount = amount; 1091 op.timeout = PR_INTERVAL_NO_TIMEOUT; 1092 op.function = pt_read_cont; 1093 op.event = POLLIN | POLLPRI; 1094 bytes = pt_Continue(&op); 1095 syserrno = op.syserrno; 1096 } 1097 if (bytes < 0) { 1098 pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno); 1099 } 1100 return bytes; 1101 } /* pt_Read */ 1102 1103 static PRInt32 pt_Write(PRFileDesc* fd, const void* buf, PRInt32 amount) { 1104 PRInt32 syserrno, bytes = -1; 1105 PRBool fNeedContinue = PR_FALSE; 1106 1107 if (pt_TestAbort()) { 1108 return bytes; 1109 } 1110 1111 bytes = write(fd->secret->md.osfd, buf, amount); 1112 syserrno = errno; 1113 1114 if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) { 1115 buf = (char*)buf + bytes; 1116 amount -= bytes; 1117 fNeedContinue = PR_TRUE; 1118 } 1119 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1120 (!fd->secret->nonblocking)) { 1121 bytes = 0; 1122 fNeedContinue = PR_TRUE; 1123 } 1124 1125 if (fNeedContinue == PR_TRUE) { 1126 pt_Continuation op; 1127 op.arg1.osfd = fd->secret->md.osfd; 1128 op.arg2.buffer = (void*)buf; 1129 op.arg3.amount = amount; 1130 op.timeout = PR_INTERVAL_NO_TIMEOUT; 1131 op.result.code = bytes; /* initialize the number sent */ 1132 op.function = pt_write_cont; 1133 op.event = POLLOUT | POLLPRI; 1134 bytes = pt_Continue(&op); 1135 syserrno = op.syserrno; 1136 } 1137 if (bytes == -1) { 1138 pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno); 1139 } 1140 return bytes; 1141 } /* pt_Write */ 1142 1143 static PRInt32 pt_Writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_len, 1144 PRIntervalTime timeout) { 1145 PRIntn iov_index; 1146 PRBool fNeedContinue = PR_FALSE; 1147 PRInt32 syserrno, bytes, rv = -1; 1148 struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov; 1149 int osiov_len; 1150 1151 if (pt_TestAbort()) { 1152 return rv; 1153 } 1154 1155 /* Ensured by PR_Writev */ 1156 PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE); 1157 1158 /* 1159 * We can't pass iov to writev because PRIOVec and struct iovec 1160 * may not be binary compatible. Make osiov a copy of iov and 1161 * pass osiov to writev. We can modify osiov if we need to 1162 * continue the operation. 1163 */ 1164 osiov = osiov_local; 1165 osiov_len = iov_len; 1166 for (iov_index = 0; iov_index < osiov_len; iov_index++) { 1167 osiov[iov_index].iov_base = iov[iov_index].iov_base; 1168 osiov[iov_index].iov_len = iov[iov_index].iov_len; 1169 } 1170 1171 rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len); 1172 syserrno = errno; 1173 1174 if (!fd->secret->nonblocking) { 1175 if (bytes >= 0) { 1176 /* 1177 * If we moved some bytes, how does that implicate the 1178 * i/o vector list? In other words, exactly where are 1179 * we within that array? What are the parameters for 1180 * resumption? Maybe we're done! 1181 */ 1182 for (; osiov_len > 0; osiov++, osiov_len--) { 1183 if (bytes < osiov->iov_len) { 1184 /* this one's not done yet */ 1185 osiov->iov_base = (char*)osiov->iov_base + bytes; 1186 osiov->iov_len -= bytes; 1187 break; /* go off and do that */ 1188 } 1189 bytes -= osiov->iov_len; /* this one's done cooked */ 1190 } 1191 PR_ASSERT(osiov_len > 0 || bytes == 0); 1192 if (osiov_len > 0) { 1193 if (PR_INTERVAL_NO_WAIT == timeout) { 1194 rv = -1; 1195 syserrno = ETIMEDOUT; 1196 } else { 1197 fNeedContinue = PR_TRUE; 1198 } 1199 } 1200 } else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN) { 1201 if (PR_INTERVAL_NO_WAIT == timeout) { 1202 syserrno = ETIMEDOUT; 1203 } else { 1204 rv = 0; 1205 fNeedContinue = PR_TRUE; 1206 } 1207 } 1208 } 1209 1210 if (fNeedContinue == PR_TRUE) { 1211 pt_Continuation op; 1212 1213 op.arg1.osfd = fd->secret->md.osfd; 1214 op.arg2.buffer = (void*)osiov; 1215 op.arg3.amount = osiov_len; 1216 op.timeout = timeout; 1217 op.result.code = rv; 1218 op.function = pt_writev_cont; 1219 op.event = POLLOUT | POLLPRI; 1220 rv = pt_Continue(&op); 1221 syserrno = op.syserrno; 1222 } 1223 if (rv == -1) { 1224 pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno); 1225 } 1226 return rv; 1227 } /* pt_Writev */ 1228 1229 static PRInt32 pt_Seek(PRFileDesc* fd, PRInt32 offset, PRSeekWhence whence) { 1230 return _PR_MD_LSEEK(fd, offset, whence); 1231 } /* pt_Seek */ 1232 1233 static PRInt64 pt_Seek64(PRFileDesc* fd, PRInt64 offset, PRSeekWhence whence) { 1234 return _PR_MD_LSEEK64(fd, offset, whence); 1235 } /* pt_Seek64 */ 1236 1237 static PRInt32 pt_Available_f(PRFileDesc* fd) { 1238 PRInt32 result, cur, end; 1239 1240 cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR); 1241 1242 if (cur >= 0) { 1243 end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END); 1244 } 1245 1246 if ((cur < 0) || (end < 0)) { 1247 return -1; 1248 } 1249 1250 result = end - cur; 1251 _PR_MD_LSEEK(fd, cur, PR_SEEK_SET); 1252 1253 return result; 1254 } /* pt_Available_f */ 1255 1256 static PRInt64 pt_Available64_f(PRFileDesc* fd) { 1257 PRInt64 result, cur, end; 1258 PRInt64 minus_one; 1259 1260 LL_I2L(minus_one, -1); 1261 cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR); 1262 1263 if (LL_GE_ZERO(cur)) { 1264 end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END); 1265 } 1266 1267 if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) { 1268 return minus_one; 1269 } 1270 1271 LL_SUB(result, end, cur); 1272 (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET); 1273 1274 return result; 1275 } /* pt_Available64_f */ 1276 1277 static PRInt32 pt_Available_s(PRFileDesc* fd) { 1278 PRInt32 rv, bytes = -1; 1279 if (pt_TestAbort()) { 1280 return bytes; 1281 } 1282 1283 rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes); 1284 1285 if (rv == -1) { 1286 pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno); 1287 } 1288 return bytes; 1289 } /* pt_Available_s */ 1290 1291 static PRInt64 pt_Available64_s(PRFileDesc* fd) { 1292 PRInt64 rv; 1293 LL_I2L(rv, pt_Available_s(fd)); 1294 return rv; 1295 } /* pt_Available64_s */ 1296 1297 static PRStatus pt_FileInfo(PRFileDesc* fd, PRFileInfo* info) { 1298 PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info); 1299 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 1300 } /* pt_FileInfo */ 1301 1302 static PRStatus pt_FileInfo64(PRFileDesc* fd, PRFileInfo64* info) { 1303 PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info); 1304 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 1305 } /* pt_FileInfo64 */ 1306 1307 static PRStatus pt_Synch(PRFileDesc* fd) { 1308 return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; 1309 } /* pt_Synch */ 1310 1311 static PRStatus pt_Fsync(PRFileDesc* fd) { 1312 PRIntn rv = -1; 1313 if (pt_TestAbort()) { 1314 return PR_FAILURE; 1315 } 1316 1317 rv = fsync(fd->secret->md.osfd); 1318 if (rv < 0) { 1319 pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno); 1320 return PR_FAILURE; 1321 } 1322 return PR_SUCCESS; 1323 } /* pt_Fsync */ 1324 1325 static PRStatus pt_Connect(PRFileDesc* fd, const PRNetAddr* addr, 1326 PRIntervalTime timeout) { 1327 PRIntn rv = -1, syserrno; 1328 pt_SockLen addr_len; 1329 const PRNetAddr* addrp = addr; 1330 # if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) 1331 PRNetAddr addrCopy; 1332 # endif 1333 # ifdef _PR_HAVE_SOCKADDR_LEN 1334 PRUint16 md_af = addr->raw.family; 1335 # endif 1336 1337 if (pt_TestAbort()) { 1338 return PR_FAILURE; 1339 } 1340 1341 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1342 addr_len = PR_NETADDR_SIZE(addr); 1343 # ifdef _PR_INET6 1344 if (addr->raw.family == PR_AF_INET6) { 1345 # ifdef _PR_HAVE_SOCKADDR_LEN 1346 md_af = AF_INET6; 1347 # else 1348 addrCopy = *addr; 1349 addrCopy.raw.family = AF_INET6; 1350 addrp = &addrCopy; 1351 # endif 1352 } 1353 # endif 1354 1355 # ifdef _PR_HAVE_SOCKADDR_LEN 1356 addrCopy = *addr; 1357 ((struct sockaddr*)&addrCopy)->sa_len = addr_len; 1358 ((struct sockaddr*)&addrCopy)->sa_family = md_af; 1359 addrp = &addrCopy; 1360 # endif 1361 rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); 1362 syserrno = errno; 1363 if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking)) { 1364 if (PR_INTERVAL_NO_WAIT == timeout) { 1365 syserrno = ETIMEDOUT; 1366 } else { 1367 pt_Continuation op; 1368 op.arg1.osfd = fd->secret->md.osfd; 1369 op.arg2.buffer = (void*)addrp; 1370 op.arg3.amount = addr_len; 1371 op.timeout = timeout; 1372 op.function = pt_connect_cont; 1373 op.event = POLLOUT | POLLPRI; 1374 rv = pt_Continue(&op); 1375 syserrno = op.syserrno; 1376 } 1377 } 1378 if (-1 == rv) { 1379 pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno); 1380 return PR_FAILURE; 1381 } 1382 return PR_SUCCESS; 1383 } /* pt_Connect */ 1384 1385 static PRStatus pt_ConnectContinue(PRFileDesc* fd, PRInt16 out_flags) { 1386 int err; 1387 PRInt32 osfd; 1388 1389 if (out_flags & PR_POLL_NVAL) { 1390 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 1391 return PR_FAILURE; 1392 } 1393 if ((out_flags & 1394 (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP)) == 0) { 1395 PR_ASSERT(out_flags == 0); 1396 PR_SetError(PR_IN_PROGRESS_ERROR, 0); 1397 return PR_FAILURE; 1398 } 1399 1400 osfd = fd->secret->md.osfd; 1401 1402 err = _MD_unix_get_nonblocking_connect_error(osfd); 1403 if (err != 0) { 1404 _PR_MD_MAP_CONNECT_ERROR(err); 1405 return PR_FAILURE; 1406 } 1407 return PR_SUCCESS; 1408 } /* pt_ConnectContinue */ 1409 1410 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc* pd) { 1411 /* Find the NSPR layer and invoke its connectcontinue method */ 1412 PRFileDesc* bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 1413 1414 if (NULL == bottom) { 1415 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1416 return PR_FAILURE; 1417 } 1418 return pt_ConnectContinue(bottom, pd->out_flags); 1419 } /* PR_GetConnectStatus */ 1420 1421 static PRFileDesc* pt_Accept(PRFileDesc* fd, PRNetAddr* addr, 1422 PRIntervalTime timeout) { 1423 PRFileDesc* newfd = NULL; 1424 PRIntn syserrno, osfd = -1; 1425 pt_SockLen addr_len = sizeof(PRNetAddr); 1426 1427 if (pt_TestAbort()) { 1428 return newfd; 1429 } 1430 1431 # ifdef _PR_STRICT_ADDR_LEN 1432 if (addr) { 1433 /* 1434 * Set addr->raw.family just so that we can use the 1435 * PR_NETADDR_SIZE macro. 1436 */ 1437 addr->raw.family = fd->secret->af; 1438 addr_len = PR_NETADDR_SIZE(addr); 1439 } 1440 # endif 1441 1442 osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); 1443 syserrno = errno; 1444 1445 if (osfd == -1) { 1446 if (fd->secret->nonblocking) { 1447 goto failed; 1448 } 1449 1450 if (EWOULDBLOCK != syserrno && EAGAIN != syserrno && 1451 ECONNABORTED != syserrno) { 1452 goto failed; 1453 } else { 1454 if (PR_INTERVAL_NO_WAIT == timeout) { 1455 syserrno = ETIMEDOUT; 1456 } else { 1457 pt_Continuation op; 1458 op.arg1.osfd = fd->secret->md.osfd; 1459 op.arg2.buffer = addr; 1460 op.arg3.addr_len = &addr_len; 1461 op.timeout = timeout; 1462 op.function = pt_accept_cont; 1463 op.event = POLLIN | POLLPRI; 1464 osfd = pt_Continue(&op); 1465 syserrno = op.syserrno; 1466 } 1467 if (osfd < 0) { 1468 goto failed; 1469 } 1470 } 1471 } 1472 # ifdef _PR_HAVE_SOCKADDR_LEN 1473 /* ignore the sa_len field of struct sockaddr */ 1474 if (addr) { 1475 addr->raw.family = ((struct sockaddr*)addr)->sa_family; 1476 } 1477 # endif /* _PR_HAVE_SOCKADDR_LEN */ 1478 # ifdef _PR_INET6 1479 if (addr && (AF_INET6 == addr->raw.family)) { 1480 addr->raw.family = PR_AF_INET6; 1481 } 1482 # endif 1483 newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE); 1484 if (newfd == NULL) { 1485 close(osfd); /* $$$ whoops! this doesn't work $$$ */ 1486 } else { 1487 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1488 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); 1489 # ifdef LINUX 1490 /* 1491 * On Linux, experiments showed that the accepted sockets 1492 * inherit the TCP_NODELAY socket option of the listening 1493 * socket. 1494 */ 1495 newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay; 1496 # endif 1497 } 1498 return newfd; 1499 1500 failed: 1501 pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno); 1502 return NULL; 1503 } /* pt_Accept */ 1504 1505 static PRStatus pt_Bind(PRFileDesc* fd, const PRNetAddr* addr) { 1506 PRIntn rv; 1507 pt_SockLen addr_len; 1508 const PRNetAddr* addrp = addr; 1509 # if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) 1510 PRNetAddr addrCopy; 1511 # endif 1512 # ifdef _PR_HAVE_SOCKADDR_LEN 1513 PRUint16 md_af = addr->raw.family; 1514 # endif 1515 1516 if (pt_TestAbort()) { 1517 return PR_FAILURE; 1518 } 1519 1520 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1521 if (addr->raw.family == AF_UNIX) { 1522 /* Disallow relative pathnames */ 1523 if (addr->local.path[0] != '/' 1524 # if defined(LINUX) 1525 /* Linux has abstract socket address support */ 1526 && addr->local.path[0] != 0 1527 # endif 1528 ) { 1529 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1530 return PR_FAILURE; 1531 } 1532 } 1533 1534 # ifdef _PR_INET6 1535 if (addr->raw.family == PR_AF_INET6) { 1536 # ifdef _PR_HAVE_SOCKADDR_LEN 1537 md_af = AF_INET6; 1538 # else 1539 addrCopy = *addr; 1540 addrCopy.raw.family = AF_INET6; 1541 addrp = &addrCopy; 1542 # endif 1543 } 1544 # endif 1545 1546 addr_len = PR_NETADDR_SIZE(addr); 1547 # ifdef _PR_HAVE_SOCKADDR_LEN 1548 addrCopy = *addr; 1549 ((struct sockaddr*)&addrCopy)->sa_len = addr_len; 1550 ((struct sockaddr*)&addrCopy)->sa_family = md_af; 1551 addrp = &addrCopy; 1552 # endif 1553 rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); 1554 1555 if (rv == -1) { 1556 pt_MapError(_PR_MD_MAP_BIND_ERROR, errno); 1557 return PR_FAILURE; 1558 } 1559 return PR_SUCCESS; 1560 } /* pt_Bind */ 1561 1562 static PRStatus pt_Listen(PRFileDesc* fd, PRIntn backlog) { 1563 PRIntn rv; 1564 1565 if (pt_TestAbort()) { 1566 return PR_FAILURE; 1567 } 1568 1569 rv = listen(fd->secret->md.osfd, backlog); 1570 if (rv == -1) { 1571 pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno); 1572 return PR_FAILURE; 1573 } 1574 return PR_SUCCESS; 1575 } /* pt_Listen */ 1576 1577 static PRStatus pt_Shutdown(PRFileDesc* fd, PRIntn how) { 1578 PRIntn rv = -1; 1579 if (pt_TestAbort()) { 1580 return PR_FAILURE; 1581 } 1582 1583 rv = shutdown(fd->secret->md.osfd, how); 1584 1585 if (rv == -1) { 1586 pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno); 1587 return PR_FAILURE; 1588 } 1589 return PR_SUCCESS; 1590 } /* pt_Shutdown */ 1591 1592 static PRInt16 pt_Poll(PRFileDesc* fd, PRInt16 in_flags, PRInt16* out_flags) { 1593 *out_flags = 0; 1594 return in_flags; 1595 } /* pt_Poll */ 1596 1597 static PRInt32 pt_Recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags, 1598 PRIntervalTime timeout) { 1599 PRInt32 syserrno, bytes = -1; 1600 PRIntn osflags; 1601 1602 if (0 == flags) { 1603 osflags = 0; 1604 } else if (PR_MSG_PEEK == flags) { 1605 osflags = MSG_PEEK; 1606 } else { 1607 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1608 return bytes; 1609 } 1610 1611 if (pt_TestAbort()) { 1612 return bytes; 1613 } 1614 1615 /* recv() is a much slower call on pre-2.6 Solaris than read(). */ 1616 # if defined(SOLARIS) 1617 if (0 == osflags) { 1618 bytes = read(fd->secret->md.osfd, buf, amount); 1619 } else { 1620 bytes = recv(fd->secret->md.osfd, buf, amount, osflags); 1621 } 1622 # else 1623 bytes = recv(fd->secret->md.osfd, buf, amount, osflags); 1624 # endif 1625 syserrno = errno; 1626 1627 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1628 (!fd->secret->nonblocking)) { 1629 if (PR_INTERVAL_NO_WAIT == timeout) { 1630 syserrno = ETIMEDOUT; 1631 } else { 1632 pt_Continuation op; 1633 op.arg1.osfd = fd->secret->md.osfd; 1634 op.arg2.buffer = buf; 1635 op.arg3.amount = amount; 1636 op.arg4.flags = osflags; 1637 op.timeout = timeout; 1638 op.function = pt_recv_cont; 1639 op.event = POLLIN | POLLPRI; 1640 bytes = pt_Continue(&op); 1641 syserrno = op.syserrno; 1642 } 1643 } 1644 if (bytes < 0) { 1645 pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno); 1646 } 1647 return bytes; 1648 } /* pt_Recv */ 1649 1650 static PRInt32 pt_SocketRead(PRFileDesc* fd, void* buf, PRInt32 amount) { 1651 return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); 1652 } /* pt_SocketRead */ 1653 1654 static PRInt32 pt_Send(PRFileDesc* fd, const void* buf, PRInt32 amount, 1655 PRIntn flags, PRIntervalTime timeout) { 1656 PRInt32 syserrno, bytes = -1; 1657 PRBool fNeedContinue = PR_FALSE; 1658 # if defined(SOLARIS) 1659 PRInt32 tmp_amount = amount; 1660 # endif 1661 1662 if (pt_TestAbort()) { 1663 return bytes; 1664 } 1665 1666 /* 1667 * On pre-2.6 Solaris, send() is much slower than write(). 1668 * On 2.6 and beyond, with in-kernel sockets, send() and 1669 * write() are fairly equivalent in performance. 1670 */ 1671 # if defined(SOLARIS) 1672 PR_ASSERT(0 == flags); 1673 retry: 1674 bytes = write(fd->secret->md.osfd, buf, tmp_amount); 1675 # else 1676 bytes = send(fd->secret->md.osfd, buf, amount, flags); 1677 # endif 1678 syserrno = errno; 1679 1680 # if defined(SOLARIS) 1681 /* 1682 * The write system call has been reported to return the ERANGE error 1683 * on occasion. Try to write in smaller chunks to workaround this bug. 1684 */ 1685 if ((bytes == -1) && (syserrno == ERANGE)) { 1686 if (tmp_amount > 1) { 1687 tmp_amount = tmp_amount / 2; /* half the bytes */ 1688 goto retry; 1689 } 1690 } 1691 # endif 1692 1693 if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) { 1694 if (PR_INTERVAL_NO_WAIT == timeout) { 1695 bytes = -1; 1696 syserrno = ETIMEDOUT; 1697 } else { 1698 buf = (char*)buf + bytes; 1699 amount -= bytes; 1700 fNeedContinue = PR_TRUE; 1701 } 1702 } 1703 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1704 (!fd->secret->nonblocking)) { 1705 if (PR_INTERVAL_NO_WAIT == timeout) { 1706 syserrno = ETIMEDOUT; 1707 } else { 1708 bytes = 0; 1709 fNeedContinue = PR_TRUE; 1710 } 1711 } 1712 1713 if (fNeedContinue == PR_TRUE) { 1714 pt_Continuation op; 1715 op.arg1.osfd = fd->secret->md.osfd; 1716 op.arg2.buffer = (void*)buf; 1717 op.arg3.amount = amount; 1718 op.arg4.flags = flags; 1719 op.timeout = timeout; 1720 op.result.code = bytes; /* initialize the number sent */ 1721 op.function = pt_send_cont; 1722 op.event = POLLOUT | POLLPRI; 1723 bytes = pt_Continue(&op); 1724 syserrno = op.syserrno; 1725 } 1726 if (bytes == -1) { 1727 pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno); 1728 } 1729 return bytes; 1730 } /* pt_Send */ 1731 1732 static PRInt32 pt_SocketWrite(PRFileDesc* fd, const void* buf, PRInt32 amount) { 1733 return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); 1734 } /* pt_SocketWrite */ 1735 1736 static PRInt32 pt_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount, 1737 PRIntn flags, const PRNetAddr* addr, 1738 PRIntervalTime timeout) { 1739 PRInt32 syserrno, bytes = -1; 1740 PRBool fNeedContinue = PR_FALSE; 1741 pt_SockLen addr_len; 1742 const PRNetAddr* addrp = addr; 1743 # if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) 1744 PRNetAddr addrCopy; 1745 # endif 1746 # ifdef _PR_HAVE_SOCKADDR_LEN 1747 PRUint16 md_af = addr->raw.family; 1748 # endif 1749 1750 if (pt_TestAbort()) { 1751 return bytes; 1752 } 1753 1754 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1755 # ifdef _PR_INET6 1756 if (addr->raw.family == PR_AF_INET6) { 1757 # ifdef _PR_HAVE_SOCKADDR_LEN 1758 md_af = AF_INET6; 1759 # else 1760 addrCopy = *addr; 1761 addrCopy.raw.family = AF_INET6; 1762 addrp = &addrCopy; 1763 # endif 1764 } 1765 # endif 1766 1767 addr_len = PR_NETADDR_SIZE(addr); 1768 # ifdef _PR_HAVE_SOCKADDR_LEN 1769 addrCopy = *addr; 1770 ((struct sockaddr*)&addrCopy)->sa_len = addr_len; 1771 ((struct sockaddr*)&addrCopy)->sa_family = md_af; 1772 addrp = &addrCopy; 1773 # endif 1774 bytes = sendto(fd->secret->md.osfd, buf, amount, flags, 1775 (struct sockaddr*)addrp, addr_len); 1776 syserrno = errno; 1777 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1778 (!fd->secret->nonblocking)) { 1779 if (PR_INTERVAL_NO_WAIT == timeout) { 1780 syserrno = ETIMEDOUT; 1781 } else { 1782 fNeedContinue = PR_TRUE; 1783 } 1784 } 1785 if (fNeedContinue == PR_TRUE) { 1786 pt_Continuation op; 1787 op.arg1.osfd = fd->secret->md.osfd; 1788 op.arg2.buffer = (void*)buf; 1789 op.arg3.amount = amount; 1790 op.arg4.flags = flags; 1791 op.arg5.addr = (PRNetAddr*)addrp; 1792 op.timeout = timeout; 1793 op.result.code = 0; /* initialize the number sent */ 1794 op.function = pt_sendto_cont; 1795 op.event = POLLOUT | POLLPRI; 1796 bytes = pt_Continue(&op); 1797 syserrno = op.syserrno; 1798 } 1799 if (bytes < 0) { 1800 pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno); 1801 } 1802 return bytes; 1803 } /* pt_SendTo */ 1804 1805 # if defined(LINUX) || defined(DARWIN) 1806 /* Linux uses SendTo to send data during TCP Fast Open. OSX uses connectx, but 1807 * we will make it imitate the Linux's interface. */ 1808 static PRInt32 pt_TCP_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount, 1809 PRIntn flags, const PRNetAddr* addr, 1810 PRIntervalTime timeout) { 1811 # if defined(LINUX) || HAS_CONNECTX 1812 PRInt32 syserrno; 1813 PRBool fNeedContinue = PR_FALSE; 1814 pt_SockLen addr_len; 1815 const PRNetAddr* addrp = addr; 1816 # if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) 1817 PRNetAddr addrCopy; 1818 # endif 1819 # ifdef _PR_HAVE_SOCKADDR_LEN 1820 PRUint16 md_af = addr->raw.family; 1821 # endif 1822 1823 if (pt_TestAbort()) { 1824 return -1; 1825 } 1826 1827 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 1828 addr_len = PR_NETADDR_SIZE(addr); 1829 # if defined(_PR_INET6) 1830 if (addr->raw.family == PR_AF_INET6) { 1831 # ifdef _PR_HAVE_SOCKADDR_LEN 1832 md_af = AF_INET6; 1833 # else 1834 /* If _PR_INET6 is defined and it is PR_AF_INET6 we set family 1835 * to AF_INET6. */ 1836 addrCopy = *addr; 1837 addrCopy.raw.family = AF_INET6; 1838 addrp = &addrCopy; 1839 # endif 1840 } 1841 # endif 1842 1843 # ifdef _PR_HAVE_SOCKADDR_LEN 1844 /* if _PR_HAVE_SOCKADDR_LEN is defined and it is PR_AF_INET6 we set family 1845 * to AF_INET6 and we set address length. */ 1846 addrCopy = *addr; 1847 ((struct sockaddr*)&addrCopy)->sa_len = addr_len; 1848 ((struct sockaddr*)&addrCopy)->sa_family = md_af; 1849 addrp = &addrCopy; 1850 # endif 1851 1852 size_t bytes = 0; 1853 PRInt32 netResult = 0; 1854 # ifndef HAS_CONNECTX 1855 netResult = sendto(fd->secret->md.osfd, buf, amount, MSG_FASTOPEN, 1856 (struct sockaddr*)addrp, addr_len); 1857 if (netResult >= 0) { 1858 bytes = netResult; 1859 } 1860 # else 1861 sa_endpoints_t endpoints; 1862 endpoints.sae_srcif = 0; 1863 endpoints.sae_srcaddr = NULL; 1864 endpoints.sae_srcaddrlen = 0; 1865 endpoints.sae_dstaddr = (struct sockaddr*)addrp; 1866 endpoints.sae_dstaddrlen = addr_len; 1867 struct iovec iov[1]; 1868 iov[0].iov_base = buf; 1869 iov[0].iov_len = amount; 1870 netResult = connectx(fd->secret->md.osfd, &endpoints, SAE_ASSOCID_ANY, 1871 CONNECT_DATA_IDEMPOTENT, iov, 1, &bytes, NULL); 1872 # endif 1873 syserrno = errno; 1874 if ((netResult < 0) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1875 (!fd->secret->nonblocking)) { 1876 if (PR_INTERVAL_NO_WAIT == timeout) { 1877 syserrno = ETIMEDOUT; 1878 } else { 1879 fNeedContinue = PR_TRUE; 1880 } 1881 } 1882 if (fNeedContinue == PR_TRUE) { 1883 pt_Continuation op; 1884 op.arg1.osfd = fd->secret->md.osfd; 1885 op.arg2.buffer = (void*)buf; 1886 op.arg3.amount = amount; 1887 op.arg4.flags = flags; 1888 op.arg5.addr = (PRNetAddr*)addrp; 1889 op.timeout = timeout; 1890 op.result.code = 0; /* initialize the number sent */ 1891 op.function = pt_sendto_cont; 1892 op.event = POLLOUT | POLLPRI; 1893 netResult = pt_Continue(&op); 1894 if (netResult >= 0) { 1895 bytes = netResult; 1896 } 1897 syserrno = op.syserrno; 1898 } 1899 if (netResult < 0) { 1900 pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno); 1901 return -1; 1902 } 1903 return bytes; 1904 # else /* !(defined(LINUX) || HAS_CONNECTX) */ 1905 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1906 return -1; 1907 # endif 1908 } /* pt_TCP_SendTo */ 1909 # endif /* LINUX || DARWIN */ 1910 1911 static PRInt32 pt_RecvFrom(PRFileDesc* fd, void* buf, PRInt32 amount, 1912 PRIntn flags, PRNetAddr* addr, 1913 PRIntervalTime timeout) { 1914 PRBool fNeedContinue = PR_FALSE; 1915 PRInt32 syserrno, bytes = -1; 1916 pt_SockLen addr_len = sizeof(PRNetAddr); 1917 1918 if (pt_TestAbort()) { 1919 return bytes; 1920 } 1921 1922 bytes = recvfrom(fd->secret->md.osfd, buf, amount, flags, 1923 (struct sockaddr*)addr, &addr_len); 1924 syserrno = errno; 1925 1926 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) && 1927 (!fd->secret->nonblocking)) { 1928 if (PR_INTERVAL_NO_WAIT == timeout) { 1929 syserrno = ETIMEDOUT; 1930 } else { 1931 fNeedContinue = PR_TRUE; 1932 } 1933 } 1934 1935 if (fNeedContinue == PR_TRUE) { 1936 pt_Continuation op; 1937 op.arg1.osfd = fd->secret->md.osfd; 1938 op.arg2.buffer = buf; 1939 op.arg3.amount = amount; 1940 op.arg4.flags = flags; 1941 op.arg5.addr = addr; 1942 op.timeout = timeout; 1943 op.function = pt_recvfrom_cont; 1944 op.event = POLLIN | POLLPRI; 1945 bytes = pt_Continue(&op); 1946 syserrno = op.syserrno; 1947 } 1948 if (bytes >= 0) { 1949 # ifdef _PR_HAVE_SOCKADDR_LEN 1950 /* ignore the sa_len field of struct sockaddr */ 1951 if (addr) { 1952 addr->raw.family = ((struct sockaddr*)addr)->sa_family; 1953 } 1954 # endif /* _PR_HAVE_SOCKADDR_LEN */ 1955 # ifdef _PR_INET6 1956 if (addr && (AF_INET6 == addr->raw.family)) { 1957 addr->raw.family = PR_AF_INET6; 1958 } 1959 # endif 1960 } else { 1961 pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno); 1962 } 1963 return bytes; 1964 } /* pt_RecvFrom */ 1965 1966 # ifdef AIX 1967 # ifndef HAVE_SEND_FILE 1968 static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT; 1969 1970 static void pt_aix_sendfile_init_routine(void) { 1971 void* handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); 1972 pt_aix_sendfile_fptr = (ssize_t(*)())dlsym(handle, "send_file"); 1973 dlclose(handle); 1974 } 1975 1976 /* 1977 * pt_AIXDispatchSendFile 1978 */ 1979 static PRInt32 pt_AIXDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd, 1980 PRTransmitFileFlags flags, 1981 PRIntervalTime timeout) { 1982 int rv; 1983 1984 rv = pthread_once(&pt_aix_sendfile_once_block, pt_aix_sendfile_init_routine); 1985 PR_ASSERT(0 == rv); 1986 if (pt_aix_sendfile_fptr) { 1987 return pt_AIXSendFile(sd, sfd, flags, timeout); 1988 } else { 1989 return PR_EmulateSendFile(sd, sfd, flags, timeout); 1990 } 1991 } 1992 # endif /* !HAVE_SEND_FILE */ 1993 1994 /* 1995 * pt_AIXSendFile 1996 * 1997 * Send file sfd->fd across socket sd. If specified, header and trailer 1998 * buffers are sent before and after the file, respectively. 1999 * 2000 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file 2001 * 2002 * return number of bytes sent or -1 on error 2003 * 2004 * This implementation takes advantage of the send_file() system 2005 * call available in AIX 4.3.2. 2006 */ 2007 2008 static PRInt32 pt_AIXSendFile(PRFileDesc* sd, PRSendFileData* sfd, 2009 PRTransmitFileFlags flags, 2010 PRIntervalTime timeout) { 2011 struct sf_parms sf_struct; 2012 uint_t send_flags; 2013 ssize_t rv; 2014 int syserrno; 2015 PRInt32 count; 2016 unsigned long long saved_file_offset; 2017 long long saved_file_bytes; 2018 2019 sf_struct.header_data = (void*)sfd->header; /* cast away the 'const' */ 2020 sf_struct.header_length = sfd->hlen; 2021 sf_struct.file_descriptor = sfd->fd->secret->md.osfd; 2022 sf_struct.file_size = 0; 2023 sf_struct.file_offset = sfd->file_offset; 2024 if (sfd->file_nbytes == 0) { 2025 sf_struct.file_bytes = -1; 2026 } else { 2027 sf_struct.file_bytes = sfd->file_nbytes; 2028 } 2029 sf_struct.trailer_data = (void*)sfd->trailer; 2030 sf_struct.trailer_length = sfd->tlen; 2031 sf_struct.bytes_sent = 0; 2032 2033 saved_file_offset = sf_struct.file_offset; 2034 saved_file_bytes = sf_struct.file_bytes; 2035 2036 send_flags = 0; /* flags processed at the end */ 2037 2038 /* The first argument to send_file() is int*. */ 2039 PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd)); 2040 do { 2041 rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags); 2042 } while (rv == -1 && (syserrno = errno) == EINTR); 2043 2044 if (rv == -1) { 2045 if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) { 2046 count = 0; /* Not a real error. Need to continue. */ 2047 } else { 2048 count = -1; 2049 } 2050 } else { 2051 count = sf_struct.bytes_sent; 2052 /* 2053 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from 2054 * being updated. So, 'file_bytes' is maintained by NSPR to 2055 * avoid conflict when this bug is fixed in AIX, in the future. 2056 */ 2057 if (saved_file_bytes != -1) { 2058 saved_file_bytes -= (sf_struct.file_offset - saved_file_offset); 2059 } 2060 sf_struct.file_bytes = saved_file_bytes; 2061 } 2062 2063 if ((rv == 1) || ((rv == -1) && (count == 0))) { 2064 pt_Continuation op; 2065 2066 op.arg1.osfd = sd->secret->md.osfd; 2067 op.arg2.buffer = &sf_struct; 2068 op.arg4.flags = send_flags; 2069 op.result.code = count; 2070 op.timeout = timeout; 2071 op.function = pt_aix_sendfile_cont; 2072 op.event = POLLOUT | POLLPRI; 2073 count = pt_Continue(&op); 2074 syserrno = op.syserrno; 2075 } 2076 2077 if (count == -1) { 2078 pt_MapError(_MD_aix_map_sendfile_error, syserrno); 2079 return -1; 2080 } 2081 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { 2082 PR_Close(sd); 2083 } 2084 PR_ASSERT(count == 2085 (sfd->hlen + sfd->tlen + 2086 ((sfd->file_nbytes == 0) ? sf_struct.file_size - sfd->file_offset 2087 : sfd->file_nbytes))); 2088 return count; 2089 } 2090 # endif /* AIX */ 2091 2092 # ifdef HPUX11 2093 /* 2094 * pt_HPUXSendFile 2095 * 2096 * Send file sfd->fd across socket sd. If specified, header and trailer 2097 * buffers are sent before and after the file, respectively. 2098 * 2099 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file 2100 * 2101 * return number of bytes sent or -1 on error 2102 * 2103 * This implementation takes advantage of the sendfile() system 2104 * call available in HP-UX B.11.00. 2105 */ 2106 2107 static PRInt32 pt_HPUXSendFile(PRFileDesc* sd, PRSendFileData* sfd, 2108 PRTransmitFileFlags flags, 2109 PRIntervalTime timeout) { 2110 struct stat statbuf; 2111 size_t nbytes_to_send, file_nbytes_to_send; 2112 struct iovec hdtrl[2]; /* optional header and trailer buffers */ 2113 int send_flags; 2114 PRInt32 count; 2115 int syserrno; 2116 2117 if (sfd->file_nbytes == 0) { 2118 /* Get file size */ 2119 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { 2120 _PR_MD_MAP_FSTAT_ERROR(errno); 2121 return -1; 2122 } 2123 file_nbytes_to_send = statbuf.st_size - sfd->file_offset; 2124 } else { 2125 file_nbytes_to_send = sfd->file_nbytes; 2126 } 2127 nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; 2128 2129 hdtrl[0].iov_base = (void*)sfd->header; /* cast away the 'const' */ 2130 hdtrl[0].iov_len = sfd->hlen; 2131 hdtrl[1].iov_base = (void*)sfd->trailer; 2132 hdtrl[1].iov_len = sfd->tlen; 2133 /* 2134 * SF_DISCONNECT seems to close the socket even if sendfile() 2135 * only does a partial send on a nonblocking socket. This 2136 * would prevent the subsequent sendfile() calls on that socket 2137 * from working. So we don't use the SD_DISCONNECT flag. 2138 */ 2139 send_flags = 0; 2140 2141 do { 2142 count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, 2143 sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags); 2144 } while (count == -1 && (syserrno = errno) == EINTR); 2145 2146 if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) { 2147 count = 0; 2148 } 2149 if (count != -1 && count < nbytes_to_send) { 2150 pt_Continuation op; 2151 2152 if (count < sfd->hlen) { 2153 /* header not sent */ 2154 2155 hdtrl[0].iov_base = ((char*)sfd->header) + count; 2156 hdtrl[0].iov_len = sfd->hlen - count; 2157 op.arg3.file_spec.offset = sfd->file_offset; 2158 op.arg3.file_spec.nbytes = file_nbytes_to_send; 2159 } else if (count < (sfd->hlen + file_nbytes_to_send)) { 2160 /* header sent, file not sent */ 2161 2162 hdtrl[0].iov_base = NULL; 2163 hdtrl[0].iov_len = 0; 2164 2165 op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen; 2166 op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen); 2167 } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) { 2168 PRUint32 trailer_nbytes_sent; 2169 2170 /* header sent, file sent, trailer not sent */ 2171 2172 hdtrl[0].iov_base = NULL; 2173 hdtrl[0].iov_len = 0; 2174 /* 2175 * set file offset and len so that no more file data is 2176 * sent 2177 */ 2178 op.arg3.file_spec.offset = statbuf.st_size; 2179 op.arg3.file_spec.nbytes = 0; 2180 2181 trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send; 2182 hdtrl[1].iov_base = ((char*)sfd->trailer) + trailer_nbytes_sent; 2183 hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent; 2184 } 2185 2186 op.arg1.osfd = sd->secret->md.osfd; 2187 op.filedesc = sfd->fd->secret->md.osfd; 2188 op.arg2.buffer = hdtrl; 2189 op.arg3.file_spec.st_size = statbuf.st_size; 2190 op.arg4.flags = send_flags; 2191 op.nbytes_to_send = nbytes_to_send - count; 2192 op.result.code = count; 2193 op.timeout = timeout; 2194 op.function = pt_hpux_sendfile_cont; 2195 op.event = POLLOUT | POLLPRI; 2196 count = pt_Continue(&op); 2197 syserrno = op.syserrno; 2198 } 2199 2200 if (count == -1) { 2201 pt_MapError(_MD_hpux_map_sendfile_error, syserrno); 2202 return -1; 2203 } 2204 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { 2205 PR_Close(sd); 2206 } 2207 PR_ASSERT(count == nbytes_to_send); 2208 return count; 2209 } 2210 2211 # endif /* HPUX11 */ 2212 2213 # ifdef SOLARIS 2214 2215 /* 2216 * pt_SolarisSendFile 2217 * 2218 * Send file sfd->fd across socket sd. If specified, header and trailer 2219 * buffers are sent before and after the file, respectively. 2220 * 2221 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file 2222 * 2223 * return number of bytes sent or -1 on error 2224 * 2225 * This implementation takes advantage of the sendfilev() system 2226 * call available in Solaris 8. 2227 */ 2228 2229 static PRInt32 pt_SolarisSendFile(PRFileDesc* sd, PRSendFileData* sfd, 2230 PRTransmitFileFlags flags, 2231 PRIntervalTime timeout) { 2232 struct stat statbuf; 2233 size_t nbytes_to_send, file_nbytes_to_send; 2234 struct sendfilevec sfv_struct[3]; 2235 int sfvcnt = 0; 2236 size_t xferred; 2237 PRInt32 count; 2238 int syserrno; 2239 2240 if (sfd->file_nbytes == 0) { 2241 /* Get file size */ 2242 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { 2243 _PR_MD_MAP_FSTAT_ERROR(errno); 2244 return -1; 2245 } 2246 file_nbytes_to_send = statbuf.st_size - sfd->file_offset; 2247 } else { 2248 file_nbytes_to_send = sfd->file_nbytes; 2249 } 2250 2251 nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; 2252 2253 if (sfd->hlen != 0) { 2254 sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; 2255 sfv_struct[sfvcnt].sfv_flag = 0; 2256 sfv_struct[sfvcnt].sfv_off = (off_t)sfd->header; 2257 sfv_struct[sfvcnt].sfv_len = sfd->hlen; 2258 sfvcnt++; 2259 } 2260 2261 if (file_nbytes_to_send != 0) { 2262 sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd; 2263 sfv_struct[sfvcnt].sfv_flag = 0; 2264 sfv_struct[sfvcnt].sfv_off = sfd->file_offset; 2265 sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send; 2266 sfvcnt++; 2267 } 2268 2269 if (sfd->tlen != 0) { 2270 sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; 2271 sfv_struct[sfvcnt].sfv_flag = 0; 2272 sfv_struct[sfvcnt].sfv_off = (off_t)sfd->trailer; 2273 sfv_struct[sfvcnt].sfv_len = sfd->tlen; 2274 sfvcnt++; 2275 } 2276 2277 if (0 == sfvcnt) { 2278 count = 0; 2279 goto done; 2280 } 2281 2282 /* 2283 * Strictly speaking, we may have sent some bytes when the 2284 * sendfilev() is interrupted and we should retry it from an 2285 * updated offset. We are not doing that here. 2286 */ 2287 count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct, sfvcnt, &xferred); 2288 2289 PR_ASSERT((count == -1) || (count == xferred)); 2290 2291 if (count == -1) { 2292 syserrno = errno; 2293 if (syserrno == EINTR || syserrno == EAGAIN || syserrno == EWOULDBLOCK) { 2294 count = xferred; 2295 } 2296 } else if (count == 0) { 2297 /* 2298 * We are now at EOF. The file was truncated. Solaris sendfile is 2299 * supposed to return 0 and no error in this case, though some versions 2300 * may return -1 and EINVAL . 2301 */ 2302 count = -1; 2303 syserrno = 0; /* will be treated as EOF */ 2304 } 2305 2306 if (count != -1 && count < nbytes_to_send) { 2307 pt_Continuation op; 2308 struct sendfilevec* vec = sfv_struct; 2309 PRInt32 rem = count; 2310 2311 while (rem >= vec->sfv_len) { 2312 rem -= vec->sfv_len; 2313 vec++; 2314 sfvcnt--; 2315 } 2316 PR_ASSERT(sfvcnt > 0); 2317 2318 vec->sfv_off += rem; 2319 vec->sfv_len -= rem; 2320 PR_ASSERT(vec->sfv_len > 0); 2321 2322 op.arg1.osfd = sd->secret->md.osfd; 2323 op.arg2.buffer = vec; 2324 op.arg3.amount = sfvcnt; 2325 op.arg4.flags = 0; 2326 op.nbytes_to_send = nbytes_to_send - count; 2327 op.result.code = count; 2328 op.timeout = timeout; 2329 op.function = pt_solaris_sendfile_cont; 2330 op.event = POLLOUT | POLLPRI; 2331 count = pt_Continue(&op); 2332 syserrno = op.syserrno; 2333 } 2334 2335 done: 2336 if (count == -1) { 2337 pt_MapError(_MD_solaris_map_sendfile_error, syserrno); 2338 return -1; 2339 } 2340 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { 2341 PR_Close(sd); 2342 } 2343 PR_ASSERT(count == nbytes_to_send); 2344 return count; 2345 } 2346 2347 # ifndef HAVE_SENDFILEV 2348 static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT; 2349 2350 static void pt_solaris_sendfilev_init_routine(void) { 2351 void* handle; 2352 PRBool close_it = PR_FALSE; 2353 2354 /* 2355 * We do not want to unload libsendfile.so. This handle is leaked 2356 * intentionally. 2357 */ 2358 handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL); 2359 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, 2360 ("dlopen(libsendfile.so) returns %p", handle)); 2361 2362 if (NULL == handle) { 2363 /* 2364 * The dlopen(0, mode) call is to allow for the possibility that 2365 * sendfilev() may become part of a standard system library in a 2366 * future Solaris release. 2367 */ 2368 handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL); 2369 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("dlopen(0) returns %p", handle)); 2370 close_it = PR_TRUE; 2371 } 2372 pt_solaris_sendfilev_fptr = (ssize_t(*)())dlsym(handle, "sendfilev"); 2373 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, 2374 ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr)); 2375 2376 if (close_it) { 2377 dlclose(handle); 2378 } 2379 } 2380 2381 /* 2382 * pt_SolarisDispatchSendFile 2383 */ 2384 static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd, 2385 PRTransmitFileFlags flags, 2386 PRIntervalTime timeout) { 2387 int rv; 2388 2389 rv = pthread_once(&pt_solaris_sendfilev_once_block, 2390 pt_solaris_sendfilev_init_routine); 2391 PR_ASSERT(0 == rv); 2392 if (pt_solaris_sendfilev_fptr) { 2393 return pt_SolarisSendFile(sd, sfd, flags, timeout); 2394 } else { 2395 return PR_EmulateSendFile(sd, sfd, flags, timeout); 2396 } 2397 } 2398 # endif /* !HAVE_SENDFILEV */ 2399 2400 # endif /* SOLARIS */ 2401 2402 # ifdef LINUX 2403 /* 2404 * pt_LinuxSendFile 2405 * 2406 * Send file sfd->fd across socket sd. If specified, header and trailer 2407 * buffers are sent before and after the file, respectively. 2408 * 2409 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file 2410 * 2411 * return number of bytes sent or -1 on error 2412 * 2413 * This implementation takes advantage of the sendfile() system 2414 * call available in Linux kernel 2.2 or higher. 2415 */ 2416 2417 static PRInt32 pt_LinuxSendFile(PRFileDesc* sd, PRSendFileData* sfd, 2418 PRTransmitFileFlags flags, 2419 PRIntervalTime timeout) { 2420 struct stat statbuf; 2421 size_t file_nbytes_to_send; 2422 PRInt32 count = 0; 2423 ssize_t rv; 2424 int syserrno; 2425 off_t offset; 2426 PRBool tcp_cork_enabled = PR_FALSE; 2427 int tcp_cork; 2428 2429 if (sfd->file_nbytes == 0) { 2430 /* Get file size */ 2431 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { 2432 _PR_MD_MAP_FSTAT_ERROR(errno); 2433 return -1; 2434 } 2435 file_nbytes_to_send = statbuf.st_size - sfd->file_offset; 2436 } else { 2437 file_nbytes_to_send = sfd->file_nbytes; 2438 } 2439 2440 if ((sfd->hlen != 0 || sfd->tlen != 0) && sd->secret->md.tcp_nodelay == 0) { 2441 tcp_cork = 1; 2442 if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork, 2443 sizeof tcp_cork) == 0) { 2444 tcp_cork_enabled = PR_TRUE; 2445 } else { 2446 syserrno = errno; 2447 if (syserrno != EINVAL) { 2448 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno); 2449 return -1; 2450 } 2451 /* 2452 * The most likely reason for the EINVAL error is that 2453 * TCP_NODELAY is set (with a function other than 2454 * PR_SetSocketOption). This is not fatal, so we keep 2455 * on going. 2456 */ 2457 PR_LOG(_pr_io_lm, PR_LOG_WARNING, 2458 ("pt_LinuxSendFile: " 2459 "setsockopt(TCP_CORK) failed with EINVAL\n")); 2460 } 2461 } 2462 2463 if (sfd->hlen != 0) { 2464 count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout); 2465 if (count == -1) { 2466 goto failed; 2467 } 2468 } 2469 2470 if (file_nbytes_to_send != 0) { 2471 offset = sfd->file_offset; 2472 do { 2473 rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, &offset, 2474 file_nbytes_to_send); 2475 } while (rv == -1 && (syserrno = errno) == EINTR); 2476 if (rv == -1) { 2477 if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) { 2478 _MD_linux_map_sendfile_error(syserrno); 2479 count = -1; 2480 goto failed; 2481 } 2482 rv = 0; 2483 } 2484 PR_ASSERT(rv == offset - sfd->file_offset); 2485 count += rv; 2486 2487 if (rv < file_nbytes_to_send) { 2488 pt_Continuation op; 2489 2490 op.arg1.osfd = sd->secret->md.osfd; 2491 op.in_fd = sfd->fd->secret->md.osfd; 2492 op.offset = offset; 2493 op.count = file_nbytes_to_send - rv; 2494 op.result.code = count; 2495 op.timeout = timeout; 2496 op.function = pt_linux_sendfile_cont; 2497 op.event = POLLOUT | POLLPRI; 2498 count = pt_Continue(&op); 2499 syserrno = op.syserrno; 2500 if (count == -1) { 2501 pt_MapError(_MD_linux_map_sendfile_error, syserrno); 2502 goto failed; 2503 } 2504 } 2505 } 2506 2507 if (sfd->tlen != 0) { 2508 rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); 2509 if (rv == -1) { 2510 count = -1; 2511 goto failed; 2512 } 2513 count += rv; 2514 } 2515 2516 failed: 2517 if (tcp_cork_enabled) { 2518 tcp_cork = 0; 2519 if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork, 2520 sizeof tcp_cork) == -1 && 2521 count != -1) { 2522 _PR_MD_MAP_SETSOCKOPT_ERROR(errno); 2523 count = -1; 2524 } 2525 } 2526 if (count != -1) { 2527 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { 2528 PR_Close(sd); 2529 } 2530 PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send); 2531 } 2532 return count; 2533 } 2534 # endif /* LINUX */ 2535 2536 # ifdef AIX 2537 extern int _pr_aix_send_file_use_disabled; 2538 # endif 2539 2540 static PRInt32 pt_SendFile(PRFileDesc* sd, PRSendFileData* sfd, 2541 PRTransmitFileFlags flags, PRIntervalTime timeout) { 2542 if (pt_TestAbort()) { 2543 return -1; 2544 } 2545 /* The socket must be in blocking mode. */ 2546 if (sd->secret->nonblocking) { 2547 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 2548 return -1; 2549 } 2550 # ifdef HPUX11 2551 return (pt_HPUXSendFile(sd, sfd, flags, timeout)); 2552 # elif defined(AIX) 2553 # ifdef HAVE_SEND_FILE 2554 /* 2555 * A bug in AIX 4.3.2 results in corruption of data transferred by 2556 * send_file(); AIX patch PTF U463956 contains the fix. A user can 2557 * disable the use of send_file function in NSPR, when this patch is 2558 * not installed on the system, by setting the envionment variable 2559 * NSPR_AIX_SEND_FILE_USE_DISABLED to 1. 2560 */ 2561 if (_pr_aix_send_file_use_disabled) { 2562 return (PR_EmulateSendFile(sd, sfd, flags, timeout)); 2563 } else { 2564 return (pt_AIXSendFile(sd, sfd, flags, timeout)); 2565 } 2566 # else 2567 return (PR_EmulateSendFile(sd, sfd, flags, timeout)); 2568 /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/ 2569 # endif /* HAVE_SEND_FILE */ 2570 # elif defined(SOLARIS) 2571 # ifdef HAVE_SENDFILEV 2572 return (pt_SolarisSendFile(sd, sfd, flags, timeout)); 2573 # else 2574 return (pt_SolarisDispatchSendFile(sd, sfd, flags, timeout)); 2575 # endif /* HAVE_SENDFILEV */ 2576 # elif defined(LINUX) 2577 return (pt_LinuxSendFile(sd, sfd, flags, timeout)); 2578 # else 2579 return (PR_EmulateSendFile(sd, sfd, flags, timeout)); 2580 # endif 2581 } 2582 2583 static PRInt32 pt_TransmitFile(PRFileDesc* sd, PRFileDesc* fd, 2584 const void* headers, PRInt32 hlen, 2585 PRTransmitFileFlags flags, 2586 PRIntervalTime timeout) { 2587 PRSendFileData sfd; 2588 2589 sfd.fd = fd; 2590 sfd.file_offset = 0; 2591 sfd.file_nbytes = 0; 2592 sfd.header = headers; 2593 sfd.hlen = hlen; 2594 sfd.trailer = NULL; 2595 sfd.tlen = 0; 2596 2597 return (pt_SendFile(sd, &sfd, flags, timeout)); 2598 } /* pt_TransmitFile */ 2599 2600 static PRInt32 pt_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr, 2601 void* buf, PRInt32 amount, 2602 PRIntervalTime timeout) { 2603 PRInt32 rv = -1; 2604 2605 if (pt_TestAbort()) { 2606 return rv; 2607 } 2608 /* The socket must be in blocking mode. */ 2609 if (sd->secret->nonblocking) { 2610 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 2611 return rv; 2612 } 2613 2614 rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); 2615 return rv; 2616 } /* pt_AcceptRead */ 2617 2618 static PRStatus pt_GetSockName(PRFileDesc* fd, PRNetAddr* addr) { 2619 PRIntn rv = -1; 2620 pt_SockLen addr_len = sizeof(PRNetAddr); 2621 2622 if (pt_TestAbort()) { 2623 return PR_FAILURE; 2624 } 2625 2626 rv = getsockname(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); 2627 if (rv == -1) { 2628 pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno); 2629 return PR_FAILURE; 2630 } 2631 # ifdef _PR_HAVE_SOCKADDR_LEN 2632 /* ignore the sa_len field of struct sockaddr */ 2633 if (addr) { 2634 addr->raw.family = ((struct sockaddr*)addr)->sa_family; 2635 } 2636 # endif /* _PR_HAVE_SOCKADDR_LEN */ 2637 # ifdef _PR_INET6 2638 if (AF_INET6 == addr->raw.family) { 2639 addr->raw.family = PR_AF_INET6; 2640 } 2641 # endif 2642 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 2643 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); 2644 return PR_SUCCESS; 2645 } /* pt_GetSockName */ 2646 2647 static PRStatus pt_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) { 2648 PRIntn rv = -1; 2649 pt_SockLen addr_len = sizeof(PRNetAddr); 2650 2651 if (pt_TestAbort()) { 2652 return PR_FAILURE; 2653 } 2654 2655 rv = getpeername(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); 2656 2657 if (rv == -1) { 2658 pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno); 2659 return PR_FAILURE; 2660 } 2661 # ifdef _PR_HAVE_SOCKADDR_LEN 2662 /* ignore the sa_len field of struct sockaddr */ 2663 if (addr) { 2664 addr->raw.family = ((struct sockaddr*)addr)->sa_family; 2665 } 2666 # endif /* _PR_HAVE_SOCKADDR_LEN */ 2667 # ifdef _PR_INET6 2668 if (AF_INET6 == addr->raw.family) { 2669 addr->raw.family = PR_AF_INET6; 2670 } 2671 # endif 2672 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); 2673 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); 2674 return PR_SUCCESS; 2675 } /* pt_GetPeerName */ 2676 2677 static PRStatus pt_GetSocketOption(PRFileDesc* fd, PRSocketOptionData* data) { 2678 PRIntn rv; 2679 pt_SockLen length; 2680 PRInt32 level, name; 2681 2682 /* 2683 * PR_SockOpt_Nonblocking is a special case that does not 2684 * translate to a getsockopt() call 2685 */ 2686 if (PR_SockOpt_Nonblocking == data->option) { 2687 data->value.non_blocking = fd->secret->nonblocking; 2688 return PR_SUCCESS; 2689 } 2690 2691 rv = _PR_MapOptionName(data->option, &level, &name); 2692 if (PR_SUCCESS == rv) { 2693 switch (data->option) { 2694 case PR_SockOpt_Linger: { 2695 struct linger linger; 2696 length = sizeof(linger); 2697 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&linger, 2698 &length); 2699 PR_ASSERT((-1 == rv) || (sizeof(linger) == length)); 2700 data->value.linger.polarity = (linger.l_onoff) ? PR_TRUE : PR_FALSE; 2701 data->value.linger.linger = PR_SecondsToInterval(linger.l_linger); 2702 break; 2703 } 2704 case PR_SockOpt_Reuseaddr: 2705 case PR_SockOpt_Keepalive: 2706 case PR_SockOpt_NoDelay: 2707 case PR_SockOpt_Broadcast: 2708 case PR_SockOpt_Reuseport: { 2709 PRIntn value; 2710 length = sizeof(PRIntn); 2711 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2712 &length); 2713 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); 2714 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; 2715 break; 2716 } 2717 case PR_SockOpt_McastLoopback: { 2718 PRUint8 xbool; 2719 length = sizeof(xbool); 2720 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&xbool, 2721 &length); 2722 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length)); 2723 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE; 2724 break; 2725 } 2726 case PR_SockOpt_RecvBufferSize: 2727 case PR_SockOpt_SendBufferSize: 2728 case PR_SockOpt_MaxSegment: { 2729 PRIntn value; 2730 length = sizeof(PRIntn); 2731 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2732 &length); 2733 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); 2734 data->value.recv_buffer_size = value; 2735 break; 2736 } 2737 case PR_SockOpt_IpTimeToLive: 2738 case PR_SockOpt_IpTypeOfService: { 2739 length = sizeof(PRUintn); 2740 rv = getsockopt(fd->secret->md.osfd, level, name, 2741 (char*)&data->value.ip_ttl, &length); 2742 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); 2743 break; 2744 } 2745 case PR_SockOpt_McastTimeToLive: { 2746 PRUint8 ttl; 2747 length = sizeof(ttl); 2748 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&ttl, &length); 2749 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length)); 2750 data->value.mcast_ttl = ttl; 2751 break; 2752 } 2753 case PR_SockOpt_AddMember: 2754 case PR_SockOpt_DropMember: { 2755 struct ip_mreq mreq; 2756 length = sizeof(mreq); 2757 rv = 2758 getsockopt(fd->secret->md.osfd, level, name, (char*)&mreq, &length); 2759 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length)); 2760 data->value.add_member.mcaddr.inet.ip = mreq.imr_multiaddr.s_addr; 2761 data->value.add_member.ifaddr.inet.ip = mreq.imr_interface.s_addr; 2762 break; 2763 } 2764 case PR_SockOpt_McastInterface: { 2765 length = sizeof(data->value.mcast_if.inet.ip); 2766 rv = getsockopt(fd->secret->md.osfd, level, name, 2767 (char*)&data->value.mcast_if.inet.ip, &length); 2768 PR_ASSERT((-1 == rv) || 2769 (sizeof(data->value.mcast_if.inet.ip) == length)); 2770 break; 2771 } 2772 case PR_SockOpt_DontFrag: { 2773 # if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID) 2774 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); 2775 rv = PR_FAILURE; 2776 # else 2777 PRIntn value; 2778 length = sizeof(value); 2779 rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2780 &length); 2781 # if defined(DARWIN) 2782 data->value.dont_fragment = value; 2783 # else 2784 data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0; 2785 # endif 2786 # endif /* !(!defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */ 2787 break; 2788 } 2789 default: 2790 PR_NOT_REACHED("Unknown socket option"); 2791 break; 2792 } 2793 if (-1 == rv) { 2794 _PR_MD_MAP_GETSOCKOPT_ERROR(errno); 2795 } 2796 } 2797 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 2798 } /* pt_GetSocketOption */ 2799 2800 static PRStatus pt_SetSocketOption(PRFileDesc* fd, 2801 const PRSocketOptionData* data) { 2802 PRIntn rv; 2803 PRInt32 level, name; 2804 2805 /* 2806 * PR_SockOpt_Nonblocking is a special case that does not 2807 * translate to a setsockopt call. 2808 */ 2809 if (PR_SockOpt_Nonblocking == data->option) { 2810 fd->secret->nonblocking = data->value.non_blocking; 2811 return PR_SUCCESS; 2812 } 2813 2814 rv = _PR_MapOptionName(data->option, &level, &name); 2815 if (PR_SUCCESS == rv) { 2816 switch (data->option) { 2817 case PR_SockOpt_Linger: { 2818 struct linger linger; 2819 linger.l_onoff = data->value.linger.polarity; 2820 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); 2821 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&linger, 2822 sizeof(linger)); 2823 break; 2824 } 2825 case PR_SockOpt_Reuseaddr: 2826 case PR_SockOpt_Keepalive: 2827 case PR_SockOpt_NoDelay: 2828 case PR_SockOpt_Broadcast: 2829 case PR_SockOpt_Reuseport: { 2830 PRIntn value = (data->value.reuse_addr) ? 1 : 0; 2831 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2832 sizeof(PRIntn)); 2833 # ifdef LINUX 2834 /* for pt_LinuxSendFile */ 2835 if (name == TCP_NODELAY && rv == 0) { 2836 fd->secret->md.tcp_nodelay = value; 2837 } 2838 # endif 2839 break; 2840 } 2841 case PR_SockOpt_McastLoopback: { 2842 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0; 2843 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&xbool, 2844 sizeof(xbool)); 2845 break; 2846 } 2847 case PR_SockOpt_RecvBufferSize: 2848 case PR_SockOpt_SendBufferSize: 2849 case PR_SockOpt_MaxSegment: { 2850 PRIntn value = data->value.recv_buffer_size; 2851 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2852 sizeof(PRIntn)); 2853 break; 2854 } 2855 case PR_SockOpt_IpTimeToLive: 2856 case PR_SockOpt_IpTypeOfService: { 2857 rv = setsockopt(fd->secret->md.osfd, level, name, 2858 (char*)&data->value.ip_ttl, sizeof(PRUintn)); 2859 break; 2860 } 2861 case PR_SockOpt_McastTimeToLive: { 2862 PRUint8 ttl = data->value.mcast_ttl; 2863 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&ttl, 2864 sizeof(ttl)); 2865 break; 2866 } 2867 case PR_SockOpt_AddMember: 2868 case PR_SockOpt_DropMember: { 2869 struct ip_mreq mreq; 2870 mreq.imr_multiaddr.s_addr = data->value.add_member.mcaddr.inet.ip; 2871 mreq.imr_interface.s_addr = data->value.add_member.ifaddr.inet.ip; 2872 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&mreq, 2873 sizeof(mreq)); 2874 break; 2875 } 2876 case PR_SockOpt_McastInterface: { 2877 rv = setsockopt(fd->secret->md.osfd, level, name, 2878 (char*)&data->value.mcast_if.inet.ip, 2879 sizeof(data->value.mcast_if.inet.ip)); 2880 break; 2881 } 2882 case PR_SockOpt_DontFrag: { 2883 # if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID) 2884 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); 2885 rv = PR_FAILURE; 2886 # else 2887 PRIntn value; 2888 # if defined(LINUX) || defined(ANDROID) 2889 value = (data->value.dont_fragment) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; 2890 # elif defined(DARWIN) 2891 value = data->value.dont_fragment; 2892 # endif 2893 rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value, 2894 sizeof(value)); 2895 # endif /* !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */ 2896 break; 2897 } 2898 default: 2899 PR_NOT_REACHED("Unknown socket option"); 2900 break; 2901 } 2902 if (-1 == rv) { 2903 _PR_MD_MAP_SETSOCKOPT_ERROR(errno); 2904 } 2905 } 2906 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 2907 } /* pt_SetSocketOption */ 2908 2909 /*****************************************************************************/ 2910 /****************************** I/O method objects ***************************/ 2911 /*****************************************************************************/ 2912 2913 static PRIOMethods _pr_file_methods = {PR_DESC_FILE, 2914 pt_Close, 2915 pt_Read, 2916 pt_Write, 2917 pt_Available_f, 2918 pt_Available64_f, 2919 pt_Fsync, 2920 pt_Seek, 2921 pt_Seek64, 2922 pt_FileInfo, 2923 pt_FileInfo64, 2924 (PRWritevFN)_PR_InvalidInt, 2925 (PRConnectFN)_PR_InvalidStatus, 2926 (PRAcceptFN)_PR_InvalidDesc, 2927 (PRBindFN)_PR_InvalidStatus, 2928 (PRListenFN)_PR_InvalidStatus, 2929 (PRShutdownFN)_PR_InvalidStatus, 2930 (PRRecvFN)_PR_InvalidInt, 2931 (PRSendFN)_PR_InvalidInt, 2932 (PRRecvfromFN)_PR_InvalidInt, 2933 (PRSendtoFN)_PR_InvalidInt, 2934 pt_Poll, 2935 (PRAcceptreadFN)_PR_InvalidInt, 2936 (PRTransmitfileFN)_PR_InvalidInt, 2937 (PRGetsocknameFN)_PR_InvalidStatus, 2938 (PRGetpeernameFN)_PR_InvalidStatus, 2939 (PRReservedFN)_PR_InvalidInt, 2940 (PRReservedFN)_PR_InvalidInt, 2941 (PRGetsocketoptionFN)_PR_InvalidStatus, 2942 (PRSetsocketoptionFN)_PR_InvalidStatus, 2943 (PRSendfileFN)_PR_InvalidInt, 2944 (PRConnectcontinueFN)_PR_InvalidStatus, 2945 (PRReservedFN)_PR_InvalidInt, 2946 (PRReservedFN)_PR_InvalidInt, 2947 (PRReservedFN)_PR_InvalidInt, 2948 (PRReservedFN)_PR_InvalidInt}; 2949 2950 static PRIOMethods _pr_pipe_methods = {PR_DESC_PIPE, 2951 pt_Close, 2952 pt_Read, 2953 pt_Write, 2954 pt_Available_s, 2955 pt_Available64_s, 2956 pt_Synch, 2957 (PRSeekFN)_PR_InvalidInt, 2958 (PRSeek64FN)_PR_InvalidInt64, 2959 (PRFileInfoFN)_PR_InvalidStatus, 2960 (PRFileInfo64FN)_PR_InvalidStatus, 2961 (PRWritevFN)_PR_InvalidInt, 2962 (PRConnectFN)_PR_InvalidStatus, 2963 (PRAcceptFN)_PR_InvalidDesc, 2964 (PRBindFN)_PR_InvalidStatus, 2965 (PRListenFN)_PR_InvalidStatus, 2966 (PRShutdownFN)_PR_InvalidStatus, 2967 (PRRecvFN)_PR_InvalidInt, 2968 (PRSendFN)_PR_InvalidInt, 2969 (PRRecvfromFN)_PR_InvalidInt, 2970 (PRSendtoFN)_PR_InvalidInt, 2971 pt_Poll, 2972 (PRAcceptreadFN)_PR_InvalidInt, 2973 (PRTransmitfileFN)_PR_InvalidInt, 2974 (PRGetsocknameFN)_PR_InvalidStatus, 2975 (PRGetpeernameFN)_PR_InvalidStatus, 2976 (PRReservedFN)_PR_InvalidInt, 2977 (PRReservedFN)_PR_InvalidInt, 2978 (PRGetsocketoptionFN)_PR_InvalidStatus, 2979 (PRSetsocketoptionFN)_PR_InvalidStatus, 2980 (PRSendfileFN)_PR_InvalidInt, 2981 (PRConnectcontinueFN)_PR_InvalidStatus, 2982 (PRReservedFN)_PR_InvalidInt, 2983 (PRReservedFN)_PR_InvalidInt, 2984 (PRReservedFN)_PR_InvalidInt, 2985 (PRReservedFN)_PR_InvalidInt}; 2986 2987 static PRIOMethods _pr_tcp_methods = { 2988 PR_DESC_SOCKET_TCP, 2989 pt_Close, 2990 pt_SocketRead, 2991 pt_SocketWrite, 2992 pt_Available_s, 2993 pt_Available64_s, 2994 pt_Synch, 2995 (PRSeekFN)_PR_InvalidInt, 2996 (PRSeek64FN)_PR_InvalidInt64, 2997 (PRFileInfoFN)_PR_InvalidStatus, 2998 (PRFileInfo64FN)_PR_InvalidStatus, 2999 pt_Writev, 3000 pt_Connect, 3001 pt_Accept, 3002 pt_Bind, 3003 pt_Listen, 3004 pt_Shutdown, 3005 pt_Recv, 3006 pt_Send, 3007 (PRRecvfromFN)_PR_InvalidInt, 3008 # if defined(LINUX) || defined(DARWIN) 3009 pt_TCP_SendTo, /* This is for TCP Fast Open. Linux uses SendTo function for 3010 this. OSX uses connectx, but we imitate Linux. */ 3011 # else 3012 (PRSendtoFN)_PR_InvalidInt, 3013 # endif 3014 pt_Poll, 3015 pt_AcceptRead, 3016 pt_TransmitFile, 3017 pt_GetSockName, 3018 pt_GetPeerName, 3019 (PRReservedFN)_PR_InvalidInt, 3020 (PRReservedFN)_PR_InvalidInt, 3021 pt_GetSocketOption, 3022 pt_SetSocketOption, 3023 pt_SendFile, 3024 pt_ConnectContinue, 3025 (PRReservedFN)_PR_InvalidInt, 3026 (PRReservedFN)_PR_InvalidInt, 3027 (PRReservedFN)_PR_InvalidInt, 3028 (PRReservedFN)_PR_InvalidInt}; 3029 3030 static PRIOMethods _pr_udp_methods = {PR_DESC_SOCKET_UDP, 3031 pt_Close, 3032 pt_SocketRead, 3033 pt_SocketWrite, 3034 pt_Available_s, 3035 pt_Available64_s, 3036 pt_Synch, 3037 (PRSeekFN)_PR_InvalidInt, 3038 (PRSeek64FN)_PR_InvalidInt64, 3039 (PRFileInfoFN)_PR_InvalidStatus, 3040 (PRFileInfo64FN)_PR_InvalidStatus, 3041 pt_Writev, 3042 pt_Connect, 3043 (PRAcceptFN)_PR_InvalidDesc, 3044 pt_Bind, 3045 pt_Listen, 3046 pt_Shutdown, 3047 pt_Recv, 3048 pt_Send, 3049 pt_RecvFrom, 3050 pt_SendTo, 3051 pt_Poll, 3052 (PRAcceptreadFN)_PR_InvalidInt, 3053 (PRTransmitfileFN)_PR_InvalidInt, 3054 pt_GetSockName, 3055 pt_GetPeerName, 3056 (PRReservedFN)_PR_InvalidInt, 3057 (PRReservedFN)_PR_InvalidInt, 3058 pt_GetSocketOption, 3059 pt_SetSocketOption, 3060 (PRSendfileFN)_PR_InvalidInt, 3061 (PRConnectcontinueFN)_PR_InvalidStatus, 3062 (PRReservedFN)_PR_InvalidInt, 3063 (PRReservedFN)_PR_InvalidInt, 3064 (PRReservedFN)_PR_InvalidInt, 3065 (PRReservedFN)_PR_InvalidInt}; 3066 3067 static PRIOMethods _pr_socketpollfd_methods = { 3068 (PRDescType)0, 3069 (PRCloseFN)_PR_InvalidStatus, 3070 (PRReadFN)_PR_InvalidInt, 3071 (PRWriteFN)_PR_InvalidInt, 3072 (PRAvailableFN)_PR_InvalidInt, 3073 (PRAvailable64FN)_PR_InvalidInt64, 3074 (PRFsyncFN)_PR_InvalidStatus, 3075 (PRSeekFN)_PR_InvalidInt, 3076 (PRSeek64FN)_PR_InvalidInt64, 3077 (PRFileInfoFN)_PR_InvalidStatus, 3078 (PRFileInfo64FN)_PR_InvalidStatus, 3079 (PRWritevFN)_PR_InvalidInt, 3080 (PRConnectFN)_PR_InvalidStatus, 3081 (PRAcceptFN)_PR_InvalidDesc, 3082 (PRBindFN)_PR_InvalidStatus, 3083 (PRListenFN)_PR_InvalidStatus, 3084 (PRShutdownFN)_PR_InvalidStatus, 3085 (PRRecvFN)_PR_InvalidInt, 3086 (PRSendFN)_PR_InvalidInt, 3087 (PRRecvfromFN)_PR_InvalidInt, 3088 (PRSendtoFN)_PR_InvalidInt, 3089 pt_Poll, 3090 (PRAcceptreadFN)_PR_InvalidInt, 3091 (PRTransmitfileFN)_PR_InvalidInt, 3092 (PRGetsocknameFN)_PR_InvalidStatus, 3093 (PRGetpeernameFN)_PR_InvalidStatus, 3094 (PRReservedFN)_PR_InvalidInt, 3095 (PRReservedFN)_PR_InvalidInt, 3096 (PRGetsocketoptionFN)_PR_InvalidStatus, 3097 (PRSetsocketoptionFN)_PR_InvalidStatus, 3098 (PRSendfileFN)_PR_InvalidInt, 3099 (PRConnectcontinueFN)_PR_InvalidStatus, 3100 (PRReservedFN)_PR_InvalidInt, 3101 (PRReservedFN)_PR_InvalidInt, 3102 (PRReservedFN)_PR_InvalidInt, 3103 (PRReservedFN)_PR_InvalidInt}; 3104 3105 # if defined(SOLARIS) || defined(LINUX) || \ 3106 defined(__GNU__) || defined(__GLIBC__) || defined(AIX) || \ 3107 defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \ 3108 defined(NTO) || defined(DARWIN) || defined(RISCOS) 3109 # define _PR_FCNTL_FLAGS O_NONBLOCK 3110 # else 3111 # error "Can't determine architecture" 3112 # endif 3113 3114 /* 3115 * Put a Unix file descriptor in non-blocking mode. 3116 */ 3117 static void pt_MakeFdNonblock(PRIntn osfd) { 3118 PRIntn flags; 3119 flags = fcntl(osfd, F_GETFL, 0); 3120 flags |= _PR_FCNTL_FLAGS; 3121 (void)fcntl(osfd, F_SETFL, flags); 3122 } 3123 3124 /* 3125 * Put a Unix socket fd in non-blocking mode that can 3126 * ideally be inherited by an accepted socket. 3127 * 3128 * Why doesn't pt_MakeFdNonblock do? This is to deal with 3129 * the special case of HP-UX. HP-UX has three kinds of 3130 * non-blocking modes for sockets: the fcntl() O_NONBLOCK 3131 * and O_NDELAY flags and ioctl() FIOSNBIO request. Only 3132 * the ioctl() FIOSNBIO form of non-blocking mode is 3133 * inherited by an accepted socket. 3134 * 3135 * Other platforms just use the generic pt_MakeFdNonblock 3136 * to put a socket in non-blocking mode. 3137 */ 3138 # define pt_MakeSocketNonblock pt_MakeFdNonblock 3139 3140 static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type, 3141 PRBool isAcceptedSocket, PRBool imported) { 3142 PRFileDesc* fd = _PR_Getfd(); 3143 3144 if (fd == NULL) { 3145 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 3146 } else { 3147 fd->secret->md.osfd = osfd; 3148 fd->secret->state = _PR_FILEDESC_OPEN; 3149 if (imported) { 3150 fd->secret->inheritable = _PR_TRI_UNKNOWN; 3151 } else { 3152 /* By default, a Unix fd is not closed on exec. */ 3153 # ifdef DEBUG 3154 PRIntn flags; 3155 flags = fcntl(osfd, F_GETFD, 0); 3156 PR_ASSERT(0 == flags); 3157 # endif 3158 fd->secret->inheritable = _PR_TRI_TRUE; 3159 } 3160 switch (type) { 3161 case PR_DESC_FILE: 3162 fd->methods = PR_GetFileMethods(); 3163 break; 3164 case PR_DESC_SOCKET_TCP: 3165 fd->methods = PR_GetTCPMethods(); 3166 # ifdef _PR_ACCEPT_INHERIT_NONBLOCK 3167 if (!isAcceptedSocket) { 3168 pt_MakeSocketNonblock(osfd); 3169 } 3170 # else 3171 pt_MakeSocketNonblock(osfd); 3172 # endif 3173 break; 3174 case PR_DESC_SOCKET_UDP: 3175 fd->methods = PR_GetUDPMethods(); 3176 pt_MakeFdNonblock(osfd); 3177 break; 3178 case PR_DESC_PIPE: 3179 fd->methods = PR_GetPipeMethods(); 3180 pt_MakeFdNonblock(osfd); 3181 break; 3182 default: 3183 break; 3184 } 3185 } 3186 return fd; 3187 } /* pt_SetMethods */ 3188 3189 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) { 3190 return &_pr_file_methods; 3191 } /* PR_GetFileMethods */ 3192 3193 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) { 3194 return &_pr_pipe_methods; 3195 } /* PR_GetPipeMethods */ 3196 3197 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void) { 3198 return &_pr_tcp_methods; 3199 } /* PR_GetTCPMethods */ 3200 3201 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void) { 3202 return &_pr_udp_methods; 3203 } /* PR_GetUDPMethods */ 3204 3205 static const PRIOMethods* PR_GetSocketPollFdMethods(void) { 3206 return &_pr_socketpollfd_methods; 3207 } /* PR_GetSocketPollFdMethods */ 3208 3209 PR_IMPLEMENT(PRFileDesc*) 3210 PR_AllocFileDesc(PRInt32 osfd, const PRIOMethods* methods) { 3211 PRFileDesc* fd = _PR_Getfd(); 3212 3213 if (NULL == fd) { 3214 goto failed; 3215 } 3216 3217 fd->methods = methods; 3218 fd->secret->md.osfd = osfd; 3219 /* Make fd non-blocking */ 3220 if (osfd > 2) { 3221 /* Don't mess around with stdin, stdout or stderr */ 3222 if (&_pr_tcp_methods == methods) { 3223 pt_MakeSocketNonblock(osfd); 3224 } else { 3225 pt_MakeFdNonblock(osfd); 3226 } 3227 } 3228 fd->secret->state = _PR_FILEDESC_OPEN; 3229 fd->secret->inheritable = _PR_TRI_UNKNOWN; 3230 return fd; 3231 3232 failed: 3233 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 3234 return fd; 3235 } /* PR_AllocFileDesc */ 3236 3237 # if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) 3238 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd); 3239 # if defined(_PR_INET6_PROBE) 3240 extern PRBool _pr_ipv6_is_present(void); 3241 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() { 3242 int osfd; 3243 3244 # if defined(DARWIN) 3245 /* 3246 * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3). IPv6 on 3247 * lesser versions is not ready for general use (see bug 222031). 3248 */ 3249 { 3250 struct utsname u; 3251 if (uname(&u) != 0 || atoi(u.release) < 7) { 3252 return PR_FALSE; 3253 } 3254 } 3255 # endif 3256 3257 /* 3258 * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001) 3259 * suggests that we call open("/dev/ip6", O_RDWR) to determine 3260 * whether IPv6 APIs and the IPv6 stack are on the system. 3261 * Our portable test below seems to work fine, so I am using it. 3262 */ 3263 osfd = socket(AF_INET6, SOCK_STREAM, 0); 3264 if (osfd != -1) { 3265 close(osfd); 3266 return PR_TRUE; 3267 } 3268 return PR_FALSE; 3269 } 3270 # endif /* _PR_INET6_PROBE */ 3271 # endif 3272 3273 PR_IMPLEMENT(PRFileDesc*) 3274 PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) { 3275 PRIntn osfd; 3276 PRDescType ftype; 3277 PRFileDesc* fd = NULL; 3278 # if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) 3279 PRInt32 tmp_domain = domain; 3280 # endif 3281 3282 if (!_pr_initialized) { 3283 _PR_ImplicitInitialization(); 3284 } 3285 3286 if (pt_TestAbort()) { 3287 return NULL; 3288 } 3289 3290 if (PF_INET != domain && PR_AF_INET6 != domain 3291 # if defined(_PR_HAVE_SDP) 3292 && PR_AF_INET_SDP != domain 3293 # if defined(SOLARIS) 3294 && PR_AF_INET6_SDP != domain 3295 # endif /* SOLARIS */ 3296 # endif /* _PR_HAVE_SDP */ 3297 && PF_UNIX != domain) { 3298 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 3299 return fd; 3300 } 3301 if (type == SOCK_STREAM) { 3302 ftype = PR_DESC_SOCKET_TCP; 3303 } else if (type == SOCK_DGRAM) { 3304 ftype = PR_DESC_SOCKET_UDP; 3305 } else { 3306 (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 3307 return fd; 3308 } 3309 # if defined(_PR_HAVE_SDP) 3310 # if defined(LINUX) 3311 if (PR_AF_INET_SDP == domain) { 3312 domain = AF_INET_SDP; 3313 } 3314 # elif defined(SOLARIS) 3315 if (PR_AF_INET_SDP == domain) { 3316 domain = AF_INET; 3317 proto = PROTO_SDP; 3318 } else if (PR_AF_INET6_SDP == domain) { 3319 domain = AF_INET6; 3320 proto = PROTO_SDP; 3321 } 3322 # endif /* SOLARIS */ 3323 # endif /* _PR_HAVE_SDP */ 3324 # if defined(_PR_INET6_PROBE) 3325 if (PR_AF_INET6 == domain) { 3326 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; 3327 } 3328 # elif defined(_PR_INET6) 3329 if (PR_AF_INET6 == domain) { 3330 domain = AF_INET6; 3331 } 3332 # else 3333 if (PR_AF_INET6 == domain) { 3334 domain = AF_INET; 3335 } 3336 # endif 3337 3338 osfd = socket(domain, type, proto); 3339 if (osfd == -1) { 3340 pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno); 3341 } else { 3342 # ifdef _PR_IPV6_V6ONLY_PROBE 3343 if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default) { 3344 int on = 0; 3345 (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); 3346 } 3347 # endif 3348 fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE); 3349 if (fd == NULL) { 3350 close(osfd); 3351 } 3352 } 3353 # ifdef _PR_NEED_SECRET_AF 3354 if (fd != NULL) { 3355 fd->secret->af = domain; 3356 } 3357 # endif 3358 # if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) 3359 if (fd != NULL) { 3360 /* 3361 * For platforms with no support for IPv6 3362 * create layered socket for IPv4-mapped IPv6 addresses 3363 */ 3364 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { 3365 if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { 3366 PR_Close(fd); 3367 fd = NULL; 3368 } 3369 } 3370 } 3371 # endif 3372 return fd; 3373 } /* PR_Socket */ 3374 3375 /*****************************************************************************/ 3376 /****************************** I/O public methods ***************************/ 3377 /*****************************************************************************/ 3378 3379 PR_IMPLEMENT(PRFileDesc*) 3380 PR_OpenFile(const char* name, PRIntn flags, PRIntn mode) { 3381 PRFileDesc* fd = NULL; 3382 PRIntn syserrno, osfd = -1, osflags = 0; 3383 ; 3384 3385 if (!_pr_initialized) { 3386 _PR_ImplicitInitialization(); 3387 } 3388 3389 if (pt_TestAbort()) { 3390 return NULL; 3391 } 3392 3393 if (flags & PR_RDONLY) { 3394 osflags |= O_RDONLY; 3395 } 3396 if (flags & PR_WRONLY) { 3397 osflags |= O_WRONLY; 3398 } 3399 if (flags & PR_RDWR) { 3400 osflags |= O_RDWR; 3401 } 3402 if (flags & PR_APPEND) { 3403 osflags |= O_APPEND; 3404 } 3405 if (flags & PR_TRUNCATE) { 3406 osflags |= O_TRUNC; 3407 } 3408 if (flags & PR_EXCL) { 3409 osflags |= O_EXCL; 3410 } 3411 if (flags & PR_SYNC) { 3412 # if defined(O_SYNC) 3413 osflags |= O_SYNC; 3414 # elif defined(O_FSYNC) 3415 osflags |= O_FSYNC; 3416 # else 3417 # error "Neither O_SYNC nor O_FSYNC is defined on this platform" 3418 # endif 3419 } 3420 3421 /* 3422 ** We have to hold the lock across the creation in order to 3423 ** enforce the sematics of PR_Rename(). (see the latter for 3424 ** more details) 3425 */ 3426 if (flags & PR_CREATE_FILE) { 3427 osflags |= O_CREAT; 3428 if (NULL != _pr_rename_lock) { 3429 PR_Lock(_pr_rename_lock); 3430 } 3431 } 3432 3433 osfd = _md_iovector._open64(name, osflags, mode); 3434 syserrno = errno; 3435 3436 if ((flags & PR_CREATE_FILE) && (NULL != _pr_rename_lock)) { 3437 PR_Unlock(_pr_rename_lock); 3438 } 3439 3440 if (osfd == -1) { 3441 pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno); 3442 } else { 3443 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE); 3444 if (fd == NULL) { 3445 close(osfd); /* $$$ whoops! this is bad $$$ */ 3446 } 3447 } 3448 return fd; 3449 } /* PR_OpenFile */ 3450 3451 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char* name, PRIntn flags, PRIntn mode) { 3452 return PR_OpenFile(name, flags, mode); 3453 } /* PR_Open */ 3454 3455 PR_IMPLEMENT(PRStatus) PR_Delete(const char* name) { 3456 PRIntn rv = -1; 3457 3458 if (!_pr_initialized) { 3459 _PR_ImplicitInitialization(); 3460 } 3461 3462 if (pt_TestAbort()) { 3463 return PR_FAILURE; 3464 } 3465 3466 rv = unlink(name); 3467 3468 if (rv == -1) { 3469 pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno); 3470 return PR_FAILURE; 3471 } 3472 return PR_SUCCESS; 3473 } /* PR_Delete */ 3474 3475 PR_IMPLEMENT(PRStatus) PR_Access(const char* name, PRAccessHow how) { 3476 PRIntn rv; 3477 3478 if (pt_TestAbort()) { 3479 return PR_FAILURE; 3480 } 3481 3482 switch (how) { 3483 case PR_ACCESS_READ_OK: 3484 rv = access(name, R_OK); 3485 break; 3486 case PR_ACCESS_WRITE_OK: 3487 rv = access(name, W_OK); 3488 break; 3489 case PR_ACCESS_EXISTS: 3490 default: 3491 rv = access(name, F_OK); 3492 } 3493 if (0 == rv) { 3494 return PR_SUCCESS; 3495 } 3496 pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno); 3497 return PR_FAILURE; 3498 3499 } /* PR_Access */ 3500 3501 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char* fn, PRFileInfo* info) { 3502 PRInt32 rv = _PR_MD_GETFILEINFO(fn, info); 3503 return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 3504 } /* PR_GetFileInfo */ 3505 3506 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char* fn, PRFileInfo64* info) { 3507 PRInt32 rv; 3508 3509 if (!_pr_initialized) { 3510 _PR_ImplicitInitialization(); 3511 } 3512 rv = _PR_MD_GETFILEINFO64(fn, info); 3513 return (0 == rv) ? PR_SUCCESS : PR_FAILURE; 3514 } /* PR_GetFileInfo64 */ 3515 3516 PR_IMPLEMENT(PRStatus) PR_Rename(const char* from, const char* to) { 3517 PRIntn rv = -1; 3518 3519 if (pt_TestAbort()) { 3520 return PR_FAILURE; 3521 } 3522 3523 /* 3524 ** We have to acquire a lock here to stiffle anybody trying to create 3525 ** a new file at the same time. And we have to hold that lock while we 3526 ** test to see if the file exists and do the rename. The other place 3527 ** where the lock is held is in PR_Open() when possibly creating a 3528 ** new file. 3529 */ 3530 3531 PR_Lock(_pr_rename_lock); 3532 rv = access(to, F_OK); 3533 if (0 == rv) { 3534 PR_SetError(PR_FILE_EXISTS_ERROR, 0); 3535 rv = -1; 3536 } else { 3537 rv = rename(from, to); 3538 if (rv == -1) { 3539 pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno); 3540 } 3541 } 3542 PR_Unlock(_pr_rename_lock); 3543 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 3544 } /* PR_Rename */ 3545 3546 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir* dir) { 3547 if (pt_TestAbort()) { 3548 return PR_FAILURE; 3549 } 3550 3551 if (NULL != dir->md.d) { 3552 if (closedir(dir->md.d) == -1) { 3553 _PR_MD_MAP_CLOSEDIR_ERROR(errno); 3554 return PR_FAILURE; 3555 } 3556 dir->md.d = NULL; 3557 PR_DELETE(dir); 3558 } 3559 return PR_SUCCESS; 3560 } /* PR_CloseDir */ 3561 3562 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char* name, PRIntn mode) { 3563 PRInt32 rv = -1; 3564 3565 if (pt_TestAbort()) { 3566 return PR_FAILURE; 3567 } 3568 3569 /* 3570 ** This lock is used to enforce rename semantics as described 3571 ** in PR_Rename. 3572 */ 3573 if (NULL != _pr_rename_lock) { 3574 PR_Lock(_pr_rename_lock); 3575 } 3576 rv = mkdir(name, mode); 3577 if (-1 == rv) { 3578 pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno); 3579 } 3580 if (NULL != _pr_rename_lock) { 3581 PR_Unlock(_pr_rename_lock); 3582 } 3583 3584 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; 3585 } /* PR_Makedir */ 3586 3587 PR_IMPLEMENT(PRStatus) PR_MkDir(const char* name, PRIntn mode) { 3588 return PR_MakeDir(name, mode); 3589 } /* PR_Mkdir */ 3590 3591 PR_IMPLEMENT(PRStatus) PR_RmDir(const char* name) { 3592 PRInt32 rv; 3593 3594 if (pt_TestAbort()) { 3595 return PR_FAILURE; 3596 } 3597 3598 rv = rmdir(name); 3599 if (0 == rv) { 3600 return PR_SUCCESS; 3601 } 3602 pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno); 3603 return PR_FAILURE; 3604 } /* PR_Rmdir */ 3605 3606 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char* name) { 3607 DIR* osdir; 3608 PRDir* dir = NULL; 3609 3610 if (pt_TestAbort()) { 3611 return dir; 3612 } 3613 3614 osdir = opendir(name); 3615 if (osdir == NULL) { 3616 pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno); 3617 } else { 3618 dir = PR_NEWZAP(PRDir); 3619 if (dir) { 3620 dir->md.d = osdir; 3621 } else { 3622 (void)closedir(osdir); 3623 } 3624 } 3625 return dir; 3626 } /* PR_OpenDir */ 3627 3628 static PRInt32 _pr_poll_with_poll(PRPollDesc* pds, PRIntn npds, 3629 PRIntervalTime timeout) { 3630 PRInt32 ready = 0; 3631 /* 3632 * For restarting poll() if it is interrupted by a signal. 3633 * We use these variables to figure out how much time has 3634 * elapsed and how much of the timeout still remains. 3635 */ 3636 PRIntervalTime start = 0, elapsed, remaining; 3637 3638 if (pt_TestAbort()) { 3639 return -1; 3640 } 3641 3642 if (0 == npds) { 3643 PR_Sleep(timeout); 3644 } else { 3645 # define STACK_POLL_DESC_COUNT 64 3646 struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT]; 3647 struct pollfd* syspoll; 3648 PRIntn index, msecs; 3649 3650 if (npds <= STACK_POLL_DESC_COUNT) { 3651 syspoll = stack_syspoll; 3652 } else { 3653 PRThread* me = PR_GetCurrentThread(); 3654 if (npds > me->syspoll_count) { 3655 PR_Free(me->syspoll_list); 3656 me->syspoll_list = 3657 (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); 3658 if (NULL == me->syspoll_list) { 3659 me->syspoll_count = 0; 3660 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 3661 return -1; 3662 } 3663 me->syspoll_count = npds; 3664 } 3665 syspoll = me->syspoll_list; 3666 } 3667 3668 for (index = 0; index < npds; ++index) { 3669 PRInt16 in_flags_read = 0, in_flags_write = 0; 3670 PRInt16 out_flags_read = 0, out_flags_write = 0; 3671 3672 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { 3673 if (pds[index].in_flags & PR_POLL_READ) { 3674 in_flags_read = (pds[index].fd->methods->poll)( 3675 pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE, 3676 &out_flags_read); 3677 } 3678 if (pds[index].in_flags & PR_POLL_WRITE) { 3679 in_flags_write = (pds[index].fd->methods->poll)( 3680 pds[index].fd, pds[index].in_flags & ~PR_POLL_READ, 3681 &out_flags_write); 3682 } 3683 if ((0 != (in_flags_read & out_flags_read)) || 3684 (0 != (in_flags_write & out_flags_write))) { 3685 /* this one is ready right now */ 3686 if (0 == ready) { 3687 /* 3688 * We will return without calling the system 3689 * poll function. So zero the out_flags 3690 * fields of all the poll descriptors before 3691 * this one. 3692 */ 3693 int i; 3694 for (i = 0; i < index; i++) { 3695 pds[i].out_flags = 0; 3696 } 3697 } 3698 ready += 1; 3699 pds[index].out_flags = out_flags_read | out_flags_write; 3700 } else { 3701 /* now locate the NSPR layer at the bottom of the stack */ 3702 PRFileDesc* bottom = 3703 PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); 3704 /* ignore a socket without PR_NSPR_IO_LAYER available */ 3705 3706 pds[index].out_flags = 0; /* pre-condition */ 3707 if ((NULL != bottom) && 3708 (_PR_FILEDESC_OPEN == bottom->secret->state)) { 3709 if (0 == ready) { 3710 syspoll[index].fd = bottom->secret->md.osfd; 3711 syspoll[index].events = 0; 3712 if (in_flags_read & PR_POLL_READ) { 3713 pds[index].out_flags |= _PR_POLL_READ_SYS_READ; 3714 syspoll[index].events |= POLLIN; 3715 } 3716 if (in_flags_read & PR_POLL_WRITE) { 3717 pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE; 3718 syspoll[index].events |= POLLOUT; 3719 } 3720 if (in_flags_write & PR_POLL_READ) { 3721 pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ; 3722 syspoll[index].events |= POLLIN; 3723 } 3724 if (in_flags_write & PR_POLL_WRITE) { 3725 pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE; 3726 syspoll[index].events |= POLLOUT; 3727 } 3728 if (pds[index].in_flags & PR_POLL_EXCEPT) { 3729 syspoll[index].events |= POLLPRI; 3730 } 3731 } 3732 } else { 3733 if (0 == ready) { 3734 int i; 3735 for (i = 0; i < index; i++) { 3736 pds[i].out_flags = 0; 3737 } 3738 } 3739 ready += 1; /* this will cause an abrupt return */ 3740 pds[index].out_flags = PR_POLL_NVAL; /* bogii */ 3741 } 3742 } 3743 } else { 3744 /* make poll() ignore this entry */ 3745 syspoll[index].fd = -1; 3746 syspoll[index].events = 0; 3747 pds[index].out_flags = 0; 3748 } 3749 } 3750 if (0 == ready) { 3751 switch (timeout) { 3752 case PR_INTERVAL_NO_WAIT: 3753 msecs = 0; 3754 break; 3755 case PR_INTERVAL_NO_TIMEOUT: 3756 msecs = -1; 3757 break; 3758 default: 3759 msecs = PR_IntervalToMilliseconds(timeout); 3760 start = PR_IntervalNow(); 3761 } 3762 3763 retry: 3764 ready = poll(syspoll, npds, msecs); 3765 if (-1 == ready) { 3766 PRIntn oserror = errno; 3767 3768 if (EINTR == oserror) { 3769 if (timeout == PR_INTERVAL_NO_TIMEOUT) { 3770 goto retry; 3771 } else if (timeout == PR_INTERVAL_NO_WAIT) { 3772 ready = 0; /* don't retry, just time out */ 3773 } else { 3774 elapsed = (PRIntervalTime)(PR_IntervalNow() - start); 3775 if (elapsed > timeout) { 3776 ready = 0; /* timed out */ 3777 } else { 3778 remaining = timeout - elapsed; 3779 msecs = PR_IntervalToMilliseconds(remaining); 3780 goto retry; 3781 } 3782 } 3783 } else { 3784 _PR_MD_MAP_POLL_ERROR(oserror); 3785 } 3786 } else if (ready > 0) { 3787 for (index = 0; index < npds; ++index) { 3788 PRInt16 out_flags = 0; 3789 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { 3790 if (0 != syspoll[index].revents) { 3791 if (syspoll[index].revents & POLLIN) { 3792 if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) { 3793 out_flags |= PR_POLL_READ; 3794 } 3795 if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) { 3796 out_flags |= PR_POLL_WRITE; 3797 } 3798 } 3799 if (syspoll[index].revents & POLLOUT) { 3800 if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) { 3801 out_flags |= PR_POLL_READ; 3802 } 3803 if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) { 3804 out_flags |= PR_POLL_WRITE; 3805 } 3806 } 3807 if (syspoll[index].revents & POLLPRI) { 3808 out_flags |= PR_POLL_EXCEPT; 3809 } 3810 if (syspoll[index].revents & POLLERR) { 3811 out_flags |= PR_POLL_ERR; 3812 } 3813 if (syspoll[index].revents & POLLNVAL) { 3814 out_flags |= PR_POLL_NVAL; 3815 } 3816 if (syspoll[index].revents & POLLHUP) { 3817 out_flags |= PR_POLL_HUP; 3818 } 3819 } 3820 } 3821 pds[index].out_flags = out_flags; 3822 } 3823 } 3824 } 3825 } 3826 return ready; 3827 3828 } /* _pr_poll_with_poll */ 3829 3830 3831 PR_IMPLEMENT(PRInt32) 3832 PR_Poll(PRPollDesc* pds, PRIntn npds, PRIntervalTime timeout) { 3833 return (_pr_poll_with_poll(pds, npds, timeout)); 3834 } 3835 3836 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir* dir, PRDirFlags flags) { 3837 struct dirent* dp; 3838 3839 if (pt_TestAbort()) { 3840 return NULL; 3841 } 3842 3843 for (;;) { 3844 errno = 0; 3845 dp = readdir(dir->md.d); 3846 if (NULL == dp) { 3847 pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno); 3848 return NULL; 3849 } 3850 if ((flags & PR_SKIP_DOT) && ('.' == dp->d_name[0]) && 3851 (0 == dp->d_name[1])) { 3852 continue; 3853 } 3854 if ((flags & PR_SKIP_DOT_DOT) && ('.' == dp->d_name[0]) && 3855 ('.' == dp->d_name[1]) && (0 == dp->d_name[2])) { 3856 continue; 3857 } 3858 if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0])) { 3859 continue; 3860 } 3861 break; 3862 } 3863 dir->d.name = dp->d_name; 3864 return &dir->d; 3865 } /* PR_ReadDir */ 3866 3867 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) { 3868 PRIntn domain = PF_INET; 3869 3870 return PR_Socket(domain, SOCK_DGRAM, 0); 3871 } /* PR_NewUDPSocket */ 3872 3873 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) { 3874 PRIntn domain = PF_INET; 3875 3876 return PR_Socket(domain, SOCK_STREAM, 0); 3877 } /* PR_NewTCPSocket */ 3878 3879 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) { 3880 return PR_Socket(af, SOCK_DGRAM, 0); 3881 } /* PR_NewUDPSocket */ 3882 3883 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) { 3884 return PR_Socket(af, SOCK_STREAM, 0); 3885 } /* PR_NewTCPSocket */ 3886 3887 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc* fds[2]) { 3888 PRInt32 osfd[2]; 3889 3890 if (pt_TestAbort()) { 3891 return PR_FAILURE; 3892 } 3893 3894 if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) { 3895 pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno); 3896 return PR_FAILURE; 3897 } 3898 3899 fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); 3900 if (fds[0] == NULL) { 3901 close(osfd[0]); 3902 close(osfd[1]); 3903 return PR_FAILURE; 3904 } 3905 fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); 3906 if (fds[1] == NULL) { 3907 PR_Close(fds[0]); 3908 close(osfd[1]); 3909 return PR_FAILURE; 3910 } 3911 return PR_SUCCESS; 3912 } /* PR_NewTCPSocketPair */ 3913 3914 PR_IMPLEMENT(PRStatus) 3915 PR_CreatePipe(PRFileDesc** readPipe, PRFileDesc** writePipe) { 3916 int pipefd[2]; 3917 3918 if (pt_TestAbort()) { 3919 return PR_FAILURE; 3920 } 3921 3922 if (pipe(pipefd) == -1) { 3923 /* XXX map pipe error */ 3924 PR_SetError(PR_UNKNOWN_ERROR, errno); 3925 return PR_FAILURE; 3926 } 3927 *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE); 3928 if (NULL == *readPipe) { 3929 close(pipefd[0]); 3930 close(pipefd[1]); 3931 return PR_FAILURE; 3932 } 3933 *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE); 3934 if (NULL == *writePipe) { 3935 PR_Close(*readPipe); 3936 close(pipefd[1]); 3937 return PR_FAILURE; 3938 } 3939 return PR_SUCCESS; 3940 } 3941 3942 /* 3943 ** Set the inheritance attribute of a file descriptor. 3944 */ 3945 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(PRFileDesc* fd, PRBool inheritable) { 3946 /* 3947 * Only a non-layered, NSPR file descriptor can be inherited 3948 * by a child process. 3949 */ 3950 if (fd->identity != PR_NSPR_IO_LAYER) { 3951 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 3952 return PR_FAILURE; 3953 } 3954 if (fd->secret->inheritable != inheritable) { 3955 if (fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC) == 3956 -1) { 3957 _PR_MD_MAP_DEFAULT_ERROR(errno); 3958 return PR_FAILURE; 3959 } 3960 fd->secret->inheritable = (_PRTriStateBool)inheritable; 3961 } 3962 return PR_SUCCESS; 3963 } 3964 3965 /*****************************************************************************/ 3966 /***************************** I/O friends methods ***************************/ 3967 /*****************************************************************************/ 3968 3969 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) { 3970 PRFileDesc* fd; 3971 3972 if (!_pr_initialized) { 3973 _PR_ImplicitInitialization(); 3974 } 3975 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE); 3976 if (NULL == fd) { 3977 close(osfd); 3978 } 3979 return fd; 3980 } /* PR_ImportFile */ 3981 3982 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) { 3983 PRFileDesc* fd; 3984 3985 if (!_pr_initialized) { 3986 _PR_ImplicitInitialization(); 3987 } 3988 fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE); 3989 if (NULL == fd) { 3990 close(osfd); 3991 } 3992 return fd; 3993 } /* PR_ImportPipe */ 3994 3995 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd) { 3996 PRFileDesc* fd; 3997 3998 if (!_pr_initialized) { 3999 _PR_ImplicitInitialization(); 4000 } 4001 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE); 4002 if (NULL == fd) { 4003 close(osfd); 4004 } 4005 # ifdef _PR_NEED_SECRET_AF 4006 if (NULL != fd) { 4007 fd->secret->af = PF_INET; 4008 } 4009 # endif 4010 return fd; 4011 } /* PR_ImportTCPSocket */ 4012 4013 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) { 4014 PRFileDesc* fd; 4015 4016 if (!_pr_initialized) { 4017 _PR_ImplicitInitialization(); 4018 } 4019 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE); 4020 if (NULL == fd) { 4021 close(osfd); 4022 } 4023 return fd; 4024 } /* PR_ImportUDPSocket */ 4025 4026 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd) { 4027 PRFileDesc* fd; 4028 4029 if (!_pr_initialized) { 4030 _PR_ImplicitInitialization(); 4031 } 4032 4033 fd = _PR_Getfd(); 4034 4035 if (fd == NULL) { 4036 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 4037 } else { 4038 fd->secret->md.osfd = osfd; 4039 fd->secret->inheritable = _PR_TRI_FALSE; 4040 fd->secret->state = _PR_FILEDESC_OPEN; 4041 fd->methods = PR_GetSocketPollFdMethods(); 4042 } 4043 4044 return fd; 4045 } /* PR_CreateSocketPollFD */ 4046 4047 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) { 4048 if (NULL == fd) { 4049 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); 4050 return PR_FAILURE; 4051 } 4052 fd->secret->state = _PR_FILEDESC_CLOSED; 4053 _PR_Putfd(fd); 4054 return PR_SUCCESS; 4055 } /* PR_DestroySocketPollFd */ 4056 4057 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc* bottom) { 4058 PRInt32 osfd = -1; 4059 bottom = 4060 (NULL == bottom) ? NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER); 4061 if (NULL == bottom) { 4062 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 4063 } else { 4064 osfd = bottom->secret->md.osfd; 4065 } 4066 return osfd; 4067 } /* PR_FileDesc2NativeHandle */ 4068 4069 PR_IMPLEMENT(void) 4070 PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PRInt32 handle) { 4071 if (fd) { 4072 fd->secret->md.osfd = handle; 4073 } 4074 } /* PR_ChangeFileDescNativeHandle*/ 4075 4076 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc* fd) { 4077 PRStatus status = PR_SUCCESS; 4078 4079 if (pt_TestAbort()) { 4080 return PR_FAILURE; 4081 } 4082 4083 PR_Lock(_pr_flock_lock); 4084 while (-1 == fd->secret->lockCount) { 4085 PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT); 4086 } 4087 if (0 == fd->secret->lockCount) { 4088 fd->secret->lockCount = -1; 4089 PR_Unlock(_pr_flock_lock); 4090 status = _PR_MD_LOCKFILE(fd->secret->md.osfd); 4091 PR_Lock(_pr_flock_lock); 4092 fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0; 4093 PR_NotifyAllCondVar(_pr_flock_cv); 4094 } else { 4095 fd->secret->lockCount += 1; 4096 } 4097 PR_Unlock(_pr_flock_lock); 4098 4099 return status; 4100 } /* PR_LockFile */ 4101 4102 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc* fd) { 4103 PRStatus status = PR_SUCCESS; 4104 4105 if (pt_TestAbort()) { 4106 return PR_FAILURE; 4107 } 4108 4109 PR_Lock(_pr_flock_lock); 4110 if (0 == fd->secret->lockCount) { 4111 status = _PR_MD_TLOCKFILE(fd->secret->md.osfd); 4112 if (PR_SUCCESS == status) { 4113 fd->secret->lockCount = 1; 4114 } 4115 } else { 4116 fd->secret->lockCount += 1; 4117 } 4118 PR_Unlock(_pr_flock_lock); 4119 4120 return status; 4121 } /* PR_TLockFile */ 4122 4123 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc* fd) { 4124 PRStatus status = PR_SUCCESS; 4125 4126 if (pt_TestAbort()) { 4127 return PR_FAILURE; 4128 } 4129 4130 PR_Lock(_pr_flock_lock); 4131 if (fd->secret->lockCount == 1) { 4132 status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd); 4133 if (PR_SUCCESS == status) { 4134 fd->secret->lockCount = 0; 4135 } 4136 } else { 4137 fd->secret->lockCount -= 1; 4138 } 4139 PR_Unlock(_pr_flock_lock); 4140 4141 return status; 4142 } 4143 4144 /* 4145 * The next two entry points should not be in the API, but they are 4146 * defined here for historical (or hysterical) reasons. 4147 */ 4148 4149 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void) { 4150 # if defined(AIX) 4151 return sysconf(_SC_OPEN_MAX); 4152 # else 4153 struct rlimit rlim; 4154 4155 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 4156 return -1; 4157 } 4158 4159 return rlim.rlim_max; 4160 # endif 4161 } 4162 4163 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size) { 4164 # if defined(AIX) 4165 return -1; 4166 # else 4167 struct rlimit rlim; 4168 PRInt32 tableMax = PR_GetSysfdTableMax(); 4169 4170 if (tableMax < 0) { 4171 return -1; 4172 } 4173 rlim.rlim_max = tableMax; 4174 4175 /* Grow as much as we can; even if too big */ 4176 if (rlim.rlim_max < table_size) { 4177 rlim.rlim_cur = rlim.rlim_max; 4178 } else { 4179 rlim.rlim_cur = table_size; 4180 } 4181 4182 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 4183 return -1; 4184 } 4185 4186 return rlim.rlim_cur; 4187 # endif 4188 } 4189 4190 /* 4191 * PR_Stat is supported for backward compatibility; some existing Java 4192 * code uses it. New code should use PR_GetFileInfo. 4193 */ 4194 4195 # ifndef NO_NSPR_10_SUPPORT 4196 PR_IMPLEMENT(PRInt32) PR_Stat(const char* name, struct stat* buf) { 4197 static PRBool unwarned = PR_TRUE; 4198 if (unwarned) { 4199 unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo"); 4200 } 4201 4202 if (pt_TestAbort()) { 4203 return -1; 4204 } 4205 4206 if (-1 == stat(name, buf)) { 4207 pt_MapError(_PR_MD_MAP_STAT_ERROR, errno); 4208 return -1; 4209 } else { 4210 return 0; 4211 } 4212 } 4213 # endif /* ! NO_NSPR_10_SUPPORT */ 4214 4215 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set* set) { 4216 static PRBool unwarned = PR_TRUE; 4217 if (unwarned) { 4218 unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll"); 4219 } 4220 memset(set, 0, sizeof(PR_fd_set)); 4221 } 4222 4223 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc* fh, PR_fd_set* set) { 4224 static PRBool unwarned = PR_TRUE; 4225 if (unwarned) { 4226 unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll"); 4227 } 4228 PR_ASSERT(set->hsize < PR_MAX_SELECT_DESC); 4229 4230 set->harray[set->hsize++] = fh; 4231 } 4232 4233 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc* fh, PR_fd_set* set) { 4234 PRUint32 index, index2; 4235 static PRBool unwarned = PR_TRUE; 4236 if (unwarned) { 4237 unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll"); 4238 } 4239 4240 for (index = 0; index < set->hsize; index++) 4241 if (set->harray[index] == fh) { 4242 for (index2 = index; index2 < (set->hsize - 1); index2++) { 4243 set->harray[index2] = set->harray[index2 + 1]; 4244 } 4245 set->hsize--; 4246 break; 4247 } 4248 } 4249 4250 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) { 4251 PRUint32 index; 4252 static PRBool unwarned = PR_TRUE; 4253 if (unwarned) { 4254 unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll"); 4255 } 4256 for (index = 0; index < set->hsize; index++) 4257 if (set->harray[index] == fh) { 4258 return 1; 4259 } 4260 return 0; 4261 } 4262 4263 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set* set) { 4264 static PRBool unwarned = PR_TRUE; 4265 if (unwarned) { 4266 unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll"); 4267 } 4268 PR_ASSERT(set->nsize < PR_MAX_SELECT_DESC); 4269 4270 set->narray[set->nsize++] = fd; 4271 } 4272 4273 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set* set) { 4274 PRUint32 index, index2; 4275 static PRBool unwarned = PR_TRUE; 4276 if (unwarned) { 4277 unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll"); 4278 } 4279 4280 for (index = 0; index < set->nsize; index++) 4281 if (set->narray[index] == fd) { 4282 for (index2 = index; index2 < (set->nsize - 1); index2++) { 4283 set->narray[index2] = set->narray[index2 + 1]; 4284 } 4285 set->nsize--; 4286 break; 4287 } 4288 } 4289 4290 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set* set) { 4291 PRUint32 index; 4292 static PRBool unwarned = PR_TRUE; 4293 if (unwarned) { 4294 unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll"); 4295 } 4296 for (index = 0; index < set->nsize; index++) 4297 if (set->narray[index] == fd) { 4298 return 1; 4299 } 4300 return 0; 4301 } 4302 4303 # include <sys/types.h> 4304 # include <sys/time.h> 4305 # if !defined(LINUX) && !defined(__GNU__) && \ 4306 !defined(__GLIBC__) 4307 # include <sys/select.h> 4308 # endif 4309 4310 static PRInt32 _PR_getset(PR_fd_set* pr_set, fd_set* set) { 4311 PRUint32 index; 4312 PRInt32 max = 0; 4313 4314 if (!pr_set) { 4315 return 0; 4316 } 4317 4318 FD_ZERO(set); 4319 4320 /* First set the pr file handle osfds */ 4321 for (index = 0; index < pr_set->hsize; index++) { 4322 FD_SET(pr_set->harray[index]->secret->md.osfd, set); 4323 if (pr_set->harray[index]->secret->md.osfd > max) { 4324 max = pr_set->harray[index]->secret->md.osfd; 4325 } 4326 } 4327 /* Second set the native osfds */ 4328 for (index = 0; index < pr_set->nsize; index++) { 4329 FD_SET(pr_set->narray[index], set); 4330 if (pr_set->narray[index] > max) { 4331 max = pr_set->narray[index]; 4332 } 4333 } 4334 return max; 4335 } 4336 4337 static void _PR_setset(PR_fd_set* pr_set, fd_set* set) { 4338 PRUint32 index, last_used; 4339 4340 if (!pr_set) { 4341 return; 4342 } 4343 4344 for (last_used = 0, index = 0; index < pr_set->hsize; index++) { 4345 if (FD_ISSET(pr_set->harray[index]->secret->md.osfd, set)) { 4346 pr_set->harray[last_used++] = pr_set->harray[index]; 4347 } 4348 } 4349 pr_set->hsize = last_used; 4350 4351 for (last_used = 0, index = 0; index < pr_set->nsize; index++) { 4352 if (FD_ISSET(pr_set->narray[index], set)) { 4353 pr_set->narray[last_used++] = pr_set->narray[index]; 4354 } 4355 } 4356 pr_set->nsize = last_used; 4357 } 4358 4359 PR_IMPLEMENT(PRInt32) 4360 PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex, 4361 PRIntervalTime timeout) { 4362 fd_set rd, wr, ex; 4363 struct timeval tv, *tvp; 4364 PRInt32 max, max_fd; 4365 PRInt32 rv; 4366 /* 4367 * For restarting select() if it is interrupted by a Unix signal. 4368 * We use these variables to figure out how much time has elapsed 4369 * and how much of the timeout still remains. 4370 */ 4371 PRIntervalTime start = 0, elapsed, remaining; 4372 4373 static PRBool unwarned = PR_TRUE; 4374 if (unwarned) { 4375 unwarned = _PR_Obsolete("PR_Select", "PR_Poll"); 4376 } 4377 4378 FD_ZERO(&rd); 4379 FD_ZERO(&wr); 4380 FD_ZERO(&ex); 4381 4382 max_fd = _PR_getset(pr_rd, &rd); 4383 max_fd = (max = _PR_getset(pr_wr, &wr)) > max_fd ? max : max_fd; 4384 max_fd = (max = _PR_getset(pr_ex, &ex)) > max_fd ? max : max_fd; 4385 4386 if (timeout == PR_INTERVAL_NO_TIMEOUT) { 4387 tvp = NULL; 4388 } else { 4389 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout); 4390 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( 4391 timeout - PR_SecondsToInterval(tv.tv_sec)); 4392 tvp = &tv; 4393 start = PR_IntervalNow(); 4394 } 4395 4396 retry: 4397 rv = select(max_fd + 1, (_PRSelectFdSetArg_t)&rd, (_PRSelectFdSetArg_t)&wr, 4398 (_PRSelectFdSetArg_t)&ex, tvp); 4399 4400 if (rv == -1 && errno == EINTR) { 4401 if (timeout == PR_INTERVAL_NO_TIMEOUT) { 4402 goto retry; 4403 } else { 4404 elapsed = (PRIntervalTime)(PR_IntervalNow() - start); 4405 if (elapsed > timeout) { 4406 rv = 0; /* timed out */ 4407 } else { 4408 remaining = timeout - elapsed; 4409 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining); 4410 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( 4411 remaining - PR_SecondsToInterval(tv.tv_sec)); 4412 goto retry; 4413 } 4414 } 4415 } 4416 4417 if (rv > 0) { 4418 _PR_setset(pr_rd, &rd); 4419 _PR_setset(pr_wr, &wr); 4420 _PR_setset(pr_ex, &ex); 4421 } else if (rv == -1) { 4422 pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno); 4423 } 4424 return rv; 4425 } 4426 #endif /* defined(_PR_PTHREADS) */ 4427 4428 #ifdef MOZ_UNICODE 4429 /* ================ UTF16 Interfaces ================================ */ 4430 PR_IMPLEMENT(PRFileDesc*) 4431 PR_OpenFileUTF16(const PRUnichar* name, PRIntn flags, PRIntn mode) { 4432 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 4433 return NULL; 4434 } 4435 4436 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir* dir) { 4437 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 4438 return PR_FAILURE; 4439 } 4440 4441 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar* name) { 4442 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 4443 return NULL; 4444 } 4445 4446 PR_IMPLEMENT(PRDirEntryUTF16*) 4447 PR_ReadDirUTF16(PRDirUTF16* dir, PRDirFlags flags) { 4448 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 4449 return NULL; 4450 } 4451 4452 PR_IMPLEMENT(PRStatus) 4453 PR_GetFileInfo64UTF16(const PRUnichar* fn, PRFileInfo64* info) { 4454 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 4455 return PR_FAILURE; 4456 } 4457 /* ================ UTF16 Interfaces ================================ */ 4458 #endif /* MOZ_UNICODE */ 4459 4460 /* ptio.c */