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