Bug Summary

File:libs/apr/network_io/unix/sendrecv.c
Location:line 289, column 5
Description:Value stored to 'flags' is never read

Annotated Source Code

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_SENDFILE1
21/* This file is needed to allow us access to the apr_file_t internals. */
22#include "apr_arch_file_io.h"
23#endif /* APR_HAS_SENDFILE */
24
25/* osreldate.h is only needed on FreeBSD for sendfile detection */
26#if defined(__FreeBSD__)
27#include <osreldate.h>
28#endif
29
30apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf,
31 apr_size_t *len)
32{
33 apr_ssize_t rv;
34
35 if (sock->options & APR_INCOMPLETE_WRITE8192) {
36 sock->options &= ~APR_INCOMPLETE_WRITE8192;
37 goto do_select;
38 }
39
40 do {
41 rv = write(sock->socketdes, buf, (*len));
42 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
43
44 while (rv == -1 && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
45 && (sock->timeout > 0)) {
46 apr_status_t arv;
47do_select:
48 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
49 if (arv != APR_SUCCESS0) {
50 *len = 0;
51 return arv;
52 }
53 else {
54 do {
55 rv = write(sock->socketdes, buf, (*len));
56 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
57 }
58 }
59 if (rv == -1) {
60 *len = 0;
61 return errno(*__errno_location ());
62 }
63 if ((sock->timeout > 0) && (rv < *len)) {
64 sock->options |= APR_INCOMPLETE_WRITE8192;
65 }
66 (*len) = rv;
67 return APR_SUCCESS0;
68}
69
70apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
71{
72 apr_ssize_t rv;
73 apr_status_t arv;
74
75 if (sock->options & APR_INCOMPLETE_READ4096) {
76 sock->options &= ~APR_INCOMPLETE_READ4096;
77 goto do_select;
78 }
79
80 do {
81 rv = read(sock->socketdes, buf, (*len));
82 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
83
84 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
85 && (sock->timeout > 0)) {
86do_select:
87 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 1);
88 if (arv != APR_SUCCESS0) {
89 *len = 0;
90 return arv;
91 }
92 else {
93 do {
94 rv = read(sock->socketdes, buf, (*len));
95 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
96 }
97 }
98 if (rv == -1) {
99 (*len) = 0;
100 return errno(*__errno_location ());
101 }
102 if ((sock->timeout > 0) && (rv < *len)) {
103 sock->options |= APR_INCOMPLETE_READ4096;
104 }
105 (*len) = rv;
106 if (rv == 0) {
107 return APR_EOF((20000 + 50000) + 14);
108 }
109 return APR_SUCCESS0;
110}
111
112apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where,
113 apr_int32_t flags, const char *buf,
114 apr_size_t *len)
115{
116 apr_ssize_t rv;
117
118 do {
119 rv = sendto(sock->socketdes, buf, (*len), flags,
120 (const struct sockaddr*)&where->sa,
121 where->salen);
122 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
123
124 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
125 && (sock->timeout > 0)) {
126 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
127 if (arv != APR_SUCCESS0) {
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(*__errno_location ()) == EINTR4);
136 }
137 }
138 if (rv == -1) {
139 *len = 0;
140 return errno(*__errno_location ());
141 }
142 *len = rv;
143 return APR_SUCCESS0;
144}
145
146apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock,
147 apr_int32_t flags, char *buf,
148 apr_size_t *len)
149{
150 apr_ssize_t rv;
151
152 from->salen = sizeof(from->sa);
153
154 do {
155 rv = recvfrom(sock->socketdes, buf, (*len), flags,
156 (struct sockaddr*)&from->sa, &from->salen);
157 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
158
159 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
160 && (sock->timeout > 0)) {
161 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 1);
162 if (arv != APR_SUCCESS0) {
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(*__errno_location ()) == EINTR4);
170 }
171 }
172 if (rv == -1) {
173 (*len) = 0;
174 return errno(*__errno_location ());
175 }
176
177 apr_sockaddr_vars_set(from, from->sa.sin.sin_family, ntohs(from->sa.sin.sin_port)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (from->sa.sin.sin_port); if (__builtin_constant_p (__x
)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
);
178
179 (*len) = rv;
180 if (rv == 0 && sock->type == SOCK_STREAMSOCK_STREAM) {
181 return APR_EOF((20000 + 50000) + 14);
182 }
183
184 return APR_SUCCESS0;
185}
186
187apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec,
188 apr_int32_t nvec, apr_size_t *len)
189{
190#ifdef HAVE_WRITEV1
191 apr_ssize_t rv;
192 apr_size_t requested_len = 0;
193 apr_int32_t i;
194
195 for (i = 0; i < nvec; i++) {
196 requested_len += vec[i].iov_len;
197 }
198
199 if (sock->options & APR_INCOMPLETE_WRITE8192) {
200 sock->options &= ~APR_INCOMPLETE_WRITE8192;
201 goto do_select;
202 }
203
204 do {
205 rv = writev(sock->socketdes, vec, nvec);
206 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
207
208 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
209 && (sock->timeout > 0)) {
210 apr_status_t arv;
211do_select:
212 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
213 if (arv != APR_SUCCESS0) {
214 *len = 0;
215 return arv;
216 }
217 else {
218 do {
219 rv = writev(sock->socketdes, vec, nvec);
220 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
221 }
222 }
223 if (rv == -1) {
224 *len = 0;
225 return errno(*__errno_location ());
226 }
227 if ((sock->timeout > 0) && (rv < requested_len)) {
228 sock->options |= APR_INCOMPLETE_WRITE8192;
229 }
230 (*len) = rv;
231 return APR_SUCCESS0;
232#else
233 *len = vec[0].iov_len;
234 return apr_socket_send(sock, vec[0].iov_base, len);
235#endif
236}
237
238#if APR_HAS_SENDFILE1
239
240/* TODO: Verify that all platforms handle the fd the same way,
241 * i.e. that they don't move the file pointer.
242 */
243/* TODO: what should flags be? int_32? */
244
245/* Define a structure to pass in when we have a NULL header value */
246static apr_hdtr_t no_hdtr;
247
248#if defined(__linux__1) && defined(HAVE_WRITEV1)
249
250apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
251 apr_hdtr_t *hdtr, apr_off_t *offset,
252 apr_size_t *len, apr_int32_t flags)
253{
254 int rv, nbytes = 0, total_hdrbytes, i;
255 apr_status_t arv;
256
257#if APR_HAS_LARGE_FILES0 && defined(HAVE_SENDFILE64)
258 apr_off_t off = *offset;
259#define sendfile sendfile64
260
261#elif APR_HAS_LARGE_FILES0 && SIZEOF_OFF_T8 == 4
262 /* 64-bit apr_off_t but no sendfile64(): fail if trying to send
263 * past the 2Gb limit. */
264 off_t off;
265
266 if ((apr_int64_t)*offset + *len > INT_MAX2147483647) {
267 return EINVAL22;
268 }
269
270 off = *offset;
271
272#else
273 off_t off = *offset;
274
275 /* Multiple reports have shown sendfile failing with EINVAL if
276 * passed a >=2Gb count value on some 64-bit kernels. It won't
277 * noticably hurt performance to limit each call to <2Gb at a
278 * time, so avoid that issue here: */
279 if (sizeof(off_t) == 8 && *len > INT_MAX2147483647) {
280 *len = INT_MAX2147483647;
281 }
282#endif
283
284 if (!hdtr) {
285 hdtr = &no_hdtr;
286 }
287
288 /* Ignore flags for now. */
289 flags = 0;
Value stored to 'flags' is never read
290
291 if (hdtr->numheaders > 0) {
292 apr_size_t hdrbytes;
293
294 /* cork before writing headers */
295 rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 1);
296 if (rv != APR_SUCCESS0) {
297 return rv;
298 }
299
300 /* Now write the headers */
301 arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders,
302 &hdrbytes);
303 if (arv != APR_SUCCESS0) {
304 *len = 0;
305 return errno(*__errno_location ());
306 }
307 nbytes += hdrbytes;
308
309 /* If this was a partial write and we aren't doing timeouts,
310 * return now with the partial byte count; this is a non-blocking
311 * socket.
312 */
313 total_hdrbytes = 0;
314 for (i = 0; i < hdtr->numheaders; i++) {
315 total_hdrbytes += hdtr->headers[i].iov_len;
316 }
317 if (hdrbytes < total_hdrbytes) {
318 *len = hdrbytes;
319 return apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 0);
320 }
321 }
322
323 if (sock->options & APR_INCOMPLETE_WRITE8192) {
324 sock->options &= ~APR_INCOMPLETE_WRITE8192;
325 goto do_select;
326 }
327
328 do {
329 rv = sendfile(sock->socketdes, /* socket */
330 file->filedes, /* open file descriptor of the file to be sent */
331 &off, /* where in the file to start */
332 *len); /* number of bytes to send */
333 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
334
335 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
336 && (sock->timeout > 0)) {
337do_select:
338 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
339 if (arv != APR_SUCCESS0) {
340 *len = 0;
341 return arv;
342 }
343 else {
344 do {
345 rv = sendfile(sock->socketdes, /* socket */
346 file->filedes, /* open file descriptor of the file to be sent */
347 &off, /* where in the file to start */
348 *len); /* number of bytes to send */
349 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
350 }
351 }
352
353 if (rv == -1) {
354 *len = nbytes;
355 rv = errno(*__errno_location ());
356 apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 0);
357 return rv;
358 }
359
360 nbytes += rv;
361
362 if (rv < *len) {
363 *len = nbytes;
364 arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 0);
365 if (rv > 0) {
366
367 /* If this was a partial write, return now with the
368 * partial byte count; this is a non-blocking socket.
369 */
370
371 if (sock->timeout > 0) {
372 sock->options |= APR_INCOMPLETE_WRITE8192;
373 }
374 return arv;
375 }
376 else {
377 /* If the file got smaller mid-request, eventually the offset
378 * becomes equal to the new file size and the kernel returns 0.
379 * Make this an error so the caller knows to log something and
380 * exit.
381 */
382 return APR_EOF((20000 + 50000) + 14);
383 }
384 }
385
386 /* Now write the footers */
387 if (hdtr->numtrailers > 0) {
388 apr_size_t trbytes;
389 arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers,
390 &trbytes);
391 nbytes += trbytes;
392 if (arv != APR_SUCCESS0) {
393 *len = nbytes;
394 rv = errno(*__errno_location ());
395 apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 0);
396 return rv;
397 }
398 }
399
400 apr_socket_opt_set(sock, APR_TCP_NOPUSH1024, 0);
401
402 (*len) = nbytes;
403 return rv < 0 ? errno(*__errno_location ()) : APR_SUCCESS0;
404}
405
406#elif defined(DARWIN)
407
408/* OS/X Release 10.5 or greater */
409apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
410 apr_hdtr_t * hdtr, apr_off_t * offset,
411 apr_size_t * len, apr_int32_t flags)
412{
413 apr_off_t nbytes = *len;
414 int rv;
415 struct sf_hdtr headerstruct;
416
417 /* Ignore flags for now. */
418 flags = 0;
419
420 if (!hdtr) {
421 hdtr = &no_hdtr;
422 }
423
424 headerstruct.headers = hdtr->headers;
425 headerstruct.hdr_cnt = hdtr->numheaders;
426 headerstruct.trailers = hdtr->trailers;
427 headerstruct.trl_cnt = hdtr->numtrailers;
428
429 /* BSD can send the headers/footers as part of the system call */
430 do {
431 if (sock->options & APR_INCOMPLETE_WRITE8192) {
432 apr_status_t arv;
433 sock->options &= ~APR_INCOMPLETE_WRITE8192;
434 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
435 if (arv != APR_SUCCESS0) {
436 *len = 0;
437 return arv;
438 }
439 }
440 if (nbytes) {
441 /* We won't dare call sendfile() if we don't have
442 * header or file bytes to send because nbytes == 0
443 * means send the remaining file to EOF.
444 */
445 rv = sendfile(file->filedes, /* file to be sent */
446 sock->socketdes, /* socket */
447 *offset, /* where in the file to start */
448 &nbytes, /* number of bytes to write/written */
449 &headerstruct, /* Headers/footers */
450 flags); /* undefined, set to 0 */
451
452 if (rv == -1) {
453 if (errno(*__errno_location ()) == EAGAIN11) {
454 if (sock->timeout > 0) {
455 sock->options |= APR_INCOMPLETE_WRITE8192;
456 }
457 /* BSD's sendfile can return -1/EAGAIN even if it
458 * sent bytes. Sanitize the result so we get normal EAGAIN
459 * semantics w.r.t. bytes sent.
460 */
461 if (nbytes) {
462 /* normal exit for a big file & non-blocking io */
463 (*len) = nbytes;
464 return APR_SUCCESS0;
465 }
466 }
467 }
468 else { /* rv == 0 (or the kernel is broken) */
469 if (nbytes == 0) {
470 /* Most likely the file got smaller after the stat.
471 * Return an error so the caller can do the Right Thing.
472 */
473 (*len) = nbytes;
474 return APR_EOF((20000 + 50000) + 14);
475 }
476 }
477 }
478 else {
479 /* just trailer bytes... use writev()
480 */
481 rv = writev(sock->socketdes,
482 hdtr->trailers,
483 hdtr->numtrailers);
484 if (rv > 0) {
485 nbytes = rv;
486 rv = 0;
487 }
488 else {
489 nbytes = 0;
490 }
491 }
492 if ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11)
493 && (sock->timeout > 0)) {
494 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
495 if (arv != APR_SUCCESS0) {
496 *len = 0;
497 return arv;
498 }
499 }
500 } while (rv == -1 && (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11));
501
502 (*len) = nbytes;
503 if (rv == -1) {
504 return errno(*__errno_location ());
505 }
506 return APR_SUCCESS0;
507}
508
509#elif defined(__FreeBSD__) || defined(__DragonFly__)
510
511/* Release 3.1 or greater */
512apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
513 apr_hdtr_t * hdtr, apr_off_t * offset,
514 apr_size_t * len, apr_int32_t flags)
515{
516 off_t nbytes = 0;
517 int rv;
518#if defined(__FreeBSD_version) && __FreeBSD_version < 460001
519 int i;
520#endif
521 struct sf_hdtr headerstruct;
522 apr_size_t bytes_to_send = *len;
523
524 /* Ignore flags for now. */
525 flags = 0;
526
527 if (!hdtr) {
528 hdtr = &no_hdtr;
529 }
530
531#if defined(__FreeBSD_version) && __FreeBSD_version < 460001
532 else if (hdtr->numheaders) {
533
534 /* On early versions of FreeBSD sendfile, the number of bytes to send
535 * must include the length of the headers. Don't look at the man page
536 * for this :( Instead, look at the the logic in
537 * src/sys/kern/uipc_syscalls::sendfile().
538 *
539 * This was fixed in the middle of 4.6-STABLE
540 */
541 for (i = 0; i < hdtr->numheaders; i++) {
542 bytes_to_send += hdtr->headers[i].iov_len;
543 }
544 }
545#endif
546
547 headerstruct.headers = hdtr->headers;
548 headerstruct.hdr_cnt = hdtr->numheaders;
549 headerstruct.trailers = hdtr->trailers;
550 headerstruct.trl_cnt = hdtr->numtrailers;
551
552 /* FreeBSD can send the headers/footers as part of the system call */
553 do {
554 if (sock->options & APR_INCOMPLETE_WRITE8192) {
555 apr_status_t arv;
556 sock->options &= ~APR_INCOMPLETE_WRITE8192;
557 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
558 if (arv != APR_SUCCESS0) {
559 *len = 0;
560 return arv;
561 }
562 }
563 if (bytes_to_send) {
564 /* We won't dare call sendfile() if we don't have
565 * header or file bytes to send because bytes_to_send == 0
566 * means send the whole file.
567 */
568 rv = sendfile(file->filedes, /* file to be sent */
569 sock->socketdes, /* socket */
570 *offset, /* where in the file to start */
571 bytes_to_send, /* number of bytes to send */
572 &headerstruct, /* Headers/footers */
573 &nbytes, /* number of bytes written */
574 flags); /* undefined, set to 0 */
575
576 if (rv == -1) {
577 if (errno(*__errno_location ()) == EAGAIN11) {
578 if (sock->timeout > 0) {
579 sock->options |= APR_INCOMPLETE_WRITE8192;
580 }
581 /* FreeBSD's sendfile can return -1/EAGAIN even if it
582 * sent bytes. Sanitize the result so we get normal EAGAIN
583 * semantics w.r.t. bytes sent.
584 */
585 if (nbytes) {
586 /* normal exit for a big file & non-blocking io */
587 (*len) = nbytes;
588 return APR_SUCCESS0;
589 }
590 }
591 }
592 else { /* rv == 0 (or the kernel is broken) */
593 if (nbytes == 0) {
594 /* Most likely the file got smaller after the stat.
595 * Return an error so the caller can do the Right Thing.
596 */
597 (*len) = nbytes;
598 return APR_EOF((20000 + 50000) + 14);
599 }
600 }
601 }
602 else {
603 /* just trailer bytes... use writev()
604 */
605 rv = writev(sock->socketdes,
606 hdtr->trailers,
607 hdtr->numtrailers);
608 if (rv > 0) {
609 nbytes = rv;
610 rv = 0;
611 }
612 else {
613 nbytes = 0;
614 }
615 }
616 if ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11)
617 && (sock->timeout > 0)) {
618 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
619 if (arv != APR_SUCCESS0) {
620 *len = 0;
621 return arv;
622 }
623 }
624 } while (rv == -1 && (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11));
625
626 (*len) = nbytes;
627 if (rv == -1) {
628 return errno(*__errno_location ());
629 }
630 return APR_SUCCESS0;
631}
632
633#elif defined(__APPLE__)
634/*
635 int
636 sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr,
637 int flags);
638*/
639apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
640 apr_hdtr_t * hdtr, apr_off_t * offset,
641 apr_size_t * len, apr_int32_t flags)
642{
643 int rv, i;
644 struct sf_hdtr headerstruct;
645 apr_off_t bytes_to_send = *len;
646
647 /* Ignore flags for now. */
648 flags = 0;
649
650 if (!hdtr) {
651 hdtr = &no_hdtr;
652 }
653 else{
654 if(hdtr->numheaders){
655 for (i = 0; i < hdtr->numheaders; i++) {
656 bytes_to_send += hdtr->headers[i].iov_len;
657 }
658 }
659 else hdtr->headers=NULL((void*)0); //for us having headers pointing to a valid buffer, but numheaders=0 constitues EINVAL..
660 }
661
662 headerstruct.headers = hdtr->headers;
663 headerstruct.hdr_cnt = hdtr->numheaders;
664 headerstruct.trailers = hdtr->trailers;
665 headerstruct.trl_cnt = hdtr->numtrailers;
666
667
668 do {
669 if (sock->options & APR_INCOMPLETE_WRITE8192) {
670 apr_status_t arv;
671 sock->options &= ~APR_INCOMPLETE_WRITE8192;
672 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
673 if (arv != APR_SUCCESS0) {
674 *len = 0;
675 return arv;
676 }
677 }
678 if (bytes_to_send) {
679 /* We won't dare call sendfile() if we don't have
680 * header or file bytes to send because bytes_to_send == 0
681 * means send the whole file.
682 */
683 int lflags = fcntl(sock->socketdes,F_GETFL3,0);
684 lflags &= ~O_NONBLOCK04000;
685 fcntl(sock->socketdes,F_SETFL4,lflags);
686 rv = sendfile(file->filedes, /* file to be sent */
687 sock->socketdes, /* socket */
688 *offset, /* where in the file to start */
689 &bytes_to_send, /* number of bytes to send */
690 &headerstruct, /* Headers/footers */
691 flags); /* undefined, set to 0 */
692 lflags |= O_NONBLOCK04000;
693 fcntl(sock->socketdes,F_SETFL4,lflags);
694 if (rv == -1) {
695 if (errno(*__errno_location ()) == EAGAIN11) {
696 if (sock->timeout > 0) {
697 sock->options |= APR_INCOMPLETE_WRITE8192;
698 }
699 /* FreeBSD's sendfile can return -1/EAGAIN even if it
700 * sent bytes. Sanitize the result so we get normal EAGAIN
701 * semantics w.r.t. bytes sent.
702 */
703 if (bytes_to_send) {
704 /* normal exit for a big file & non-blocking io */
705 (*len) = bytes_to_send;
706 return APR_SUCCESS0;
707 }
708 }
709 }
710 else { /* rv == 0 (or the kernel is broken) */
711 if (bytes_to_send == 0) {
712 /* Most likely the file got smaller after the stat.
713 * Return an error so the caller can do the Right Thing.
714 */
715 (*len) = bytes_to_send;
716 return APR_EOF((20000 + 50000) + 14);
717 }
718 }
719 }
720 else {
721 /* just trailer bytes... use writev()
722 */
723 rv = writev(sock->socketdes,
724 hdtr->trailers,
725 hdtr->numtrailers);
726 if (rv > 0) {
727 bytes_to_send = rv;
728 rv = 0;
729 }
730 else {
731 bytes_to_send = 0;
732 }
733 }
734 if ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11)
735 && (sock->timeout > 0)) {
736 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
737 if (arv != APR_SUCCESS0) {
738 *len = 0;
739 return arv;
740 }
741 }
742 } while (rv == -1 && (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11));
743
744 (*len) = bytes_to_send;
745 if (rv == -1) {
746 return errno(*__errno_location ());
747 }
748 return APR_SUCCESS0;
749}
750
751
752#elif defined(__hpux) || defined(__hpux__)
753
754/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */
755
756/* HP-UX Version 10.30 or greater
757 * (no worries, because we only get here if autoconfiguration found sendfile)
758 */
759
760/* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes,
761 * const struct iovec *hdtrl, int flags);
762 *
763 * nbytes is the number of bytes to send just from the file; as with FreeBSD,
764 * if nbytes == 0, the rest of the file (from offset) is sent
765 */
766
767apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
768 apr_hdtr_t *hdtr, apr_off_t *offset,
769 apr_size_t *len, apr_int32_t flags)
770{
771 int i;
772 apr_ssize_t rc;
773 apr_size_t nbytes = *len, headerlen, trailerlen;
774 struct iovec hdtrarray[2];
775 char *headerbuf, *trailerbuf;
776
777#if APR_HAS_LARGE_FILES0 && defined(HAVE_SENDFILE64)
778 /* later HP-UXes have a sendfile64() */
779#define sendfile sendfile64
780 apr_off_t off = *offset;
781
782#elif APR_HAS_LARGE_FILES0 && SIZEOF_OFF_T8 == 4
783 /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send
784 * past the 2Gb limit */
785 off_t off;
786
787 if ((apr_int64_t)*offset + *len > INT_MAX2147483647) {
788 return EINVAL22;
789 }
790 off = *offset;
791#else
792 apr_off_t off = *offset;
793#endif
794
795 if (!hdtr) {
796 hdtr = &no_hdtr;
797 }
798
799 /* Ignore flags for now. */
800 flags = 0;
801
802 /* HP-UX can only send one header iovec and one footer iovec; try to
803 * only allocate storage to combine input iovecs when we really have to
804 */
805
806 switch(hdtr->numheaders) {
807 case 0:
808 hdtrarray[0].iov_base = NULL((void*)0);
809 hdtrarray[0].iov_len = 0;
810 break;
811 case 1:
812 hdtrarray[0] = hdtr->headers[0];
813 break;
814 default:
815 headerlen = 0;
816 for (i = 0; i < hdtr->numheaders; i++) {
817 headerlen += hdtr->headers[i].iov_len;
818 }
819
820 /* XXX: BUHHH? wow, what a memory leak! */
821 headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen);
822 hdtrarray[0].iov_len = headerlen;
823
824 for (i = 0; i < hdtr->numheaders; i++) {
825 memcpy(headerbuf, hdtr->headers[i].iov_base,
826 hdtr->headers[i].iov_len);
827 headerbuf += hdtr->headers[i].iov_len;
828 }
829 }
830
831 switch(hdtr->numtrailers) {
832 case 0:
833 hdtrarray[1].iov_base = NULL((void*)0);
834 hdtrarray[1].iov_len = 0;
835 break;
836 case 1:
837 hdtrarray[1] = hdtr->trailers[0];
838 break;
839 default:
840 trailerlen = 0;
841 for (i = 0; i < hdtr->numtrailers; i++) {
842 trailerlen += hdtr->trailers[i].iov_len;
843 }
844
845 /* XXX: BUHHH? wow, what a memory leak! */
846 trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen);
847 hdtrarray[1].iov_len = trailerlen;
848
849 for (i = 0; i < hdtr->numtrailers; i++) {
850 memcpy(trailerbuf, hdtr->trailers[i].iov_base,
851 hdtr->trailers[i].iov_len);
852 trailerbuf += hdtr->trailers[i].iov_len;
853 }
854 }
855
856 do {
857 if (nbytes) { /* any bytes to send from the file? */
858 rc = sendfile(sock->socketdes, /* socket */
859 file->filedes, /* file descriptor to send */
860 off, /* where in the file to start */
861 nbytes, /* number of bytes to send from file */
862 hdtrarray, /* Headers/footers */
863 flags); /* undefined, set to 0 */
864 }
865 else { /* we can't call sendfile() with no bytes to send from the file */
866 rc = writev(sock->socketdes, hdtrarray, 2);
867 }
868 } while (rc == -1 && errno(*__errno_location ()) == EINTR4);
869
870 while ((rc == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
871 && (sock->timeout > 0)) {
872 apr_status_t arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
873
874 if (arv != APR_SUCCESS0) {
875 *len = 0;
876 return arv;
877 }
878 else {
879 do {
880 if (nbytes) {
881 rc = sendfile(sock->socketdes, /* socket */
882 file->filedes, /* file descriptor to send */
883 off, /* where in the file to start */
884 nbytes, /* number of bytes to send from file */
885 hdtrarray, /* Headers/footers */
886 flags); /* undefined, set to 0 */
887 }
888 else { /* we can't call sendfile() with no bytes to send from the file */
889 rc = writev(sock->socketdes, hdtrarray, 2);
890 }
891 } while (rc == -1 && errno(*__errno_location ()) == EINTR4);
892 }
893 }
894
895 if (rc == -1) {
896 *len = 0;
897 return errno(*__errno_location ());
898 }
899
900 /* Set len to the number of bytes written */
901 *len = rc;
902 return APR_SUCCESS0;
903}
904#elif defined(_AIX) || defined(__MVS__)
905/* AIX and OS/390 have the same send_file() interface.
906 *
907 * subtle differences:
908 * AIX doesn't update the file ptr but OS/390 does
909 *
910 * availability (correctly determined by autoconf):
911 *
912 * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above
913 * OS/390 - V2R7 and above
914 */
915apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file,
916 apr_hdtr_t * hdtr, apr_off_t * offset,
917 apr_size_t * len, apr_int32_t flags)
918{
919 int i, ptr, rv = 0;
920 void * hbuf=NULL((void*)0), * tbuf=NULL((void*)0);
921 apr_status_t arv;
922 struct sf_parms parms;
923
924 if (!hdtr) {
925 hdtr = &no_hdtr;
926 }
927
928 /* Ignore flags for now. */
929 flags = 0;
930
931 /* word to the wise: by default, AIX stores files sent by send_file()
932 * in the network buffer cache... there are supposedly scenarios
933 * where the most recent copy of the file won't be sent, but I can't
934 * recreate the potential problem, perhaps because of the way we
935 * use send_file()... if you suspect such a problem, try turning
936 * on the SF_SYNC_CACHE flag
937 */
938
939 /* AIX can also send the headers/footers as part of the system call */
940 parms.header_length = 0;
941 if (hdtr && hdtr->numheaders) {
942 if (hdtr->numheaders == 1) {
943 parms.header_data = hdtr->headers[0].iov_base;
944 parms.header_length = hdtr->headers[0].iov_len;
945 }
946 else {
947 for (i = 0; i < hdtr->numheaders; i++) {
948 parms.header_length += hdtr->headers[i].iov_len;
949 }
950#if 0
951 /* Keepalives make apr_palloc a bad idea */
952 hbuf = malloc(parms.header_length);
953#else
954 /* but headers are small, so maybe we can hold on to the
955 * memory for the life of the socket...
956 */
957 hbuf = apr_palloc(sock->pool, parms.header_length);
958#endif
959 ptr = 0;
960 for (i = 0; i < hdtr->numheaders; i++) {
961 memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base,
962 hdtr->headers[i].iov_len);
963 ptr += hdtr->headers[i].iov_len;
964 }
965 parms.header_data = hbuf;
966 }
967 }
968 else parms.header_data = NULL((void*)0);
969 parms.trailer_length = 0;
970 if (hdtr && hdtr->numtrailers) {
971 if (hdtr->numtrailers == 1) {
972 parms.trailer_data = hdtr->trailers[0].iov_base;
973 parms.trailer_length = hdtr->trailers[0].iov_len;
974 }
975 else {
976 for (i = 0; i < hdtr->numtrailers; i++) {
977 parms.trailer_length += hdtr->trailers[i].iov_len;
978 }
979#if 0
980 /* Keepalives make apr_palloc a bad idea */
981 tbuf = malloc(parms.trailer_length);
982#else
983 tbuf = apr_palloc(sock->pool, parms.trailer_length);
984#endif
985 ptr = 0;
986 for (i = 0; i < hdtr->numtrailers; i++) {
987 memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base,
988 hdtr->trailers[i].iov_len);
989 ptr += hdtr->trailers[i].iov_len;
990 }
991 parms.trailer_data = tbuf;
992 }
993 }
994 else {
995 parms.trailer_data = NULL((void*)0);
996 }
997
998 /* Whew! Headers and trailers set up. Now for the file data */
999
1000 parms.file_descriptor = file->filedes;
1001 parms.file_offset = *offset;
1002 parms.file_bytes = *len;
1003
1004 /* O.K. All set up now. Let's go to town */
1005
1006 if (sock->options & APR_INCOMPLETE_WRITE8192) {
1007 sock->options &= ~APR_INCOMPLETE_WRITE8192;
1008 goto do_select;
1009 }
1010
1011 do {
1012 rv = send_file(&(sock->socketdes), /* socket */
1013 &(parms), /* all data */
1014 flags); /* flags */
1015 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
1016
1017 while ((rv == -1) && (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11)
1018 && (sock->timeout > 0)) {
1019do_select:
1020 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
1021 if (arv != APR_SUCCESS0) {
1022 *len = 0;
1023 return arv;
1024 }
1025 else {
1026 do {
1027 rv = send_file(&(sock->socketdes), /* socket */
1028 &(parms), /* all data */
1029 flags); /* flags */
1030 } while (rv == -1 && errno(*__errno_location ()) == EINTR4);
1031 }
1032 }
1033
1034 (*len) = parms.bytes_sent;
1035
1036#if 0
1037 /* Clean up after ourselves */
1038 if(hbuf) free(hbuf);
1039 if(tbuf) free(tbuf);
1040#endif
1041
1042 if (rv == -1) {
1043 return errno(*__errno_location ());
1044 }
1045
1046 if ((sock->timeout > 0)
1047 && (parms.bytes_sent
1048 < (parms.file_bytes + parms.header_length + parms.trailer_length))) {
1049 sock->options |= APR_INCOMPLETE_WRITE8192;
1050 }
1051
1052 return APR_SUCCESS0;
1053}
1054#elif defined(__osf__) && defined (__alpha)
1055/* Tru64's sendfile implementation doesn't work, and we need to make sure that
1056 * we don't use it until it is fixed. If it is used as it is now, it will
1057 * hang the machine and the only way to fix it is a reboot.
1058 */
1059#elif defined(HAVE_SENDFILEV)
1060/* Solaris 8's sendfilev() interface
1061 *
1062 * SFV_FD_SELF refers to our memory space.
1063 *
1064 * Required Sparc patches (or newer):
1065 * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03,
1066 * 108991-13
1067 * Required x86 patches (or newer):
1068 * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04,
1069 * 108992-13
1070 */
1071
1072#if APR_HAS_LARGE_FILES0 && defined(HAVE_SENDFILEV64)
1073#define sendfilevec_t sendfilevec64_t
1074#define sendfilev sendfilev64
1075#endif
1076
1077apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
1078 apr_hdtr_t *hdtr, apr_off_t *offset,
1079 apr_size_t *len, apr_int32_t flags)
1080{
1081 apr_status_t rv, arv;
1082 apr_size_t nbytes;
1083 sendfilevec_t *sfv;
1084 int vecs, curvec, i, repeat;
1085 apr_size_t requested_len = 0;
1086
1087 if (!hdtr) {
1088 hdtr = &no_hdtr;
1089 }
1090
1091 /* Ignore flags for now. */
1092 flags = 0;
1093
1094 /* Calculate how much space we need. */
1095 vecs = hdtr->numheaders + hdtr->numtrailers + 1;
1096 sfv = apr_palloc(sock->pool, sizeof(sendfilevec_t) * vecs);
1097
1098 curvec = 0;
1099
1100 /* Add the headers */
1101 for (i = 0; i < hdtr->numheaders; i++, curvec++) {
1102 sfv[curvec].sfv_fd = SFV_FD_SELF;
1103 sfv[curvec].sfv_flag = 0;
1104 /* Cast to unsigned long to prevent sign extension of the
1105 * pointer value for the LFS case; see PR 39463. */
1106 sfv[curvec].sfv_off = (unsigned long)hdtr->headers[i].iov_base;
1107 sfv[curvec].sfv_len = hdtr->headers[i].iov_len;
1108 requested_len += sfv[curvec].sfv_len;
1109 }
1110
1111 /* If the len is 0, we skip the file. */
1112 if (*len)
1113 {
1114 sfv[curvec].sfv_fd = file->filedes;
1115 sfv[curvec].sfv_flag = 0;
1116 sfv[curvec].sfv_off = *offset;
1117 sfv[curvec].sfv_len = *len;
1118 requested_len += sfv[curvec].sfv_len;
1119
1120 curvec++;
1121 }
1122 else {
1123 vecs--;
1124 }
1125
1126 /* Add the footers */
1127 for (i = 0; i < hdtr->numtrailers; i++, curvec++) {
1128 sfv[curvec].sfv_fd = SFV_FD_SELF;
1129 sfv[curvec].sfv_flag = 0;
1130 sfv[curvec].sfv_off = (unsigned long)hdtr->trailers[i].iov_base;
1131 sfv[curvec].sfv_len = hdtr->trailers[i].iov_len;
1132 requested_len += sfv[curvec].sfv_len;
1133 }
1134
1135 /* If the last write couldn't send all the requested data,
1136 * wait for the socket to become writable before proceeding
1137 */
1138 if (sock->options & APR_INCOMPLETE_WRITE8192) {
1139 sock->options &= ~APR_INCOMPLETE_WRITE8192;
1140 arv = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
1141 if (arv != APR_SUCCESS0) {
1142 *len = 0;
1143 return arv;
1144 }
1145 }
1146
1147 /* Actually do the sendfilev
1148 *
1149 * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock.
1150 *
1151 * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT
1152 * socket (which as far as the OS is concerned is a non-blocking socket),
1153 * we want to retry after waiting for the other side to read the data (as
1154 * determined by poll). Once it is clear to send, we want to retry
1155 * sending the sendfilevec_t once more.
1156 */
1157 arv = 0;
1158 do {
1159 /* Clear out the repeat */
1160 repeat = 0;
1161
1162 /* socket, vecs, number of vecs, bytes written */
1163 rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes);
1164
1165 if (rv == -1 && errno(*__errno_location ()) == EAGAIN11) {
1166 if (nbytes) {
1167 rv = 0;
1168 }
1169 else if (!arv && (sock->timeout > 0)) {
1170 apr_status_t t = apr_wait_for_io_or_timeout(NULL((void*)0), sock, 0);
1171
1172 if (t != APR_SUCCESS0) {
1173 *len = 0;
1174 return t;
1175 }
1176
1177 arv = 1;
1178 repeat = 1;
1179 }
1180 }
1181 } while ((rv == -1 && errno(*__errno_location ()) == EINTR4) || repeat);
1182
1183 if (rv == -1) {
1184 *len = 0;
1185 return errno(*__errno_location ());
1186 }
1187
1188 /* Update how much we sent */
1189 *len = nbytes;
1190 if ((sock->timeout > 0) && (*len < requested_len)) {
1191 sock->options |= APR_INCOMPLETE_WRITE8192;
1192 }
1193 return APR_SUCCESS0;
1194}
1195#else
1196#error APR has detected sendfile on your system, but nobody has written a
1197#error version of it for APR yet. To get past this, either write
1198#error apr_socket_sendfile or change APR_HAS_SENDFILE1 in apr.h to 0.
1199#endif /* __linux__, __FreeBSD__, __DragonFly__, __HPUX__, _AIX, __MVS__,
1200 Tru64/OSF1 */
1201
1202#endif /* APR_HAS_SENDFILE */