File: | libs/apr/network_io/unix/sendrecv.c |
Location: | line 289, column 5 |
Description: | Value stored to 'flags' is never read |
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 | |
30 | apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, |
31 | apr_size_t *len) |
32 | { |
33 | apr_ssize_t rv; |
34 | |
35 | if (sock->options & APR_INCOMPLETE_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; |
47 | do_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 | |
70 | apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) |
71 | { |
72 | apr_ssize_t rv; |
73 | apr_status_t arv; |
74 | |
75 | if (sock->options & APR_INCOMPLETE_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)) { |
86 | do_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 | |
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(*__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 | |
146 | apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, |
147 | apr_int32_t flags, char *buf, |
148 | apr_size_t *len) |
149 | { |
150 | apr_ssize_t rv; |
151 | |
152 | from->salen = sizeof(from->sa); |
153 | |
154 | do { |
155 | rv = recvfrom(sock->socketdes, buf, (*len), flags, |
156 | (struct sockaddr*)&from->sa, &from->salen); |
157 | } while (rv == -1 && errno(*__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 | |
187 | apr_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; |
211 | do_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 */ |
246 | static apr_hdtr_t no_hdtr; |
247 | |
248 | #if defined(__linux__1) && defined(HAVE_WRITEV1) |
249 | |
250 | apr_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)) { |
337 | do_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 */ |
409 | apr_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 */ |
512 | apr_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 | */ |
639 | apr_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 | |
767 | apr_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 | */ |
915 | apr_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)) { |
1019 | do_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 | |
1077 | apr_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 */ |