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