summaryrefslogtreecommitdiff
path: root/network_io
diff options
context:
space:
mode:
authorJim Jagielski <jim@apache.org>2008-05-09 12:47:14 +0000
committerJim Jagielski <jim@apache.org>2008-05-09 12:47:14 +0000
commitdf2ee3b7d0e34746e8492238e07489c7a2750756 (patch)
treeb2227377747c6fddedf7f7dcd3d904b92ad4f5b6 /network_io
parent9da417a512a402047d1eaf5b98d9260943d0c76f (diff)
downloadapr-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.c136
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;
}