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