trawick 01/07/25 13:59:29
Modified: network_io/unix sendrecv.c
Log:
fix some issues with apr_sendfile() for FreeBSD
1) checking when to call wait_for_io_or_timeout()
it checked errno without checking rv
it required that we already sent bytes (nbytes != 0)
it checked timeout != 0 instead of timeout > 0
2) it didn't retry the sendfile() (or writev()) after
a successful wait_for_io_or_timeout()
Revision Changes Path
1.72 +41 -14 apr/network_io/unix/sendrecv.c
Index: sendrecv.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -r1.71 -r1.72
--- sendrecv.c 2001/07/25 05:27:32 1.71
+++ sendrecv.c 2001/07/25 20:59:29 1.72
@@ -447,24 +447,51 @@
}
} while (rv == -1 && errno == EINTR);
- /* On FreeBSD, it is possible that sendfile will return EAGAIN, but
- * still send some data. This means that we cannot call sendfile
- * and then check for EAGAIN, and then wait and call sendfile again.
- * If we do that, then we are likely to send the first chunk of data
- * twice, once in the first call and once in the second.
- *
- * When we are dealing with a non-blocking or timeout socket, the
- * caller must already be aware that we may not be able to write
- * everything in one call. Therefore, we should return back to
- * the caller with how much we actually sent (as specified from EAGAIN).
- *
- * If we are using a timed write, we will now block until we are clear.
- */
- if (errno == EAGAIN && nbytes && sock->timeout >= 0) {
+ if (rv == -1 &&
+ errno == EAGAIN &&
+ sock->timeout > 0) {
apr_status_t arv = apr_wait_for_io_or_timeout(sock, 0);
if (arv != APR_SUCCESS) {
*len = 0;
return arv;
+ }
+ else {
+ do {
+ if (bytes_to_send) {
+ /* We won't dare call sendfile() if we don't have
+ * header or file bytes to send because bytes_to_send == 0
+ * means send the whole file.
+ */
+ rv = sendfile(file->filedes, /* file to be sent */
+ sock->socketdes, /* socket */
+ *offset, /* where in the file to
start */
+ bytes_to_send, /* number of bytes to send
*/
+ &headerstruct, /* Headers/footers */
+ &nbytes, /* number of bytes written
*/
+ flags); /* undefined, set to 0 */
+ /* FreeBSD's sendfile can return -1/EAGAIN even if it
+ * sent bytes. Sanitize the result so we get normal
EAGAIN
+ * semantics w.r.t. bytes sent.
+ */
+ if (rv == -1 && errno == EAGAIN && nbytes) {
+ rv = 0;
+ }
+ }
+ else {
+ /* just trailer bytes... use writev()
+ */
+ rv = writev(sock->socketdes,
+ hdtr->trailers,
+ hdtr->numtrailers);
+ if (rv > 0) {
+ nbytes = rv;
+ rv = 0;
+ }
+ else {
+ nbytes = 0;
+ }
+ }
+ } while (rv == -1 && errno == EINTR);
}
}