diff src/os/win32/ngx_wsasend_chain.c @ 461:a88a3e4e158f release-0.1.5

nginx-0.1.5-RELEASE import *) Bugfix: on Solaris and Linux there may be too many "recvmsg() returned not enough data" alerts. *) Bugfix: there were the "writev() failed (22: Invalid argument)" errors on Solaris in proxy mode without sendfile. On other platforms that do not support sendfile at all the process got caught in an endless loop. *) Bugfix: segmentation fault on Solaris in proxy mode and using sendfile. *) Bugfix: segmentation fault on Solaris. *) Bugfix: on-line upgrade did not work on Linux. *) Bugfix: the ngx_http_autoindex_module module did not escape the spaces, the quotes, and the percent signs in the directory listing. *) Change: the decrease of the copy operations. *) Feature: the userid_p3p directive.
author Igor Sysoev <igor@sysoev.ru>
date Thu, 11 Nov 2004 14:07:14 +0000
parents 42d11f017717
children 8e8f3af115b5
line wrap: on
line diff
--- a/src/os/win32/ngx_wsasend_chain.c
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -9,17 +9,21 @@
 #include <ngx_event.h>
 
 
+#define NGX_WSABUFS  8
+
+
 ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in,
                                off_t limit)
 {
     int           rc;
     u_char       *prev;
-    size_t        size;
-    u_long        sent;
-    LPWSABUF      wsabuf;
+    u_long        size, sent, send, sprev;
+    ngx_uint_t    complete;
     ngx_err_t     err;
     ngx_event_t  *wev;
-    ngx_array_t   wsabufs;
+    ngx_array_t   vec;
+    LPWSABUF      wsabuf;
+    WSABUF        wsabufs[NGX_WSABUFS];
     ngx_chain_t  *cl;
 
     wev = c->write;
@@ -28,80 +32,119 @@ ngx_chain_t *ngx_wsasend_chain(ngx_conne
         return in;
     }
 
+    send = 0;
+    complete = 0;
+
     /*
      * WSABUFs must be 4-byte aligned otherwise
      * WSASend() will return undocumented WSAEINVAL error.
      */
 
-    ngx_init_array(wsabufs, c->pool, 10, sizeof(WSABUF), NGX_CHAIN_ERROR);
-
-    prev = NULL;
-    wsabuf = NULL;
-
-    /* create the WSABUF and coalesce the neighbouring bufs */
-
-    for (cl = in; cl; cl = cl->next) {
-
-        if (prev == cl->buf->pos) {
-            wsabuf->len += cl->buf->last - cl->buf->pos;
-            prev = cl->buf->last;
+    vec.elts = wsabufs;
+    vec.size = sizeof(WSABUF);
+    vec.nalloc = NGX_WSABUFS; 
+    vec.pool = c->pool;
 
-        } else {
-            ngx_test_null(wsabuf, ngx_push_array(&wsabufs), NGX_CHAIN_ERROR);
-            wsabuf->buf = (char *) cl->buf->pos;
-            wsabuf->len = cl->buf->last - cl->buf->pos;
-            prev = cl->buf->last;
-        }
-    }
+    for ( ;; ) {
+        prev = NULL;
+        wsabuf = NULL;
+        sprev = send;
 
-    rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, NULL, NULL);
+        vec.nelts = 0;
 
-    if (rc == -1) {
-        err = ngx_errno;
+        /* create the WSABUF and coalesce the neighbouring bufs */
 
-        if (err == WSAEWOULDBLOCK) {
-            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
-                           "WSASend() not ready");
-            wev->ready = 0;
-            return in;
+        for (cl = in;
+             cl && vec.nelts < ngx_max_wsabufs && send < limit;
+             cl = cl->next)
+        {
+            if (ngx_buf_special(cl->buf)) {
+                continue;
+            }
 
-        } else {
-            wev->error = 1;
-            ngx_connection_error(c, err, "WSASend() failed");
-            return NGX_CHAIN_ERROR;
-        }
-    }
+            size = cl->buf->last - cl->buf->pos;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "WSASend: %d", sent);
+            if (send + size > limit) {
+                size = (u_long) (limit - send);
+            }
 
-    c->sent += sent;
-
-    for (cl = in; cl && sent > 0; cl = cl->next) {
+            if (prev == cl->buf->pos) {
+                wsabuf->len += cl->buf->last - cl->buf->pos;
 
-        size = cl->buf->last - cl->buf->pos;
+            } else {
+                if (!(wsabuf = ngx_array_push(&vec))) {
+                    return NGX_CHAIN_ERROR;
+                }
 
-        if (sent >= size) {
-            sent -= size;
-
-            if (ngx_buf_in_memory(cl->buf)) {
-                cl->buf->pos = cl->buf->last;
+                wsabuf->buf = (char *) cl->buf->pos;
+                wsabuf->len = cl->buf->last - cl->buf->pos;
             }
 
-            continue;
+            prev = cl->buf->last;
+            send += size;
         }
 
-        if (ngx_buf_in_memory(cl->buf)) {
-            cl->buf->pos += sent;
+        sent = 0;
+
+        rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, NULL, NULL);
+
+        if (rc == -1) {
+            err = ngx_errno;
+
+            if (err == WSAEWOULDBLOCK) {
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "WSASend() not ready");
+
+            } else {
+                wev->error = 1;
+                ngx_connection_error(c, err, "WSASend() failed");
+                return NGX_CHAIN_ERROR;
+            }
+        }
+
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "WSASend: fd:%d, s:%ul", c->fd, sent);
+
+        if (send - sprev == sent) {
+            complete = 1;
         }
 
-        break;
-    }
+        c->sent += sent;
+
+        for (cl = in; cl && sent > 0; cl = cl->next) {
+            if (ngx_buf_special(cl->buf)) {
+                continue;
+            }
+
+            if (sent == 0) {
+                break;
+            }
+
+            size = cl->buf->last - cl->buf->pos;
+
+            if (sent >= size) {
+                sent -= size;
+                cl->buf->pos = cl->buf->last;
 
-    if (cl) {
-        wev->ready = 0;
+                continue;
+            }
+
+            cl->buf->pos += sent;
+
+            break;
+        }
+
+        if (!complete) {
+            wev->ready = 0;
+            return cl;
+        }
+
+        if (send >= limit || cl == NULL) {
+            return cl;
+        }
+
+        in = cl;
     }
-
-    return cl;
 }
 
 
@@ -111,13 +154,14 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
     int               rc;
     u_char           *prev;
     size_t            size;
-    u_long            sent;
+    u_long            send, sent;
     LPWSABUF          wsabuf;
     ngx_err_t         err;
     ngx_event_t      *wev;
-    ngx_array_t       wsabufs;
+    ngx_array_t       vec;
     ngx_chain_t      *cl;
     LPWSAOVERLAPPED   ovlp;
+    WSABUF            wsabufs[NGX_WSABUFS];
 
     wev = c->write;
 
@@ -125,6 +169,9 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
         return in;
     }
 
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "wev->complete: %d", wev->complete);
+
     if (!wev->complete) {
 
         /* post the overlapped WSASend() */
@@ -134,32 +181,52 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
          * WSASend() will return undocumented WSAEINVAL error.
          */
 
-        ngx_init_array(wsabufs, c->pool, 10, sizeof(WSABUF), NGX_CHAIN_ERROR);
+        vec.elts = wsabufs;
+        vec.nelts = 0;
+        vec.size = sizeof(WSABUF);
+        vec.nalloc = NGX_WSABUFS; 
+        vec.pool = c->pool;
 
+        send = 0;
         prev = NULL;
         wsabuf = NULL;
  
         /* create the WSABUF and coalesce the neighbouring bufs */
 
-        for (cl = in; cl; cl = cl->next) {
+        for (cl = in;
+             cl && vec.nelts < ngx_max_wsabufs && send < limit;
+             cl = cl->next)
+        {
+            if (ngx_buf_special(cl->buf)) {
+                continue;
+            }
+
+            size = cl->buf->last - cl->buf->pos;
+
+            if (send + size > limit) {
+                size = (u_long) (limit - send);
+            }
 
             if (prev == cl->buf->pos) {
                 wsabuf->len += cl->buf->last - cl->buf->pos;
-                prev = cl->buf->last;
- 
+
             } else {
-                ngx_test_null(wsabuf, ngx_push_array(&wsabufs),
-                              NGX_CHAIN_ERROR);
+                if (!(wsabuf = ngx_array_push(&vec))) {
+                    return NGX_CHAIN_ERROR;
+                }
+
                 wsabuf->buf = (char *) cl->buf->pos;
                 wsabuf->len = cl->buf->last - cl->buf->pos;
-                prev = cl->buf->last;
             }
+
+            prev = cl->buf->last;
+            send += size;
         }
 
         ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
         ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
  
-        rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, ovlp, NULL);
+        rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, ovlp, NULL);
 
         wev->complete = 0;
 
@@ -167,6 +234,8 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
             err = ngx_errno;
 
             if (err == WSA_IO_PENDING) {
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+                               "WSASend() posted");
                 wev->active = 1;
                 return in;
 
@@ -188,6 +257,9 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
             return in;
         }
 
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "WSASend: fd:%d, s:%ul", c->fd, sent);
+
     } else {
 
         /* the overlapped WSASend() complete */
@@ -214,27 +286,30 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
         }
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "WSASend: %d", sent);
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "WSASend ovlp: fd:%d, s:%ul", c->fd, sent);
 
     c->sent += sent;
 
     for (cl = in; cl && sent > 0; cl = cl->next) {
+        if (ngx_buf_special(cl->buf)) {
+            continue;
+        }
+
+        if (sent == 0) {
+            break;
+        }
 
         size = cl->buf->last - cl->buf->pos;
 
         if (sent >= size) {
             sent -= size;
-
-            if (ngx_buf_in_memory(cl->buf)) {
-                cl->buf->pos = cl->buf->last;
-            }
+            cl->buf->pos = cl->buf->last;
 
             continue;
         }
 
-        if (ngx_buf_in_memory(cl->buf)) {
-            cl->buf->pos += sent;
-        }
+        cl->buf->pos += sent;
 
         break;
     }