summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2001-07-25 20:59:29 +0000
committertrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2001-07-25 20:59:29 +0000
commit346dcc0c1e42f9f5c338ec1c83b4553d1f54122c (patch)
tree69c5e5746a81a62037c4c41f47495d3f6c2590c1
parent55193b0c47a780ac0a78072a001f313907893431 (diff)
downloadlibapr-346dcc0c1e42f9f5c338ec1c83b4553d1f54122c.tar.gz
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() git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@62022 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--network_io/unix/sendrecv.c55
1 files changed, 41 insertions, 14 deletions
diff --git a/network_io/unix/sendrecv.c b/network_io/unix/sendrecv.c
index d74c3d6cf..59fc96bc0 100644
--- a/network_io/unix/sendrecv.c
+++ b/network_io/unix/sendrecv.c
@@ -447,25 +447,52 @@ apr_status_t apr_sendfile(apr_socket_t * sock, apr_file_t * file,
}
} 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);
+ }
}
(*len) = nbytes;