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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "apr_arch_networkio.h"
18 #include "apr_support.h"
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 */
25 /* sys/sysctl.h is only needed on FreeBSD for include_hdrs_in_length() */
26 #if defined(__FreeBSD__) && defined(HAVE_SYS_SYSCTL_H)
27 #include <sys/sysctl.h>
30 apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf,
35 if (sock->netmask & APR_INCOMPLETE_WRITE) {
36 sock->netmask &= ~APR_INCOMPLETE_WRITE;
41 rv = write(sock->socketdes, buf, (*len));
42 } while (rv == -1 && errno == EINTR);
44 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)
45 && apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
48 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
49 if (arv != APR_SUCCESS) {
55 rv = write(sock->socketdes, buf, (*len));
56 } while (rv == -1 && errno == EINTR);
63 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) && rv < *len) {
64 sock->netmask |= APR_INCOMPLETE_WRITE;
70 apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
75 if (sock->netmask & APR_INCOMPLETE_READ) {
76 sock->netmask &= ~APR_INCOMPLETE_READ;
81 rv = read(sock->socketdes, buf, (*len));
82 } while (rv == -1 && errno == EINTR);
84 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
85 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
87 arv = apr_wait_for_io_or_timeout(NULL, sock, 1);
88 if (arv != APR_SUCCESS) {
94 rv = read(sock->socketdes, buf, (*len));
95 } while (rv == -1 && errno == EINTR);
102 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) && rv < *len) {
103 sock->netmask |= APR_INCOMPLETE_READ;
112 apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where,
113 apr_int32_t flags, const char *buf,
119 rv = sendto(sock->socketdes, buf, (*len), flags,
120 (const struct sockaddr*)&where->sa,
122 } while (rv == -1 && errno == EINTR);
124 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)
125 && apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
126 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
127 if (arv != APR_SUCCESS) {
132 rv = sendto(sock->socketdes, buf, (*len), flags,
133 (const struct sockaddr*)&where->sa,
135 } while (rv == -1 && errno == EINTR);
146 apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock,
147 apr_int32_t flags, char *buf,
153 rv = recvfrom(sock->socketdes, buf, (*len), flags,
154 (struct sockaddr*)&from->sa, &from->salen);
155 } while (rv == -1 && errno == EINTR);
157 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
158 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
159 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1);
160 if (arv != APR_SUCCESS) {
165 rv = recvfrom(sock->socketdes, buf, (*len), flags,
166 (struct sockaddr*)&from->sa, &from->salen);
167 } while (rv == -1 && errno == EINTR);
176 if (rv == 0 && sock->type == SOCK_STREAM) {
184 apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec,
185 apr_int32_t nvec, apr_size_t *len)
188 apr_size_t requested_len = 0;
191 for (i = 0; i < nvec; i++) {
192 requested_len += vec[i].iov_len;
195 if (sock->netmask & APR_INCOMPLETE_WRITE) {
196 sock->netmask &= ~APR_INCOMPLETE_WRITE;
201 rv = writev(sock->socketdes, vec, nvec);
202 } while (rv == -1 && errno == EINTR);
204 while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
205 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
208 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
209 if (arv != APR_SUCCESS) {
215 rv = writev(sock->socketdes, vec, nvec);
216 } while (rv == -1 && errno == EINTR);
223 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) &&
224 rv < requested_len) {
225 sock->netmask |= APR_INCOMPLETE_WRITE;
234 /* TODO: Verify that all platforms handle the fd the same way,
235 * i.e. that they don't move the file pointer.
237 /* TODO: what should flags be? int_32? */
239 /* Define a structure to pass in when we have a NULL header value */
240 static apr_hdtr_t no_hdtr;
242 #if defined(__linux__) && defined(HAVE_WRITEV)
244 apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
245 apr_hdtr_t *hdtr, apr_off_t *offset,
246 apr_size_t *len, apr_int32_t flags)
249 int rv, nbytes = 0, total_hdrbytes, i;
256 /* Ignore flags for now. */
259 if (hdtr->numheaders > 0) {
262 /* cork before writing headers */
263 rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1);
264 if (rv != APR_SUCCESS) {
268 /* Now write the headers */
269 arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders,
271 if (arv != APR_SUCCESS) {
277 /* If this was a partial write and we aren't doing timeouts,
278 * return now with the partial byte count; this is a non-blocking
282 for (i = 0; i < hdtr->numheaders; i++) {
283 total_hdrbytes += hdtr->headers[i].iov_len;
285 if (hdrbytes < total_hdrbytes) {
287 return apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0);
291 if (sock->netmask & APR_INCOMPLETE_WRITE) {
292 sock->netmask &= ~APR_INCOMPLETE_WRITE;
297 rv = sendfile(sock->socketdes, /* socket */
298 file->filedes, /* open file descriptor of the file to be sent */
299 &off, /* where in the file to start */
300 *len); /* number of bytes to send */
301 } while (rv == -1 && errno == EINTR);
304 (errno == EAGAIN || errno == EWOULDBLOCK) &&
305 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
307 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
308 if (arv != APR_SUCCESS) {
314 rv = sendfile(sock->socketdes, /* socket */
315 file->filedes, /* open file descriptor of the file to be sent */
316 &off, /* where in the file to start */
317 *len); /* number of bytes to send */
318 } while (rv == -1 && errno == EINTR);
325 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0);
333 arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0);
336 /* If this was a partial write, return now with the
337 * partial byte count; this is a non-blocking socket.
340 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
341 sock->netmask |= APR_INCOMPLETE_WRITE;
346 /* If the file got smaller mid-request, eventually the offset
347 * becomes equal to the new file size and the kernel returns 0.
348 * Make this an error so the caller knows to log something and
355 /* Now write the footers */
356 if (hdtr->numtrailers > 0) {
358 arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
361 if (arv != APR_SUCCESS) {
364 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0);
369 apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0);
372 return rv < 0 ? errno : APR_SUCCESS;
375 #elif defined(__FreeBSD__)
377 static int include_hdrs_in_length(void)
379 #ifdef HAVE_SYS_SYSCTL_H
381 * if the header exists, so does the sysctlbyname() syscall, and
382 * if the header doesn't exist, the kernel is really old
386 * http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/param.h#rev1.61.2.29
387 * for kernel version number
389 * http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_syscalls.c#rev1.65.2.10
390 * for the sendfile patch
392 #define KERNEL_WITH_SENDFILE_LENGTH_FIX 460001
394 typedef enum { UNKNOWN = 0,
401 apr_size_t kernel_version_size;
403 if (api != UNKNOWN) {
406 kernel_version = 0; /* silence compiler warning */
407 kernel_version_size = sizeof(kernel_version);
408 if (sysctlbyname("kern.osreldate", &kernel_version,
409 &kernel_version_size, NULL, 0) == 0 &&
410 kernel_version < KERNEL_WITH_SENDFILE_LENGTH_FIX) {
414 /* size of kern.osreldate's output might change in the future
415 * causing the sysctlbyname to fail,
416 * but if it's the future, we should use the newer API
421 /* the build system's kernel is older than 3.4. Use the old API */
426 /* Release 3.1 or greater */
427 apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
428 apr_hdtr_t * hdtr, apr_off_t * offset,
429 apr_size_t * len, apr_int32_t flags)
433 struct sf_hdtr headerstruct;
434 apr_size_t bytes_to_send = *len;
436 /* Ignore flags for now. */
443 else if (hdtr->numheaders && include_hdrs_in_length()) {
445 /* On early versions of FreeBSD sendfile, the number of bytes to send
446 * must include the length of the headers. Don't look at the man page
447 * for this :( Instead, look at the the logic in
448 * src/sys/kern/uipc_syscalls::sendfile().
450 * This was fixed in the middle of 4.6-STABLE
452 for (i = 0; i < hdtr->numheaders; i++) {
453 bytes_to_send += hdtr->headers[i].iov_len;
457 headerstruct.headers = hdtr->headers;
458 headerstruct.hdr_cnt = hdtr->numheaders;
459 headerstruct.trailers = hdtr->trailers;
460 headerstruct.trl_cnt = hdtr->numtrailers;
462 /* FreeBSD can send the headers/footers as part of the system call */
464 if (sock->netmask & APR_INCOMPLETE_WRITE) {
466 sock->netmask &= ~APR_INCOMPLETE_WRITE;
467 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
468 if (arv != APR_SUCCESS) {
474 /* We won't dare call sendfile() if we don't have
475 * header or file bytes to send because bytes_to_send == 0
476 * means send the whole file.
478 rv = sendfile(file->filedes, /* file to be sent */
479 sock->socketdes, /* socket */
480 *offset, /* where in the file to start */
481 bytes_to_send, /* number of bytes to send */
482 &headerstruct, /* Headers/footers */
483 &nbytes, /* number of bytes written */
484 flags); /* undefined, set to 0 */
487 if (errno == EAGAIN) {
488 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
489 sock->netmask |= APR_INCOMPLETE_WRITE;
491 /* FreeBSD's sendfile can return -1/EAGAIN even if it
492 * sent bytes. Sanitize the result so we get normal EAGAIN
493 * semantics w.r.t. bytes sent.
496 /* normal exit for a big file & non-blocking io */
502 else { /* rv == 0 (or the kernel is broken) */
504 /* Most likely the file got smaller after the stat.
505 * Return an error so the caller can do the Right Thing.
513 /* just trailer bytes... use writev()
515 rv = writev(sock->socketdes,
528 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
529 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
530 if (arv != APR_SUCCESS) {
535 } while (rv == -1 && (errno == EINTR || errno == EAGAIN));
544 #elif defined(__hpux) || defined(__hpux__)
546 /* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */
548 /* HP-UX Version 10.30 or greater
549 * (no worries, because we only get here if autoconfiguration found sendfile)
552 /* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes,
553 * const struct iovec *hdtrl, int flags);
555 * nbytes is the number of bytes to send just from the file; as with FreeBSD,
556 * if nbytes == 0, the rest of the file (from offset) is sent
559 apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
560 apr_hdtr_t *hdtr, apr_off_t *offset,
561 apr_size_t *len, apr_int32_t flags)
565 apr_size_t nbytes = *len, headerlen, trailerlen;
566 struct iovec hdtrarray[2];
567 char *headerbuf, *trailerbuf;
573 /* Ignore flags for now. */
576 /* HP-UX can only send one header iovec and one footer iovec; try to
577 * only allocate storage to combine input iovecs when we really have to
580 switch(hdtr->numheaders) {
582 hdtrarray[0].iov_base = NULL;
583 hdtrarray[0].iov_len = 0;
586 hdtrarray[0] = hdtr->headers[0];
590 for (i = 0; i < hdtr->numheaders; i++) {
591 headerlen += hdtr->headers[i].iov_len;
594 /* XXX: BUHHH? wow, what a memory leak! */
595 headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->cntxt, headerlen);
596 hdtrarray[0].iov_len = headerlen;
598 for (i = 0; i < hdtr->numheaders; i++) {
599 memcpy(headerbuf, hdtr->headers[i].iov_base,
600 hdtr->headers[i].iov_len);
601 headerbuf += hdtr->headers[i].iov_len;
605 switch(hdtr->numtrailers) {
607 hdtrarray[1].iov_base = NULL;
608 hdtrarray[1].iov_len = 0;
611 hdtrarray[1] = hdtr->trailers[0];
615 for (i = 0; i < hdtr->numtrailers; i++) {
616 trailerlen += hdtr->trailers[i].iov_len;
619 /* XXX: BUHHH? wow, what a memory leak! */
620 trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->cntxt, trailerlen);
621 hdtrarray[1].iov_len = trailerlen;
623 for (i = 0; i < hdtr->numtrailers; i++) {
624 memcpy(trailerbuf, hdtr->trailers[i].iov_base,
625 hdtr->trailers[i].iov_len);
626 trailerbuf += hdtr->trailers[i].iov_len;
631 if (nbytes) { /* any bytes to send from the file? */
632 rc = sendfile(sock->socketdes, /* socket */
633 file->filedes, /* file descriptor to send */
634 *offset, /* where in the file to start */
635 nbytes, /* number of bytes to send from file */
636 hdtrarray, /* Headers/footers */
637 flags); /* undefined, set to 0 */
639 else { /* we can't call sendfile() with no bytes to send from the file */
640 rc = writev(sock->socketdes, hdtrarray, 2);
642 } while (rc == -1 && errno == EINTR);
645 (errno == EAGAIN || errno == EWOULDBLOCK) &&
646 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
647 apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
649 if (arv != APR_SUCCESS) {
656 rc = sendfile(sock->socketdes, /* socket */
657 file->filedes, /* file descriptor to send */
658 *offset, /* where in the file to start */
659 nbytes, /* number of bytes to send from file */
660 hdtrarray, /* Headers/footers */
661 flags); /* undefined, set to 0 */
663 else { /* we can't call sendfile() with no bytes to send from the file */
664 rc = writev(sock->socketdes, hdtrarray, 2);
666 } while (rc == -1 && errno == EINTR);
675 /* Set len to the number of bytes written */
679 #elif defined(_AIX) || defined(__MVS__)
680 /* AIX and OS/390 have the same send_file() interface.
682 * subtle differences:
683 * AIX doesn't update the file ptr but OS/390 does
685 * availability (correctly determined by autoconf):
687 * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above
688 * OS/390 - V2R7 and above
690 apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
691 apr_hdtr_t * hdtr, apr_off_t * offset,
692 apr_size_t * len, apr_int32_t flags)
695 void * hbuf=NULL, * tbuf=NULL;
697 struct sf_parms parms;
703 /* Ignore flags for now. */
706 /* word to the wise: by default, AIX stores files sent by send_file()
707 * in the network buffer cache... there are supposedly scenarios
708 * where the most recent copy of the file won't be sent, but I can't
709 * recreate the potential problem, perhaps because of the way we
710 * use send_file()... if you suspect such a problem, try turning
711 * on the SF_SYNC_CACHE flag
714 /* AIX can also send the headers/footers as part of the system call */
715 parms.header_length = 0;
716 if (hdtr && hdtr->numheaders) {
717 if (hdtr->numheaders == 1) {
718 parms.header_data = hdtr->headers[0].iov_base;
719 parms.header_length = hdtr->headers[0].iov_len;
722 for (i = 0; i < hdtr->numheaders; i++) {
723 parms.header_length += hdtr->headers[i].iov_len;
726 /* Keepalives make apr_palloc a bad idea */
727 hbuf = malloc(parms.header_length);
729 /* but headers are small, so maybe we can hold on to the
730 * memory for the life of the socket...
732 hbuf = apr_palloc(sock->cntxt, parms.header_length);
735 for (i = 0; i < hdtr->numheaders; i++) {
736 memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base,
737 hdtr->headers[i].iov_len);
738 ptr += hdtr->headers[i].iov_len;
740 parms.header_data = hbuf;
743 else parms.header_data = NULL;
744 parms.trailer_length = 0;
745 if (hdtr && hdtr->numtrailers) {
746 if (hdtr->numtrailers == 1) {
747 parms.trailer_data = hdtr->trailers[0].iov_base;
748 parms.trailer_length = hdtr->trailers[0].iov_len;
751 for (i = 0; i < hdtr->numtrailers; i++) {
752 parms.trailer_length += hdtr->trailers[i].iov_len;
755 /* Keepalives make apr_palloc a bad idea */
756 tbuf = malloc(parms.trailer_length);
758 tbuf = apr_palloc(sock->cntxt, parms.trailer_length);
761 for (i = 0; i < hdtr->numtrailers; i++) {
762 memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base,
763 hdtr->trailers[i].iov_len);
764 ptr += hdtr->trailers[i].iov_len;
766 parms.trailer_data = tbuf;
770 parms.trailer_data = NULL;
773 /* Whew! Headers and trailers set up. Now for the file data */
775 parms.file_descriptor = file->filedes;
776 parms.file_offset = *offset;
777 parms.file_bytes = *len;
779 /* O.K. All set up now. Let's go to town */
781 if (sock->netmask & APR_INCOMPLETE_WRITE) {
782 sock->netmask &= ~APR_INCOMPLETE_WRITE;
787 rv = send_file(&(sock->socketdes), /* socket */
788 &(parms), /* all data */
790 } while (rv == -1 && errno == EINTR);
793 (errno == EAGAIN || errno == EWOULDBLOCK) &&
794 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) {
796 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
797 if (arv != APR_SUCCESS) {
803 rv = send_file(&(sock->socketdes), /* socket */
804 &(parms), /* all data */
806 } while (rv == -1 && errno == EINTR);
810 (*len) = parms.bytes_sent;
813 /* Clean up after ourselves */
822 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) &&
823 (parms.bytes_sent < (parms.file_bytes + parms.header_length + parms.trailer_length))) {
824 sock->netmask |= APR_INCOMPLETE_WRITE;
829 #elif defined(__osf__) && defined (__alpha)
830 /* Tru64's sendfile implementation doesn't work, and we need to make sure that
831 * we don't use it until it is fixed. If it is used as it is now, it will
832 * hang the machine and the only way to fix it is a reboot.
834 #elif defined(HAVE_SENDFILEV)
835 /* Solaris 8's sendfilev() interface
837 * SFV_FD_SELF refers to our memory space.
839 * Required Sparc patches (or newer):
840 * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03,
842 * Required x86 patches (or newer):
843 * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04,
846 apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
847 apr_hdtr_t *hdtr, apr_off_t *offset,
848 apr_size_t *len, apr_int32_t flags)
850 apr_status_t rv, arv;
853 int vecs, curvec, i, repeat;
854 apr_size_t requested_len = 0;
860 /* Ignore flags for now. */
863 /* Calculate how much space we need. */
864 vecs = hdtr->numheaders + hdtr->numtrailers + 1;
865 sfv = apr_palloc(sock->cntxt, sizeof(sendfilevec_t) * vecs);
869 /* Add the headers */
870 for (i = 0; i < hdtr->numheaders; i++, curvec++) {
871 sfv[curvec].sfv_fd = SFV_FD_SELF;
872 sfv[curvec].sfv_flag = 0;
873 sfv[curvec].sfv_off = (off_t)hdtr->headers[i].iov_base;
874 sfv[curvec].sfv_len = hdtr->headers[i].iov_len;
875 requested_len += sfv[curvec].sfv_len;
878 /* If the len is 0, we skip the file. */
881 sfv[curvec].sfv_fd = file->filedes;
882 sfv[curvec].sfv_flag = 0;
883 sfv[curvec].sfv_off = *offset;
884 sfv[curvec].sfv_len = *len;
885 requested_len += sfv[curvec].sfv_len;
893 /* Add the footers */
894 for (i = 0; i < hdtr->numtrailers; i++, curvec++) {
895 sfv[curvec].sfv_fd = SFV_FD_SELF;
896 sfv[curvec].sfv_flag = 0;
897 sfv[curvec].sfv_off = (off_t)hdtr->trailers[i].iov_base;
898 sfv[curvec].sfv_len = hdtr->trailers[i].iov_len;
899 requested_len += sfv[curvec].sfv_len;
902 /* If the last write couldn't send all the requested data,
903 * wait for the socket to become writable before proceeding
905 if (sock->netmask & APR_INCOMPLETE_WRITE) {
906 sock->netmask &= ~APR_INCOMPLETE_WRITE;
907 arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
908 if (arv != APR_SUCCESS) {
914 /* Actually do the sendfilev
916 * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock.
918 * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT
919 * socket (which as far as the OS is concerned is a non-blocking socket),
920 * we want to retry after waiting for the other side to read the data (as
921 * determined by poll). Once it is clear to send, we want to retry
922 * sending the sendfilevec_t once more.
926 /* Clear out the repeat */
929 /* socket, vecs, number of vecs, bytes written */
930 rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes);
932 if (rv == -1 && errno == EAGAIN) {
937 apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) == 1) {
938 apr_status_t t = apr_wait_for_io_or_timeout(NULL, sock, 0);
940 if (t != APR_SUCCESS) {
949 } while ((rv == -1 && errno == EINTR) || repeat);
956 /* Update how much we sent */
958 if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT) &&
959 (*len < requested_len)) {
960 sock->netmask |= APR_INCOMPLETE_WRITE;
965 #error APR has detected sendfile on your system, but nobody has written a
966 #error version of it for APR yet. To get past this, either write apr_sendfile
967 #error or change APR_HAS_SENDFILE in apr.h to 0.
968 #endif /* __linux__, __FreeBSD__, __HPUX__, _AIX, __MVS__, Tru64/OSF1 */
971 apr_status_t apr_sendfile(apr_socket_t *sock, apr_file_t *file,
972 apr_hdtr_t *hdtr, apr_off_t *offset, apr_size_t *len,
975 return apr_socket_sendfile(sock, file, hdtr, offset, len, flags);
978 #endif /* APR_HAS_SENDFILE */
981 apr_status_t apr_send(apr_socket_t *sock, const char *buf, apr_size_t *len)
983 return apr_socket_send(sock, buf, len);
988 apr_status_t apr_sendv(apr_socket_t * sock, const struct iovec *vec,
989 apr_int32_t nvec, apr_size_t *len)
991 return apr_socket_sendv(sock, vec, nvec, len);
996 apr_status_t apr_sendto(apr_socket_t *sock, apr_sockaddr_t *where,
997 apr_int32_t flags, const char *buf, apr_size_t *len)
999 return apr_socket_sendto(sock, where, flags, buf, len);
1003 apr_status_t apr_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock,
1004 apr_int32_t flags, char *buf,
1007 return apr_socket_recvfrom(from, sock, flags, buf, len);
1011 apr_status_t apr_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
1013 return apr_socket_recv(sock, buf, len);