diff options
author | Jim Jagielski <jim@apache.org> | 2008-05-09 12:47:14 +0000 |
---|---|---|
committer | Jim Jagielski <jim@apache.org> | 2008-05-09 12:47:14 +0000 |
commit | df2ee3b7d0e34746e8492238e07489c7a2750756 (patch) | |
tree | b2227377747c6fddedf7f7dcd3d904b92ad4f5b6 /network_io | |
parent | 9da417a512a402047d1eaf5b98d9260943d0c76f (diff) | |
download | apr-df2ee3b7d0e34746e8492238e07489c7a2750756.tar.gz |
Restructure Darwin's sendfile impl again. Instead of writev(),
go ahead and use apr_socket_sendv(), which handles things
much more cleanly, keeping the sendfile() stuff nicely
contained. Yes, this is similar to how the Linux impl
does it :)
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@654788 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'network_io')
-rw-r--r-- | network_io/unix/sendrecv.c | 136 |
1 files changed, 70 insertions, 66 deletions
diff --git a/network_io/unix/sendrecv.c b/network_io/unix/sendrecv.c index 79ec5c6e0..8396e7de7 100644 --- a/network_io/unix/sendrecv.c +++ b/network_io/unix/sendrecv.c @@ -412,9 +412,9 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, { apr_off_t nbytes = 0; apr_off_t bytes_to_send = *len; - apr_size_t header_bytes_written = 0; + apr_off_t bytes_sent = 0; + apr_status_t arv; int rv = 0; - int sent_headers = 0; /* Ignore flags for now. */ flags = 0; @@ -425,8 +425,31 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, /* OS X can send the headers/footers as part of the system call, * but how it counts bytes isn't documented properly. We use - * writev() instead. + * apr_socket_sendv() instead. */ + if (hdtr->numheaders > 0) { + apr_size_t hbytes; + int i; + + /* Now write the headers */ + arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, + &hbytes); + if (arv != APR_SUCCESS) { + *len = 0; + return errno; + } + bytes_sent = hbytes; + + hbytes = 0; + for (i = 0; i < hdtr->numheaders; i++) { + hbytes += hdtr->headers[i].iov_len; + } + if (bytes_sent < hbytes) { + *len = bytes_sent; + return APR_SUCCESS; + } + } + do { if (sock->options & APR_INCOMPLETE_WRITE) { apr_status_t arv; @@ -438,72 +461,40 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, } } - if (!sent_headers) { - if (hdtr->numheaders) { - rv = writev(sock->socketdes, - hdtr->headers, - hdtr->numheaders); - if (rv > 0) { - header_bytes_written = rv; - sent_headers = 1; - rv = 0; - } - } - else { - sent_headers = 1; - } - } - - if (bytes_to_send && sent_headers) { - /* We won't dare call sendfile() if we don't have - * header or file bytes to send because nbytes == 0 - * means send the remaining file to EOF. - */ - nbytes = bytes_to_send; - rv = sendfile(file->filedes, /* file to be sent */ - sock->socketdes, /* socket */ - *offset, /* where in the file to start */ - &nbytes, /* number of bytes to write/written */ - NULL, /* Headers/footers */ - flags); /* undefined, set to 0 */ - - bytes_to_send -= nbytes; - if (rv == -1) { - if (errno == EAGAIN) { - if (sock->timeout > 0) { - sock->options |= APR_INCOMPLETE_WRITE; - } - /* BSD'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. - */ - else if (nbytes) { - /* normal exit for a big file & non-blocking io */ - (*len) = nbytes + header_bytes_written; - return APR_SUCCESS; - } + nbytes = bytes_to_send; + rv = sendfile(file->filedes, /* file to be sent */ + sock->socketdes, /* socket */ + *offset, /* where in the file to start */ + &nbytes, /* number of bytes to write/written */ + NULL, /* Headers/footers */ + flags); /* undefined, set to 0 */ + + bytes_sent += nbytes; + bytes_to_send -= nbytes; + (*offset) += nbytes; + if (rv == -1) { + if (errno == EAGAIN) { + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; } - } - else { /* rv == 0 (or the kernel is broken) */ - if (nbytes == 0) { - /* Most likely the file got smaller after the stat. - * Return an error so the caller can do the Right Thing. - */ - (*len) = nbytes + header_bytes_written; - return APR_EOF; + /* BSD'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. + */ + else if (nbytes) { + /* normal exit for a big file & non-blocking io */ + (*len) = bytes_sent; + return APR_SUCCESS; } } } - - if (sent_headers && !bytes_to_send) { - /* just trailer bytes... use writev() - */ - rv = writev(sock->socketdes, - hdtr->trailers, - hdtr->numtrailers); - if (rv > 0) { - nbytes += rv; - rv = 0; + else { /* rv == 0 (or the kernel is broken) */ + if (nbytes == 0) { + /* Most likely the file got smaller after the stat. + * Return an error so the caller can do the Right Thing. + */ + (*len) = bytes_sent; + return APR_EOF; } } @@ -512,7 +503,20 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, } } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); - (*len) = nbytes + header_bytes_written; + /* Now write the footers */ + if (hdtr->numtrailers > 0) { + apr_size_t tbytes; + arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, + &tbytes); + bytes_sent += tbytes; + if (arv != APR_SUCCESS) { + *len = bytes_sent; + rv = errno; + return rv; + } + } + + (*len) = bytes_sent; if (rv == -1) { return errno; } |