]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr/network_io/unix/sendrecv.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr / network_io / unix / sendrecv.c
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
30 apr_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;
47 do_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
70 apr_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)) {
86 do_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
112 apr_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
146 apr_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
194 apr_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;
218 do_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 */
253 static apr_hdtr_t no_hdtr;
254
255 #if (defined(__linux__) || defined(__GNU__)) && defined(HAVE_WRITEV)
256
257 apr_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)) {
341 do_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 */
413 apr_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 */
531 apr_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
667 apr_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  */
815 apr_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)) {
919 do_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
977 apr_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 */