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