diff options
author | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2001-07-25 20:59:29 +0000 |
---|---|---|
committer | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2001-07-25 20:59:29 +0000 |
commit | 346dcc0c1e42f9f5c338ec1c83b4553d1f54122c (patch) | |
tree | 69c5e5746a81a62037c4c41f47495d3f6c2590c1 | |
parent | 55193b0c47a780ac0a78072a001f313907893431 (diff) | |
download | libapr-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.c | 55 |
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; |