Folks,

  Please review the attached patch that eliminates the rather nasty allocations
that can occur in two situations.  One is in apr_sendv() when we have more than
50 items, now simply allocate the vectors on the stack [very portable across
win32, from vc5 onwards.]  The other simply allocates a static buffer for
the apr_sendfile headers and trailers vector concatination, and when we
exceed it, we simply sendv out the header or trailer as appropriate.

  If I hear no objections I'll commit in a day or two.

  Final question.  We 'devolve' to 64kb per sendfile.  There is a comment in 
there
about exceeding the timeout.  What on earth does unix do so special that it 
isn't
a problem over on that side?  A cluestick across my knuckles would be 
appreciated
before I even think about attacking that code.

Bill
Index: network_io/win32/sendrecv.c
===================================================================
RCS file: /home/cvs/apr/network_io/win32/sendrecv.c,v
retrieving revision 1.57
diff -u -r1.57 sendrecv.c
--- network_io/win32/sendrecv.c 6 Aug 2002 06:50:17 -0000       1.57
+++ network_io/win32/sendrecv.c 6 Aug 2002 08:22:10 -0000
@@ -71,7 +71,6 @@
  * bytes.
  */
 #define MAX_SEGMENT_SIZE 65536
-#define WSABUF_ON_STACK 50
 
 APR_DECLARE(apr_status_t) apr_send(apr_socket_t *sock, const char *buf,
                                    apr_size_t *len)
@@ -138,26 +137,24 @@
     apr_ssize_t rv;
     int i;
     DWORD dwBytes = 0;
-    WSABUF wsabuf[WSABUF_ON_STACK];
+    WSABUF *wsabuf = _alloca(sizeof(WSABUF) * nvec);
     LPWSABUF pWsaBuf = wsabuf;
 
-    if (nvec > WSABUF_ON_STACK) {
-        pWsaBuf = (LPWSABUF) malloc(sizeof(WSABUF) * nvec);
-        if (!pWsaBuf)
-            return APR_ENOMEM;
-    }
+    if (!wsabuf)
+        return APR_ENOMEM;
+
     for (i = 0; i < nvec; i++) {
-        pWsaBuf[i].buf = vec[i].iov_base;
-        pWsaBuf[i].len = vec[i].iov_len;
+        wsabuf[i].buf = vec[i].iov_base;
+        wsabuf[i].len = vec[i].iov_len;
     }
 #ifndef _WIN32_WCE
-    rv = WSASend(sock->socketdes, pWsaBuf, nvec, &dwBytes, 0, NULL, NULL);
+    rv = WSASend(sock->socketdes, wsabuf, nvec, &dwBytes, 0, NULL, NULL);
     if (rv == SOCKET_ERROR) {
         rc = apr_get_netos_error();
     }
 #else
     for (i = 0; i < nvec; i++) {
-        rv = send(sock->socketdes, pWsaBuf[i].buf, pWsaBuf[i].len, 0);
+        rv = send(sock->socketdes, wsabuf[i].buf, wsabuf[i].len, 0);
         if (rv == SOCKET_ERROR) {
             rc = apr_get_netos_error();
             break;
@@ -165,9 +162,6 @@
         dwBytes += rv;
     }
 #endif
-    if (nvec > WSABUF_ON_STACK) 
-        free(pWsaBuf);
-
     *nbytes = dwBytes;
     return rc;
 }
@@ -213,12 +207,12 @@
 }
 
 
-static void collapse_iovec(char **buf, int *len, struct iovec *iovec, int 
numvec, apr_pool_t *p)
+static apr_status_t collapse_iovec(char **off, apr_size_t *len, 
+                                   struct iovec *iovec, int numvec, 
+                                   char *buf, apr_size_t buflen)
 {
-    int ptr = 0;
-
     if (numvec == 1) {
-        *buf = iovec[0].iov_base;
+        *off = iovec[0].iov_base;
         *len = iovec[0].iov_len;
     }
     else {
@@ -227,13 +221,19 @@
             *len += iovec[i].iov_len;
         }
 
-        *buf = apr_palloc(p, *len); /* Should this be a malloc? */
+        if (*len > buflen) {
+            *len = 0;
+            return APR_INCOMPLETE;
+        }
+
+        *off = buf;
 
         for (i = 0; i < numvec; i++) {
-            memcpy((char*)*buf + ptr, iovec[i].iov_base, iovec[i].iov_len);
-            ptr += iovec[i].iov_len;
+            memcpy(buf, iovec[i].iov_base, iovec[i].iov_len);
+            buf += iovec[i].iov_len;
         }
     }
+    return APR_SUCCESS;
 }
 
 
@@ -274,7 +274,9 @@
     int ptr = 0;
     int bytes_to_send;   /* Bytes to send out of the file (not including 
headers) */
     int disconnected = 0;
+    int sendv_trailers = 0;
     HANDLE wait_event;
+    char hdtrbuf[4096];
 
     if (apr_os_level < APR_WIN_NT) {
         return APR_ENOTIMPL;
@@ -313,8 +315,18 @@
     /* Collapse the headers into a single buffer */
     if (hdtr && hdtr->numheaders) {
         ptfb = &tfb;
-        collapse_iovec((char **)&ptfb->Head, &ptfb->HeadLength, hdtr->headers, 
-                       hdtr->numheaders, sock->cntxt);
+        nbytes = 0;
+        rv = collapse_iovec((char **)&ptfb->Head, &ptfb->HeadLength, 
+                            hdtr->headers, hdtr->numheaders, 
+                            hdtrbuf, sizeof(hdtrbuf));
+        /* If not enough buffer, punt to sendv */
+        if (rv == APR_INCOMPLETE) {
+            rv = apr_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes);
+            if (rv != APR_SUCCESS)
+                return rv;
+            *len += nbytes;
+            ptfb = NULL;
+        }
     }
 
     while (bytes_to_send) {
@@ -327,11 +339,18 @@
             /* Collapse the trailers into a single buffer */
             if (hdtr && hdtr->numtrailers) {
                 ptfb = &tfb;
-                collapse_iovec((char**) &ptfb->Tail, &ptfb->TailLength, 
-                               hdtr->trailers, hdtr->numtrailers, sock->cntxt);
+                rv = collapse_iovec((char**) &ptfb->Tail, &ptfb->TailLength,
+                                    hdtr->trailers, hdtr->numtrailers,
+                                    hdtrbuf + ptfb->HeadLength,
+                                    sizeof(hdtrbuf) - ptfb->HeadLength);
+                if (rv == APR_INCOMPLETE) {
+                    /* If not enough buffer, punt to sendv, later */
+                    sendv_trailers = 1;
+                }
             }
             /* Disconnect the socket after last send */
-            if (flags & APR_SENDFILE_DISCONNECT_SOCKET) {
+            if ((flags & APR_SENDFILE_DISCONNECT_SOCKET)
+                    && !sendv_trailers) {
                 dwFlags |= TF_REUSE_SOCKET;
                 dwFlags |= TF_DISCONNECT;
                 disconnected = 1;
@@ -405,11 +424,19 @@
     }
 
     if (status == APR_SUCCESS) {
+        if (sendv_trailers) {
+            rv = apr_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes);
+            if (rv != APR_SUCCESS)
+                return rv;
+            *len += nbytes;
+        }
+
+    
         /* Mark the socket as disconnected, but do not close it.
          * Note: The application must have stored the socket prior to making
          * the call to apr_sendfile in order to either reuse it or close it.
          */
-        if (flags & APR_SENDFILE_DISCONNECT_SOCKET) {
+        if (disconnected) {
             sock->disconnected = 1;
             sock->socketdes = INVALID_SOCKET;
         }

Reply via email to