apr  1.7.0
About: APR (Apache Portable Runtime) project offers software libraries that provide a predictable and consistent interface to underlying platform-specific implementations (APR core library).
  Fossies Dox: apr-1.7.0.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

sendrecv.c
Go to the documentation of this file.
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 
31  apr_size_t *len)
32 {
33  apr_ssize_t rv;
34 
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)) {
65  }
66  (*len) = rv;
67  return APR_SUCCESS;
68 }
69 
71 {
72  apr_ssize_t rv;
73  apr_status_t arv;
74 
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)) {
104  }
105  (*len) = rv;
106  if (rv == 0) {
107  return APR_EOF;
108  }
109  return APR_SUCCESS;
110 }
111 
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)) {
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 
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)) {
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 
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 
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)) {
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 */
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;
324  }
325  }
326 
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;
361  return rv;
362  }
363 
364  nbytes += rv;
365 
366  if (rv < *len) {
367  *len = nbytes;
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) {
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;
400  return rv;
401  }
402  }
403 
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  }
462  apr_status_t arv;
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) {
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 {
574  apr_status_t arv;
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) {
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)) {
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)) {
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 
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))) {
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  */
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)) {
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)) {
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 */
apr_hdtr_t::trailers
struct iovec * trailers
Definition: apr_network_io.h:326
sendto
#define sendto
Definition: apr_arch_os2calls.h:58
apr_hdtr_t::numtrailers
int numtrailers
Definition: apr_network_io.h:328
t
apr_interval_time_t t
Definition: apr_network_io.h:735
APR_INCOMPLETE_READ
#define APR_INCOMPLETE_READ
Definition: apr_network_io.h:92
APR_INCOMPLETE_WRITE
#define APR_INCOMPLETE_WRITE
Definition: apr_network_io.h:113
apr_support.h
APR Support functions.
apr_socket_t::socketdes
int socketdes
Definition: apr_arch_networkio.h:39
APR_TCP_NOPUSH
#define APR_TCP_NOPUSH
Definition: apr_network_io.h:80
sock
apr_socket_t * sock
Definition: apr_network_io.h:403
nvec
const struct iovec apr_size_t nvec
Definition: apr_file_io.h:519
recvfrom
#define recvfrom
Definition: apr_arch_os2calls.h:59
apr_sockaddr_t::sin
struct sockaddr_in sin
Definition: apr_network_io.h:293
apr_sockaddr_vars_set
void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t)
Definition: sockaddr.c:171
apr_hdtr_t
Definition: apr_network_io.h:320
apr_socket_t::type
int type
Definition: apr_arch_networkio.h:40
offset
apr_seek_where_t apr_off_t * offset
Definition: apr_file_io.h:717
apr_socket_sendto
apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, apr_int32_t flags, const char *buf, apr_size_t *len)
Definition: sendrecv.c:112
apr_socket_send
apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, apr_size_t *len)
Definition: sendrecv.c:30
sockaddr
apr_sockaddr_t * sockaddr
Definition: apr_network_io.h:796
len
const char apr_ssize_t int apr_size_t * len
Definition: apr_encode.h:162
apr_socket_recv
apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
Definition: sendrecv.c:70
buf
char * buf
Definition: apr_errno.h:52
APR_OFFSETOF
#define APR_OFFSETOF(s_type, field)
Definition: apr_general.h:109
vec
const struct iovec * vec
Definition: apr_file_io.h:519
apr_sockaddr_t::sa
union apr_sockaddr_t::@1 sa
apr_socket_t::timeout
apr_interval_time_t timeout
Definition: apr_arch_networkio.h:44
apr_socket_t::pool
apr_pool_t * pool
Definition: apr_arch_networkio.h:38
apr_hdtr_t::numheaders
int numheaders
Definition: apr_network_io.h:324
where
apr_seek_where_t where
Definition: apr_file_io.h:717
apr_socket_t
Definition: apr_arch_networkio.h:37
apr_socket_opt_set
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition: sockopt.c:113
apr_file_t
Definition: apr_arch_file_io.h:97
apr_socket_sendv
apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec, apr_int32_t nvec, apr_size_t *len)
Definition: sendrecv.c:194
apr_status_t
int apr_status_t
Definition: apr_errno.h:44
APR_SUCCESS
#define APR_SUCCESS
Definition: apr_errno.h:225
nbytes
void apr_size_t * nbytes
Definition: apr_file_io.h:482
file
const char apr_file_t * file
Definition: apr_file_io.h:851
flags
const char apr_ssize_t int flags
Definition: apr_encode.h:162
apr_sockaddr_t::salen
apr_socklen_t salen
Definition: apr_network_io.h:278
apr_file_t::filedes
int filedes
Definition: apr_arch_file_io.h:99
apr_wait_for_io_or_timeout
apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, int for_read)
writev
#define writev
Definition: apr_arch_os2calls.h:57
apr_sockaddr_t
Definition: apr_network_io.h:266
apr_socket_recvfrom
apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, apr_int32_t flags, char *buf, apr_size_t *len)
Definition: sendrecv.c:146
apr_socket_t::options
apr_int32_t options
Definition: apr_arch_networkio.h:49
apr_hdtr_t::headers
struct iovec * headers
Definition: apr_network_io.h:322
APR_EOF
#define APR_EOF
Definition: apr_errno.h:461