httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Greg Ames <grega...@raleigh.ibm.com>
Subject [PATCH] ap_sendfile on Linux gets EINVAL, v2
Date Mon, 17 Jul 2000 21:43:26 GMT
Updated patch, re-based on the current CVS version, incorporating changes due to Jeff T's
review.  Re-tested with mpmt_pthread.  Original problem description:

If TCP_NODELAY is set, ap_sendfile fails on Linux w/EINVAL.  The setsockopt() for TCP_CORK
gets the failure

Index: lib/apr/network_io/unix/sendrecv.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/lib/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.33
diff -u -d -b -r1.33 sendrecv.c
--- sendrecv.c  2000/07/15 16:00:50     1.33
+++ sendrecv.c  2000/07/17 21:19:57
@@ -212,29 +212,76 @@
   */
 
 #if defined(__linux__) && defined(HAVE_WRITEV)
+
+/* TCP_CORK keeps us from sending partial frames when we shouldn't 
+ * however, it is mutually exclusive w/TCP_NODELAY  
+ */
+
+static int os_cork(ap_socket_t *sock)
+{
+    /* Linux only for now */
+
+    int nodelay_off = 0, corkflag = 1, rv, delayflag;
+    socklen_t delaylen = sizeof(delayflag);
+
+    /* XXX it would be cheaper to use an ap_socket_t flag here */
+    rv = getsockopt(sock->socketdes, SOL_TCP, TCP_NODELAY,
+                    (void *) &delayflag, &delaylen);
+    if (rv == 0) {  
+
+        if (delayflag != 0) {
+            /* turn off nodelay temporarily to allow cork */
+            rv = setsockopt(sock->socketdes, SOL_TCP, TCP_NODELAY,
+                            (const void *) &nodelay_off, sizeof(nodelay_off));
+            /* XXX nuke the rv checking once this is proven solid */
+            if (rv < 0) {
+                return rv;    
+            }   
+        } 
+    }
+    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
+                    (const void *) &corkflag, sizeof(corkflag));
+    return rv == 0 ? delayflag : rv;
+}   
+
+static int os_uncork(ap_socket_t *sock, int delayflag)
+{
+    /* Uncork to send queued frames - Linux only for now */
+    
+    int corkflag = 0, rv;
+    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
+                    (const void *) &corkflag, sizeof(corkflag));
+    if (rv == 0) {
+    
+        /* restore TCP_NODELAY to its original setting */
+        rv = setsockopt(sock->socketdes, SOL_TCP, TCP_NODELAY,
+                        (const void *) &delayflag, sizeof(delayflag));
+        }
+    return rv;
+}
+
 ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file,
                        ap_hdtr_t *hdtr, ap_off_t *offset, ap_size_t *len,
                        ap_int32_t flags)
 {
     off_t off = *offset;
-    int corkflag = 1;
-    int rv, nbytes = 0, total_hdrbytes, i;
+    int rv, nbytes = 0, total_hdrbytes, i, delayflag;
     ap_status_t arv;
 
     /* Ignore flags for now. */
     flags = 0;
 
-    /* TCP_CORK keeps us from sending partial frames when we shouldn't */
-    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
-                   (const void *) &corkflag, sizeof(corkflag));
-    if (rv == -1) {
-       *len = 0;
+    if (hdtr->numheaders > 0) {
+        ap_int32_t hdrbytes;
+        
+        /* cork before writing headers */
+        rv = os_cork(sock);
+        if (rv < 0) {
         return errno;
     }
+        delayflag = rv;
 
     /* Now write the headers */
-    if (hdtr->numheaders > 0) {
-        ap_int32_t hdrbytes;
         arv = ap_sendv(sock, hdtr->headers, hdtr->numheaders, &hdrbytes);
         if (arv != APR_SUCCESS) {
            *len = 0;
@@ -311,10 +358,10 @@
         }
     }
 
-    /* Uncork to send queued frames */
-    corkflag = 0;
-    rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK,
-                    (const void *) &corkflag, sizeof(corkflag));
+    if (hdtr->numheaders > 0) {
+        /* if we corked, uncork & restore TCP_NODELAY setting */
+        rv = os_uncork(sock, delayflag);
+    }
 
     (*len) = nbytes;
     return rv < 0 ? errno : APR_SUCCESS;

Mime
View raw message