1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_networkio.h" 18#include "apr_support.h" 19 20#if APR_HAS_SENDFILE 21/* This file is needed to allow us access to the apr_file_t internals. */ 22#include "apr_arch_file_io.h" 23#endif /* APR_HAS_SENDFILE */ 24 25/* osreldate.h is only needed on FreeBSD for sendfile detection */ 26#if defined(__FreeBSD__) 27#include <osreldate.h> 28#endif 29 30apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, 31 apr_size_t *len) 32{ 33 apr_ssize_t rv; 34 35 if (sock->options & APR_INCOMPLETE_WRITE) { 36 sock->options &= ~APR_INCOMPLETE_WRITE; 37 goto do_select; 38 } 39 40 do { 41 rv = write(sock->socketdes, buf, (*len)); 42 } while (rv == -1 && errno == EINTR); 43 44 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) 45 && (sock->timeout > 0)) { 46 apr_status_t arv; 47do_select: 48 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 49 if (arv != APR_SUCCESS) { 50 *len = 0; 51 return arv; 52 } 53 else { 54 do { 55 rv = write(sock->socketdes, buf, (*len)); 56 } while (rv == -1 && errno == EINTR); 57 } 58 } 59 if (rv == -1) { 60 *len = 0; 61 return errno; 62 } 63 if ((sock->timeout > 0) && (rv < *len)) { 64 sock->options |= APR_INCOMPLETE_WRITE; 65 } 66 (*len) = rv; 67 return APR_SUCCESS; 68} 69 70apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) 71{ 72 apr_ssize_t rv; 73 apr_status_t arv; 74 75 if (sock->options & APR_INCOMPLETE_READ) { 76 sock->options &= ~APR_INCOMPLETE_READ; 77 goto do_select; 78 } 79 80 do { 81 rv = read(sock->socketdes, buf, (*len)); 82 } while (rv == -1 && errno == EINTR); 83 84 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 85 && (sock->timeout > 0)) { 86do_select: 87 arv = apr_wait_for_io_or_timeout(NULL, sock, 1); 88 if (arv != APR_SUCCESS) { 89 *len = 0; 90 return arv; 91 } 92 else { 93 do { 94 rv = read(sock->socketdes, buf, (*len)); 95 } while (rv == -1 && errno == EINTR); 96 } 97 } 98 if (rv == -1) { 99 (*len) = 0; 100 return errno; 101 } 102 if ((sock->timeout > 0) && (rv < *len)) { 103 sock->options |= APR_INCOMPLETE_READ; 104 } 105 (*len) = rv; 106 if (rv == 0) { 107 return APR_EOF; 108 } 109 return APR_SUCCESS; 110} 111 112apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, 113 apr_int32_t flags, const char *buf, 114 apr_size_t *len) 115{ 116 apr_ssize_t rv; 117 118 do { 119 rv = sendto(sock->socketdes, buf, (*len), flags, 120 (const struct sockaddr*)&where->sa, 121 where->salen); 122 } while (rv == -1 && errno == EINTR); 123 124 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 125 && (sock->timeout > 0)) { 126 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 127 if (arv != APR_SUCCESS) { 128 *len = 0; 129 return arv; 130 } else { 131 do { 132 rv = sendto(sock->socketdes, buf, (*len), flags, 133 (const struct sockaddr*)&where->sa, 134 where->salen); 135 } while (rv == -1 && errno == EINTR); 136 } 137 } 138 if (rv == -1) { 139 *len = 0; 140 return errno; 141 } 142 *len = rv; 143 return APR_SUCCESS; 144} 145 146apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, 147 apr_int32_t flags, char *buf, 148 apr_size_t *len) 149{ 150 apr_ssize_t rv; 151 152 from->salen = sizeof(from->sa); 153 154 do { 155 rv = recvfrom(sock->socketdes, buf, (*len), flags, 156 (struct sockaddr*)&from->sa, &from->salen); 157 } while (rv == -1 && errno == EINTR); 158 159 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 160 && (sock->timeout > 0)) { 161 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1); 162 if (arv != APR_SUCCESS) { 163 *len = 0; 164 return arv; 165 } else { 166 do { 167 rv = recvfrom(sock->socketdes, buf, (*len), flags, 168 (struct sockaddr*)&from->sa, &from->salen); 169 } while (rv == -1 && errno == EINTR); 170 } 171 } 172 if (rv == -1) { 173 (*len) = 0; 174 return errno; 175 } 176 177 /* 178 * Check if we have a valid address. recvfrom() with MSG_PEEK may return 179 * success without filling in the address. 180 */ 181 if (from->salen > APR_OFFSETOF(struct sockaddr_in, sin_port)) { 182 apr_sockaddr_vars_set(from, from->sa.sin.sin_family, 183 ntohs(from->sa.sin.sin_port)); 184 } 185 186 (*len) = rv; 187 if (rv == 0 && sock->type == SOCK_STREAM) { 188 return APR_EOF; 189 } 190 191 return APR_SUCCESS; 192} 193 194apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec, 195 apr_int32_t nvec, apr_size_t *len) 196{ 197#ifdef HAVE_WRITEV 198 apr_ssize_t rv; 199 apr_size_t requested_len = 0; 200 apr_int32_t i; 201 202 for (i = 0; i < nvec; i++) { 203 requested_len += vec[i].iov_len; 204 } 205 206 if (sock->options & APR_INCOMPLETE_WRITE) { 207 sock->options &= ~APR_INCOMPLETE_WRITE; 208 goto do_select; 209 } 210 211 do { 212 rv = writev(sock->socketdes, vec, nvec); 213 } while (rv == -1 && errno == EINTR); 214 215 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 216 && (sock->timeout > 0)) { 217 apr_status_t arv; 218do_select: 219 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 220 if (arv != APR_SUCCESS) { 221 *len = 0; 222 return arv; 223 } 224 else { 225 do { 226 rv = writev(sock->socketdes, vec, nvec); 227 } while (rv == -1 && errno == EINTR); 228 } 229 } 230 if (rv == -1) { 231 *len = 0; 232 return errno; 233 } 234 if ((sock->timeout > 0) && (rv < requested_len)) { 235 sock->options |= APR_INCOMPLETE_WRITE; 236 } 237 (*len) = rv; 238 return APR_SUCCESS; 239#else 240 *len = vec[0].iov_len; 241 return apr_socket_send(sock, vec[0].iov_base, len); 242#endif 243} 244 245#if APR_HAS_SENDFILE 246 247/* TODO: Verify that all platforms handle the fd the same way, 248 * i.e. that they don't move the file pointer. 249 */ 250/* TODO: what should flags be? int_32? */ 251 252/* Define a structure to pass in when we have a NULL header value */ 253static apr_hdtr_t no_hdtr; 254 255#if (defined(__linux__) || defined(__GNU__)) && defined(HAVE_WRITEV) 256 257apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, 258 apr_hdtr_t *hdtr, apr_off_t *offset, 259 apr_size_t *len, apr_int32_t flags) 260{ 261 int rv, nbytes = 0, total_hdrbytes, i; 262 apr_status_t arv; 263 264#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) 265 apr_off_t off = *offset; 266#define sendfile sendfile64 267 268#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 269 /* 64-bit apr_off_t but no sendfile64(): fail if trying to send 270 * past the 2Gb limit. */ 271 off_t off; 272 273 if ((apr_int64_t)*offset + *len > INT_MAX) { 274 return EINVAL; 275 } 276 277 off = *offset; 278 279#else 280 off_t off = *offset; 281 282 /* Multiple reports have shown sendfile failing with EINVAL if 283 * passed a >=2Gb count value on some 64-bit kernels. It won't 284 * noticably hurt performance to limit each call to <2Gb at a 285 * time, so avoid that issue here: */ 286 if (sizeof(off_t) == 8 && *len > INT_MAX) { 287 *len = INT_MAX; 288 } 289#endif 290 291 if (!hdtr) { 292 hdtr = &no_hdtr; 293 } 294 295 if (hdtr->numheaders > 0) { 296 apr_size_t hdrbytes; 297 298 /* cork before writing headers */ 299 rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1); 300 if (rv != APR_SUCCESS) { 301 return rv; 302 } 303 304 /* Now write the headers */ 305 arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, 306 &hdrbytes); 307 if (arv != APR_SUCCESS) { 308 *len = 0; 309 return errno; 310 } 311 nbytes += hdrbytes; 312 313 /* If this was a partial write and we aren't doing timeouts, 314 * return now with the partial byte count; this is a non-blocking 315 * socket. 316 */ 317 total_hdrbytes = 0; 318 for (i = 0; i < hdtr->numheaders; i++) { 319 total_hdrbytes += hdtr->headers[i].iov_len; 320 } 321 if (hdrbytes < total_hdrbytes) { 322 *len = hdrbytes; 323 return apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); 324 } 325 } 326 327 if (sock->options & APR_INCOMPLETE_WRITE) { 328 sock->options &= ~APR_INCOMPLETE_WRITE; 329 goto do_select; 330 } 331 332 do { 333 rv = sendfile(sock->socketdes, /* socket */ 334 file->filedes, /* open file descriptor of the file to be sent */ 335 &off, /* where in the file to start */ 336 *len); /* number of bytes to send */ 337 } while (rv == -1 && errno == EINTR); 338 339 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 340 && (sock->timeout > 0)) { 341do_select: 342 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 343 if (arv != APR_SUCCESS) { 344 *len = 0; 345 return arv; 346 } 347 else { 348 do { 349 rv = sendfile(sock->socketdes, /* socket */ 350 file->filedes, /* open file descriptor of the file to be sent */ 351 &off, /* where in the file to start */ 352 *len); /* number of bytes to send */ 353 } while (rv == -1 && errno == EINTR); 354 } 355 } 356 357 if (rv == -1) { 358 *len = nbytes; 359 rv = errno; 360 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); 361 return rv; 362 } 363 364 nbytes += rv; 365 366 if (rv < *len) { 367 *len = nbytes; 368 arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); 369 if (rv > 0) { 370 371 /* If this was a partial write, return now with the 372 * partial byte count; this is a non-blocking socket. 373 */ 374 375 if (sock->timeout > 0) { 376 sock->options |= APR_INCOMPLETE_WRITE; 377 } 378 return arv; 379 } 380 else { 381 /* If the file got smaller mid-request, eventually the offset 382 * becomes equal to the new file size and the kernel returns 0. 383 * Make this an error so the caller knows to log something and 384 * exit. 385 */ 386 return APR_EOF; 387 } 388 } 389 390 /* Now write the footers */ 391 if (hdtr->numtrailers > 0) { 392 apr_size_t trbytes; 393 arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, 394 &trbytes); 395 nbytes += trbytes; 396 if (arv != APR_SUCCESS) { 397 *len = nbytes; 398 rv = errno; 399 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); 400 return rv; 401 } 402 } 403 404 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); 405 406 (*len) = nbytes; 407 return rv < 0 ? errno : APR_SUCCESS; 408} 409 410#elif defined(DARWIN) 411 412/* OS/X Release 10.5 or greater */ 413apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, 414 apr_hdtr_t *hdtr, apr_off_t *offset, 415 apr_size_t *len, apr_int32_t flags) 416{ 417 apr_off_t nbytes = 0; 418 apr_off_t bytes_to_send = *len; 419 apr_off_t bytes_sent = 0; 420 apr_status_t arv; 421 int rv = 0; 422 423 /* Ignore flags for now. */ 424 flags = 0; 425 426 if (!hdtr) { 427 hdtr = &no_hdtr; 428 } 429 430 /* OS X can send the headers/footers as part of the system call, 431 * but how it counts bytes isn't documented properly. We use 432 * apr_socket_sendv() instead. 433 */ 434 if (hdtr->numheaders > 0) { 435 apr_size_t hbytes; 436 int i; 437 438 /* Now write the headers */ 439 arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, 440 &hbytes); 441 if (arv != APR_SUCCESS) { 442 *len = 0; 443 return errno; 444 } 445 bytes_sent = hbytes; 446 447 hbytes = 0; 448 for (i = 0; i < hdtr->numheaders; i++) { 449 hbytes += hdtr->headers[i].iov_len; 450 } 451 if (bytes_sent < hbytes) { 452 *len = bytes_sent; 453 return APR_SUCCESS; 454 } 455 } 456 457 do { 458 if (!bytes_to_send) { 459 break; 460 } 461 if (sock->options & APR_INCOMPLETE_WRITE) { 462 apr_status_t arv; 463 sock->options &= ~APR_INCOMPLETE_WRITE; 464 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 465 if (arv != APR_SUCCESS) { 466 *len = 0; 467 return arv; 468 } 469 } 470 471 nbytes = bytes_to_send; 472 rv = sendfile(file->filedes, /* file to be sent */ 473 sock->socketdes, /* socket */ 474 *offset, /* where in the file to start */ 475 &nbytes, /* number of bytes to write/written */ 476 NULL, /* Headers/footers */ 477 flags); /* undefined, set to 0 */ 478 479 if (rv == -1) { 480 if (errno == EAGAIN) { 481 if (sock->timeout > 0) { 482 sock->options |= APR_INCOMPLETE_WRITE; 483 } 484 /* BSD's sendfile can return -1/EAGAIN even if it 485 * sent bytes. Sanitize the result so we get normal EAGAIN 486 * semantics w.r.t. bytes sent. 487 */ 488 if (nbytes) { 489 bytes_sent += nbytes; 490 /* normal exit for a big file & non-blocking io */ 491 (*len) = bytes_sent; 492 return APR_SUCCESS; 493 } 494 } 495 } 496 else { /* rv == 0 (or the kernel is broken) */ 497 bytes_sent += nbytes; 498 if (nbytes == 0) { 499 /* Most likely the file got smaller after the stat. 500 * Return an error so the caller can do the Right Thing. 501 */ 502 (*len) = bytes_sent; 503 return APR_EOF; 504 } 505 } 506 } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 507 508 /* Now write the footers */ 509 if (hdtr->numtrailers > 0) { 510 apr_size_t tbytes; 511 arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, 512 &tbytes); 513 bytes_sent += tbytes; 514 if (arv != APR_SUCCESS) { 515 *len = bytes_sent; 516 rv = errno; 517 return rv; 518 } 519 } 520 521 (*len) = bytes_sent; 522 if (rv == -1) { 523 return errno; 524 } 525 return APR_SUCCESS; 526} 527 528#elif defined(__FreeBSD__) || defined(__DragonFly__) 529 530/* Release 3.1 or greater */ 531apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, 532 apr_hdtr_t * hdtr, apr_off_t * offset, 533 apr_size_t * len, apr_int32_t flags) 534{ 535 off_t nbytes = 0; 536 int rv; 537#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 538 int i; 539#endif 540 struct sf_hdtr headerstruct; 541 apr_size_t bytes_to_send = *len; 542 543 /* Ignore flags for now. */ 544 flags = 0; 545 546 if (!hdtr) { 547 hdtr = &no_hdtr; 548 } 549 550#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 551 else if (hdtr->numheaders) { 552 553 /* On early versions of FreeBSD sendfile, the number of bytes to send 554 * must include the length of the headers. Don't look at the man page 555 * for this :( Instead, look at the logic in 556 * src/sys/kern/uipc_syscalls::sendfile(). 557 * 558 * This was fixed in the middle of 4.6-STABLE 559 */ 560 for (i = 0; i < hdtr->numheaders; i++) { 561 bytes_to_send += hdtr->headers[i].iov_len; 562 } 563 } 564#endif 565 566 headerstruct.headers = hdtr->headers; 567 headerstruct.hdr_cnt = hdtr->numheaders; 568 headerstruct.trailers = hdtr->trailers; 569 headerstruct.trl_cnt = hdtr->numtrailers; 570 571 /* FreeBSD can send the headers/footers as part of the system call */ 572 do { 573 if (sock->options & APR_INCOMPLETE_WRITE) { 574 apr_status_t arv; 575 sock->options &= ~APR_INCOMPLETE_WRITE; 576 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 577 if (arv != APR_SUCCESS) { 578 *len = 0; 579 return arv; 580 } 581 } 582 if (bytes_to_send) { 583 /* We won't dare call sendfile() if we don't have 584 * header or file bytes to send because bytes_to_send == 0 585 * means send the whole file. 586 */ 587 rv = sendfile(file->filedes, /* file to be sent */ 588 sock->socketdes, /* socket */ 589 *offset, /* where in the file to start */ 590 bytes_to_send, /* number of bytes to send */ 591 &headerstruct, /* Headers/footers */ 592 &nbytes, /* number of bytes written */ 593 flags); /* undefined, set to 0 */ 594 595 if (rv == -1) { 596 if (errno == EAGAIN) { 597 if (sock->timeout > 0) { 598 sock->options |= APR_INCOMPLETE_WRITE; 599 } 600 /* FreeBSD's sendfile can return -1/EAGAIN even if it 601 * sent bytes. Sanitize the result so we get normal EAGAIN 602 * semantics w.r.t. bytes sent. 603 */ 604 if (nbytes) { 605 /* normal exit for a big file & non-blocking io */ 606 (*len) = nbytes; 607 return APR_SUCCESS; 608 } 609 } 610 } 611 else { /* rv == 0 (or the kernel is broken) */ 612 if (nbytes == 0) { 613 /* Most likely the file got smaller after the stat. 614 * Return an error so the caller can do the Right Thing. 615 */ 616 (*len) = nbytes; 617 return APR_EOF; 618 } 619 } 620 } 621 else { 622 /* just trailer bytes... use writev() 623 */ 624 rv = writev(sock->socketdes, 625 hdtr->trailers, 626 hdtr->numtrailers); 627 if (rv > 0) { 628 nbytes = rv; 629 rv = 0; 630 } 631 else { 632 nbytes = 0; 633 } 634 } 635 if ((rv == -1) && (errno == EAGAIN) 636 && (sock->timeout > 0)) { 637 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 638 if (arv != APR_SUCCESS) { 639 *len = 0; 640 return arv; 641 } 642 } 643 } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 644 645 (*len) = nbytes; 646 if (rv == -1) { 647 return errno; 648 } 649 return APR_SUCCESS; 650} 651 652#elif defined(__hpux) || defined(__hpux__) 653 654/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */ 655 656/* HP-UX Version 10.30 or greater 657 * (no worries, because we only get here if autoconfiguration found sendfile) 658 */ 659 660/* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes, 661 * const struct iovec *hdtrl, int flags); 662 * 663 * nbytes is the number of bytes to send just from the file; as with FreeBSD, 664 * if nbytes == 0, the rest of the file (from offset) is sent 665 */ 666 667apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, 668 apr_hdtr_t *hdtr, apr_off_t *offset, 669 apr_size_t *len, apr_int32_t flags) 670{ 671 int i; 672 apr_ssize_t rc; 673 apr_size_t nbytes = *len, headerlen, trailerlen; 674 struct iovec hdtrarray[2]; 675 char *headerbuf, *trailerbuf; 676 677#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) 678 /* later HP-UXes have a sendfile64() */ 679#define sendfile sendfile64 680 apr_off_t off = *offset; 681 682#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 683 /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send 684 * past the 2Gb limit */ 685 off_t off; 686 687 if ((apr_int64_t)*offset + *len > INT_MAX) { 688 return EINVAL; 689 } 690 off = *offset; 691#else 692 apr_off_t off = *offset; 693#endif 694 695 if (!hdtr) { 696 hdtr = &no_hdtr; 697 } 698 699 /* Ignore flags for now. */ 700 flags = 0; 701 702 /* HP-UX can only send one header iovec and one footer iovec; try to 703 * only allocate storage to combine input iovecs when we really have to 704 */ 705 706 switch(hdtr->numheaders) { 707 case 0: 708 hdtrarray[0].iov_base = NULL; 709 hdtrarray[0].iov_len = 0; 710 break; 711 case 1: 712 hdtrarray[0] = hdtr->headers[0]; 713 break; 714 default: 715 headerlen = 0; 716 for (i = 0; i < hdtr->numheaders; i++) { 717 headerlen += hdtr->headers[i].iov_len; 718 } 719 720 /* XXX: BUHHH? wow, what a memory leak! */ 721 headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen); 722 hdtrarray[0].iov_len = headerlen; 723 724 for (i = 0; i < hdtr->numheaders; i++) { 725 memcpy(headerbuf, hdtr->headers[i].iov_base, 726 hdtr->headers[i].iov_len); 727 headerbuf += hdtr->headers[i].iov_len; 728 } 729 } 730 731 switch(hdtr->numtrailers) { 732 case 0: 733 hdtrarray[1].iov_base = NULL; 734 hdtrarray[1].iov_len = 0; 735 break; 736 case 1: 737 hdtrarray[1] = hdtr->trailers[0]; 738 break; 739 default: 740 trailerlen = 0; 741 for (i = 0; i < hdtr->numtrailers; i++) { 742 trailerlen += hdtr->trailers[i].iov_len; 743 } 744 745 /* XXX: BUHHH? wow, what a memory leak! */ 746 trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen); 747 hdtrarray[1].iov_len = trailerlen; 748 749 for (i = 0; i < hdtr->numtrailers; i++) { 750 memcpy(trailerbuf, hdtr->trailers[i].iov_base, 751 hdtr->trailers[i].iov_len); 752 trailerbuf += hdtr->trailers[i].iov_len; 753 } 754 } 755 756 do { 757 if (nbytes) { /* any bytes to send from the file? */ 758 rc = sendfile(sock->socketdes, /* socket */ 759 file->filedes, /* file descriptor to send */ 760 off, /* where in the file to start */ 761 nbytes, /* number of bytes to send from file */ 762 hdtrarray, /* Headers/footers */ 763 flags); /* undefined, set to 0 */ 764 } 765 else { /* we can't call sendfile() with no bytes to send from the file */ 766 rc = writev(sock->socketdes, hdtrarray, 2); 767 } 768 } while (rc == -1 && errno == EINTR); 769 770 while ((rc == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 771 && (sock->timeout > 0)) { 772 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 773 774 if (arv != APR_SUCCESS) { 775 *len = 0; 776 return arv; 777 } 778 else { 779 do { 780 if (nbytes) { 781 rc = sendfile(sock->socketdes, /* socket */ 782 file->filedes, /* file descriptor to send */ 783 off, /* where in the file to start */ 784 nbytes, /* number of bytes to send from file */ 785 hdtrarray, /* Headers/footers */ 786 flags); /* undefined, set to 0 */ 787 } 788 else { /* we can't call sendfile() with no bytes to send from the file */ 789 rc = writev(sock->socketdes, hdtrarray, 2); 790 } 791 } while (rc == -1 && errno == EINTR); 792 } 793 } 794 795 if (rc == -1) { 796 *len = 0; 797 return errno; 798 } 799 800 /* Set len to the number of bytes written */ 801 *len = rc; 802 return APR_SUCCESS; 803} 804#elif defined(_AIX) || defined(__MVS__) 805/* AIX and OS/390 have the same send_file() interface. 806 * 807 * subtle differences: 808 * AIX doesn't update the file ptr but OS/390 does 809 * 810 * availability (correctly determined by autoconf): 811 * 812 * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above 813 * OS/390 - V2R7 and above 814 */ 815apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, 816 apr_hdtr_t * hdtr, apr_off_t * offset, 817 apr_size_t * len, apr_int32_t flags) 818{ 819 int i, ptr, rv = 0; 820 void * hbuf=NULL, * tbuf=NULL; 821 apr_status_t arv; 822 struct sf_parms parms; 823 824 if (!hdtr) { 825 hdtr = &no_hdtr; 826 } 827 828 /* Ignore flags for now. */ 829 flags = 0; 830 831 /* word to the wise: by default, AIX stores files sent by send_file() 832 * in the network buffer cache... there are supposedly scenarios 833 * where the most recent copy of the file won't be sent, but I can't 834 * recreate the potential problem, perhaps because of the way we 835 * use send_file()... if you suspect such a problem, try turning 836 * on the SF_SYNC_CACHE flag 837 */ 838 839 /* AIX can also send the headers/footers as part of the system call */ 840 parms.header_length = 0; 841 if (hdtr && hdtr->numheaders) { 842 if (hdtr->numheaders == 1) { 843 parms.header_data = hdtr->headers[0].iov_base; 844 parms.header_length = hdtr->headers[0].iov_len; 845 } 846 else { 847 for (i = 0; i < hdtr->numheaders; i++) { 848 parms.header_length += hdtr->headers[i].iov_len; 849 } 850#if 0 851 /* Keepalives make apr_palloc a bad idea */ 852 hbuf = malloc(parms.header_length); 853#else 854 /* but headers are small, so maybe we can hold on to the 855 * memory for the life of the socket... 856 */ 857 hbuf = apr_palloc(sock->pool, parms.header_length); 858#endif 859 ptr = 0; 860 for (i = 0; i < hdtr->numheaders; i++) { 861 memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base, 862 hdtr->headers[i].iov_len); 863 ptr += hdtr->headers[i].iov_len; 864 } 865 parms.header_data = hbuf; 866 } 867 } 868 else parms.header_data = NULL; 869 parms.trailer_length = 0; 870 if (hdtr && hdtr->numtrailers) { 871 if (hdtr->numtrailers == 1) { 872 parms.trailer_data = hdtr->trailers[0].iov_base; 873 parms.trailer_length = hdtr->trailers[0].iov_len; 874 } 875 else { 876 for (i = 0; i < hdtr->numtrailers; i++) { 877 parms.trailer_length += hdtr->trailers[i].iov_len; 878 } 879#if 0 880 /* Keepalives make apr_palloc a bad idea */ 881 tbuf = malloc(parms.trailer_length); 882#else 883 tbuf = apr_palloc(sock->pool, parms.trailer_length); 884#endif 885 ptr = 0; 886 for (i = 0; i < hdtr->numtrailers; i++) { 887 memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base, 888 hdtr->trailers[i].iov_len); 889 ptr += hdtr->trailers[i].iov_len; 890 } 891 parms.trailer_data = tbuf; 892 } 893 } 894 else { 895 parms.trailer_data = NULL; 896 } 897 898 /* Whew! Headers and trailers set up. Now for the file data */ 899 900 parms.file_descriptor = file->filedes; 901 parms.file_offset = *offset; 902 parms.file_bytes = *len; 903 904 /* O.K. All set up now. Let's go to town */ 905 906 if (sock->options & APR_INCOMPLETE_WRITE) { 907 sock->options &= ~APR_INCOMPLETE_WRITE; 908 goto do_select; 909 } 910 911 do { 912 rv = send_file(&(sock->socketdes), /* socket */ 913 &(parms), /* all data */ 914 flags); /* flags */ 915 } while (rv == -1 && errno == EINTR); 916 917 while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) 918 && (sock->timeout > 0)) { 919do_select: 920 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 921 if (arv != APR_SUCCESS) { 922 *len = 0; 923 return arv; 924 } 925 else { 926 do { 927 rv = send_file(&(sock->socketdes), /* socket */ 928 &(parms), /* all data */ 929 flags); /* flags */ 930 } while (rv == -1 && errno == EINTR); 931 } 932 } 933 934 (*len) = parms.bytes_sent; 935 936#if 0 937 /* Clean up after ourselves */ 938 if(hbuf) free(hbuf); 939 if(tbuf) free(tbuf); 940#endif 941 942 if (rv == -1) { 943 return errno; 944 } 945 946 if ((sock->timeout > 0) 947 && (parms.bytes_sent 948 < (parms.file_bytes + parms.header_length + parms.trailer_length))) { 949 sock->options |= APR_INCOMPLETE_WRITE; 950 } 951 952 return APR_SUCCESS; 953} 954#elif defined(__osf__) && defined (__alpha) 955/* Tru64's sendfile implementation doesn't work, and we need to make sure that 956 * we don't use it until it is fixed. If it is used as it is now, it will 957 * hang the machine and the only way to fix it is a reboot. 958 */ 959#elif defined(HAVE_SENDFILEV) 960/* Solaris 8's sendfilev() interface 961 * 962 * SFV_FD_SELF refers to our memory space. 963 * 964 * Required Sparc patches (or newer): 965 * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03, 966 * 108991-13 967 * Required x86 patches (or newer): 968 * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04, 969 * 108992-13 970 */ 971 972#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILEV64) 973#define sendfilevec_t sendfilevec64_t 974#define sendfilev sendfilev64 975#endif 976 977apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, 978 apr_hdtr_t *hdtr, apr_off_t *offset, 979 apr_size_t *len, apr_int32_t flags) 980{ 981 apr_status_t rv, arv; 982 apr_size_t nbytes; 983 sendfilevec_t *sfv; 984 int vecs, curvec, i, repeat; 985 apr_size_t requested_len = 0; 986 987 if (!hdtr) { 988 hdtr = &no_hdtr; 989 } 990 991 /* Ignore flags for now. */ 992 flags = 0; 993 994 /* Calculate how much space we need. */ 995 vecs = hdtr->numheaders + hdtr->numtrailers + 1; 996 sfv = apr_palloc(sock->pool, sizeof(sendfilevec_t) * vecs); 997 998 curvec = 0; 999 1000 /* Add the headers */ 1001 for (i = 0; i < hdtr->numheaders; i++, curvec++) { 1002 sfv[curvec].sfv_fd = SFV_FD_SELF; 1003 sfv[curvec].sfv_flag = 0; 1004 /* Cast to unsigned long to prevent sign extension of the 1005 * pointer value for the LFS case; see PR 39463. */ 1006 sfv[curvec].sfv_off = (unsigned long)hdtr->headers[i].iov_base; 1007 sfv[curvec].sfv_len = hdtr->headers[i].iov_len; 1008 requested_len += sfv[curvec].sfv_len; 1009 } 1010 1011 /* If the len is 0, we skip the file. */ 1012 if (*len) 1013 { 1014 sfv[curvec].sfv_fd = file->filedes; 1015 sfv[curvec].sfv_flag = 0; 1016 sfv[curvec].sfv_off = *offset; 1017 sfv[curvec].sfv_len = *len; 1018 requested_len += sfv[curvec].sfv_len; 1019 1020 curvec++; 1021 } 1022 else { 1023 vecs--; 1024 } 1025 1026 /* Add the footers */ 1027 for (i = 0; i < hdtr->numtrailers; i++, curvec++) { 1028 sfv[curvec].sfv_fd = SFV_FD_SELF; 1029 sfv[curvec].sfv_flag = 0; 1030 sfv[curvec].sfv_off = (unsigned long)hdtr->trailers[i].iov_base; 1031 sfv[curvec].sfv_len = hdtr->trailers[i].iov_len; 1032 requested_len += sfv[curvec].sfv_len; 1033 } 1034 1035 /* If the last write couldn't send all the requested data, 1036 * wait for the socket to become writable before proceeding 1037 */ 1038 if (sock->options & APR_INCOMPLETE_WRITE) { 1039 sock->options &= ~APR_INCOMPLETE_WRITE; 1040 arv = apr_wait_for_io_or_timeout(NULL, sock, 0); 1041 if (arv != APR_SUCCESS) { 1042 *len = 0; 1043 return arv; 1044 } 1045 } 1046 1047 /* Actually do the sendfilev 1048 * 1049 * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock. 1050 * 1051 * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT 1052 * socket (which as far as the OS is concerned is a non-blocking socket), 1053 * we want to retry after waiting for the other side to read the data (as 1054 * determined by poll). Once it is clear to send, we want to retry 1055 * sending the sendfilevec_t once more. 1056 */ 1057 arv = 0; 1058 do { 1059 /* Clear out the repeat */ 1060 repeat = 0; 1061 1062 /* socket, vecs, number of vecs, bytes written */ 1063 rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes); 1064 1065 if (rv == -1 && errno == EAGAIN) { 1066 if (nbytes) { 1067 rv = 0; 1068 } 1069 else if (!arv && (sock->timeout > 0)) { 1070 apr_status_t t = apr_wait_for_io_or_timeout(NULL, sock, 0); 1071 1072 if (t != APR_SUCCESS) { 1073 *len = 0; 1074 return t; 1075 } 1076 1077 arv = 1; 1078 repeat = 1; 1079 } 1080 } 1081 } while ((rv == -1 && errno == EINTR) || repeat); 1082 1083 if (rv == -1) { 1084 *len = 0; 1085 return errno; 1086 } 1087 1088 /* Update how much we sent */ 1089 *len = nbytes; 1090 1091 if (nbytes == 0) { 1092 /* Most likely the file got smaller after the stat. 1093 * Return an error so the caller can do the Right Thing. 1094 */ 1095 return APR_EOF; 1096 } 1097 1098 if ((sock->timeout > 0) && (*len < requested_len)) { 1099 sock->options |= APR_INCOMPLETE_WRITE; 1100 } 1101 return APR_SUCCESS; 1102} 1103#else 1104#error APR has detected sendfile on your system, but nobody has written a 1105#error version of it for APR yet. To get past this, either write 1106#error apr_socket_sendfile or change APR_HAS_SENDFILE in apr.h to 0. 1107#endif /* __linux__, __FreeBSD__, __DragonFly__, __HPUX__, _AIX, __MVS__, 1108 Tru64/OSF1 */ 1109 1110#endif /* APR_HAS_SENDFILE */ 1111