Ok, here's a patch for trunk that works with all test cases. I've put in
most of the changes from wrowe's patch at
http://people.apache.org/~wrowe/working.patch as well.

>From what I can gather on the OS X man page (yay weasel-words! now you
can't hold me accountable if I'm wrong), writev() will either send
everything and return the number of bytes sent, or send nothing, return
-1, and set errno. I guess we won't have to deal with incomplete writes
for the headers and trailers.

The only problems I see now are that the code is kind of ugly and
non-blocking I/O sticks in the loop instead of returning right away.

Geoff
Index: sendrecv.c
===================================================================
--- sendrecv.c  (revision 651698)
+++ sendrecv.c  (working copy)
@@ -413,7 +413,8 @@
     apr_off_t nbytes = 0;
     apr_off_t bytes_to_send = *len;
     apr_size_t header_bytes_written = 0;
-    int rv;
+    int rv = 0;
+    int sent_headers = 0;
 
     /* Ignore flags for now. */
     flags = 0;
@@ -436,17 +437,24 @@
                 return arv;
             }
         }
-        
-        if (hdtr->numheaders) {
-            rv = writev(sock->socketdes,
-                        hdtr->headers,
-                        hdtr->numheaders);
-            if (rv > 0) {
-                header_bytes_written = rv;
-                rv = 0;
+
+        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;
+            }
         }
-        else if (bytes_to_send) {
+
+        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.
@@ -464,12 +472,13 @@
                 if (errno == EAGAIN) {
                     if (sock->timeout > 0) {
                         sock->options |= APR_INCOMPLETE_WRITE;
+                        rv = 0;
                     }
                     /* 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.
                      */
-                    if (nbytes) {
+                    else if (nbytes) {
                         /* normal exit for a big file & non-blocking io */
                         (*len) = nbytes + header_bytes_written;
                         return APR_SUCCESS;
@@ -486,27 +495,21 @@
                 }
             }
         }
-        else {
+
+        if (sent_headers && !bytes_to_send) {
             /* just trailer bytes... use writev()
              */
             rv = writev(sock->socketdes,
                         hdtr->trailers,
                         hdtr->numtrailers);
             if (rv > 0) {
-                nbytes = rv;
+                nbytes += rv;
                 rv = 0;
             }
-            else {
-                nbytes = 0;
-            }
         }
-        if ((rv == -1) && (errno == EAGAIN) 
-                       && (sock->timeout > 0)) {
-            apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
-            if (arv != APR_SUCCESS) {
-                *len = 0;
-                return arv;
-            }
+
+        if ((rv == -1) && (errno == EAGAIN) && (sock->timeout > 0)) {
+            sock->options |= APR_INCOMPLETE_WRITE;
         }
     } while (rv == -1 && (errno == EINTR || errno == EAGAIN));
 

Reply via email to