changeset 184:1bf718ce0dde

nginx-0.0.1-2003-11-14-10:20:34 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 14 Nov 2003 07:20:34 +0000
parents 4c698194c56d
children d5f50cefc322
files src/event/modules/ngx_iocp_module.c src/http/ngx_http_cache.c src/os/unix/ngx_aio_read.c src/os/unix/ngx_files.h src/os/unix/ngx_os.h src/os/unix/ngx_recv.c src/os/unix/ngx_unix_init.c src/os/unix/ngx_writev_chain.c src/os/win32/ngx_files.c src/os/win32/ngx_files.h src/os/win32/ngx_os.h src/os/win32/ngx_os_init.h src/os/win32/ngx_recv.c src/os/win32/ngx_win32_init.c src/os/win32/ngx_wsarecv.c src/os/win32/ngx_wsasend_chain.c
diffstat 16 files changed, 593 insertions(+), 229 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/modules/ngx_iocp_module.c
+++ b/src/event/modules/ngx_iocp_module.c
@@ -77,6 +77,15 @@ ngx_module_t  ngx_iocp_module = {
 };
 
 
+ngx_os_io_t ngx_iocp_io = {
+    ngx_overlapped_wsarecv,
+    NULL,
+    NULL,
+    ngx_wsasend_chain,
+    0
+};
+
+
 static HANDLE  iocp;
 
 
@@ -225,6 +234,7 @@ ngx_log_debug(log, "iocp ev: %08x" _ ev)
 
         switch (key) {
         case NGX_IOCP_IO:
+            ev->complete = 1;
             ev->ready = 1;
             break;
 
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -140,9 +140,7 @@ int ngx_http_cache_update_file(ngx_http_
     retry = 0;
 
     for ( ;; ) {
-        if (ngx_rename_file(temp_file->data, ctx->file.name.data)
-                                                             != NGX_FILE_ERROR)
-        {
+        if (ngx_rename_file(temp_file, (&ctx->file.name), r->pool) == NGX_OK) {
             return NGX_OK;
         }
 
--- a/src/os/unix/ngx_aio_read.c
+++ b/src/os/unix/ngx_aio_read.c
@@ -25,12 +25,12 @@ ssize_t ngx_aio_read(ngx_connection_t *c
     rev = c->read;
 
     if (!rev->ready) {
-        ngx_log_error(NGX_LOG_ALERT, rev->log, 0, "SECOND AIO POST");
+        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "SECOND AIO POST");
         return NGX_AGAIN;
     }
 
-    ngx_log_debug(rev->log, "rev->complete: %d" _ rev->complete);
-    ngx_log_debug(rev->log, "aio size: %d" _ size);
+    ngx_log_debug(c->log, "rev->complete: %d" _ rev->complete);
+    ngx_log_debug(c->log, "aio size: %d" _ size);
 
     if (!rev->complete) {
         ngx_memzero(&rev->aiocb, sizeof(struct aiocb));
@@ -52,7 +52,7 @@ ssize_t ngx_aio_read(ngx_connection_t *c
             return NGX_ERROR;
         }
 
-        ngx_log_debug(rev->log, "aio_read: #%d OK" _ c->fd);
+        ngx_log_debug(c->log, "aio_read: #%d OK" _ c->fd);
 
         rev->active = 1;
         rev->ready = 0;
@@ -62,7 +62,7 @@ ssize_t ngx_aio_read(ngx_connection_t *c
 
     n = aio_error(&rev->aiocb);
     if (n == -1) {
-        ngx_log_error(NGX_LOG_ALERT, rev->log, ngx_errno, "aio_error() failed");
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "aio_error() failed");
         rev->error = 1;
         return NGX_ERROR;
     }
@@ -70,14 +70,14 @@ ssize_t ngx_aio_read(ngx_connection_t *c
     if (n != 0) {
         if (n == NGX_EINPROGRESS) {
             if (rev->ready) {
-                ngx_log_error(NGX_LOG_ALERT, rev->log, n,
+                ngx_log_error(NGX_LOG_ALERT, c->log, n,
                               "aio_read() still in progress");
                 rev->ready = 0;
             }
             return NGX_AGAIN;
         }
 
-        ngx_log_error(NGX_LOG_CRIT, rev->log, n, "aio_read() failed");
+        ngx_log_error(NGX_LOG_CRIT, c->log, n, "aio_read() failed");
         rev->error = 1;
         rev->ready = 0;
         return NGX_ERROR;
@@ -85,7 +85,7 @@ ssize_t ngx_aio_read(ngx_connection_t *c
 
     n = aio_return(&rev->aiocb);
     if (n == -1) {
-        ngx_log_error(NGX_LOG_ALERT, rev->log, ngx_errno,
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                       "aio_return() failed");
 
         rev->error = 1;
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -45,7 +45,7 @@ ssize_t ngx_write_chain_to_file(ngx_file
                                 off_t offset, ngx_pool_t *pool);
 
 
-#define ngx_rename_file          rename
+#define ngx_rename_file(from, to, pool)  rename(from->data, to->data)
 #define ngx_rename_file_n        "rename"
 
 
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -35,6 +35,8 @@ typedef struct {
 int ngx_os_init(ngx_log_t *log);
 int ngx_daemon(ngx_log_t *log);
 int ngx_posix_init(ngx_log_t *log);
+int ngx_posix_post_conf_init(ngx_log_t *log);
+
 
 ssize_t ngx_unix_recv(ngx_connection_t *c, char *buf, size_t size);
 ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry);
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -40,6 +40,8 @@ ssize_t ngx_unix_recv(ngx_connection_t *
     }
 
     do {
+        rev->ready = 1;
+
         n = recv(c->fd, buf, size, 0);
 
         ngx_log_debug(c->log, "recv: %d:%d" _ n _ size);
@@ -78,11 +80,14 @@ ssize_t ngx_unix_recv(ngx_connection_t *
         }
 
         rev->ready = 0;
-        rev->error = 1;
         n = ngx_unix_recv_error(rev, ngx_socket_errno);
 
     } while (n == NGX_EINTR);
 
+    if (n == NGX_ERROR){
+        rev->error = 1;
+    }
+
     return n;
 }
 
@@ -96,6 +101,8 @@ ssize_t ngx_unix_recv(ngx_connection_t *
     rev = c->read;
 
     do {
+        rev->ready = 1;
+
         n = recv(c->fd, buf, size, 0);
 
         ngx_log_debug(c->log, "recv: %d:%d" _ n _ size);
@@ -113,11 +120,14 @@ ssize_t ngx_unix_recv(ngx_connection_t *
         }
 
         rev->ready = 0;
-        rev->error = 1;
         n = ngx_unix_recv_error(rev, ngx_socket_errno);
 
     } while (n == NGX_EINTR);
 
+    if (n == NGX_ERROR){
+        rev->error = 1;
+    }
+
     return n;
 }
 
--- a/src/os/unix/ngx_unix_init.c
+++ b/src/os/unix/ngx_unix_init.c
@@ -3,17 +3,19 @@
 #include <ngx_core.h>
 
 
+#if 0
 /* STUB */
 ssize_t ngx_unix_recv(ngx_connection_t *c, char *buf, size_t size);
 ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in);
 int ngx_posix_init(ngx_log_t *log);
 int ngx_posix_post_conf_init(ngx_log_t *log);
 /* */
+#endif
 
 
 ngx_os_io_t ngx_os_io = {
     ngx_unix_recv,
-    NULL,
+    ngx_readv_chain,
     NULL,
     ngx_writev_chain,
     NGX_HAVE_ZEROCOPY
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -24,6 +24,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
     iov = NULL;
 
     /* create the iovec and coalesce the neighbouring hunks */
+
     for (cl = in; cl; cl = cl->next) {
 
         if (prev == cl->hunk->pos) {
@@ -57,7 +58,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
     sent = n > 0 ? n : 0;
 
 #if (NGX_DEBUG_WRITE_CHAIN)
-    ngx_log_debug(c->log, "writev: %qd" _ sent);
+    ngx_log_debug(c->log, "writev: " OFF_FMT  _ sent);
 #endif
 
     c->sent += sent;
@@ -75,12 +76,6 @@ ngx_log_debug(c->log, "SIZE: %d" _ size)
                 cl->hunk->pos = cl->hunk->last;
             }
 
-#if 0
-            if (cl->hunk->type & NGX_HUNK_FILE) {
-                cl->hunk->file_pos = cl->hunk->file_last;
-            }
-#endif
-
             continue;
         }
 
@@ -88,12 +83,6 @@ ngx_log_debug(c->log, "SIZE: %d" _ size)
             cl->hunk->pos += sent;
         }
 
-#if 0
-        if (cl->hunk->type & NGX_HUNK_FILE) {
-            cl->hunk->file_pos += sent;
-        }
-#endif
-
         break;
     }
 
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -6,13 +6,73 @@
 ssize_t ngx_read_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
 {
     size_t      n;
+    long        high_offset;
+    ngx_err_t   err;
     OVERLAPPED  ovlp, *povlp;
 
-#if (WIN9X)
+    if (ngx_win32_version < NGX_WIN_NT) {
+
+        /*
+         * in Win9X the overlapped pointer must be NULL
+         * so we need to use SetFilePointer() to set the offset
+         */
+
+        if (file->offset != offset) {
+
+            /*
+             * the maximum file size on FAT16 is 2G, but on FAT32 it's 4G so we
+             * need to use high_offset because a single offset is signed value
+             */
+
+            high_offset = (long) (offset >> 32);
+            if (SetFilePointer(file->fd, (long) offset, &high_offset,
+                               FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+            {
+                /*
+                 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid
+                 * value for large file so we need also to check GetLastError()
+                 */
+
+                err = ngx_errno;
+                if (err != NO_ERROR) {
+                    ngx_log_error(NGX_LOG_ERR, file->log, err,
+                                  "SeekFilePointer() failed");
+                    return NGX_ERROR;
+                }
+            }
+        }
+
+        povlp = NULL;
+
+    } else {
+        ovlp.Internal = 0;
+        ovlp.InternalHigh = 0;
+        ovlp.Offset = (DWORD) offset;
+        ovlp.OffsetHigh = (DWORD) (offset >> 32);
+        ovlp.hEvent = NULL;
+
+        povlp = &ovlp;
+    }
+
+    if (ReadFile(file->fd, buf, size, &n, povlp) == 0) {
+        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "ReadFile() failed");
+        return NGX_ERROR;
+    }
+
+    file->offset += n;
+
+    return n;
+}
+
+
+ssize_t ngx_write_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
+{
+    size_t      n;
+    long        high_offset;
+    ngx_err_t   err;
+    OVERLAPPED  ovlp, *povlp;
 
     if (ngx_win32_version < NGX_WIN_NT) {
-        long        high_offset;
-        ngx_err_t   err;
 
         /*
          * in Win9X the overlapped pointer must be NULL
@@ -47,8 +107,6 @@ ssize_t ngx_read_file(ngx_file_t *file, 
         povlp = NULL;
 
     } else {
-
-#endif
         ovlp.Internal = 0;
         ovlp.InternalHigh = 0;
         ovlp.Offset = (DWORD) offset;
@@ -56,80 +114,7 @@ ssize_t ngx_read_file(ngx_file_t *file, 
         ovlp.hEvent = NULL;
 
         povlp = &ovlp;
-
-#if (WIN9X)
     }
-#endif
-
-    if (ReadFile(file->fd, buf, size, &n, povlp) == 0) {
-        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "ReadFile() failed");
-        return NGX_ERROR;
-    }
-
-    file->offset += n;
-
-    return n;
-}
-
-
-ssize_t ngx_write_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
-{
-    size_t      n;
-    OVERLAPPED  ovlp, *povlp;
-
-#if (WIN9X)
-
-    if (ngx_win32_version < NGX_WIN_NT) {
-        long        high_offset;
-        ngx_err_t   err;
-
-        /*
-         * in Win9X the overlapped pointer must be NULL
-         * so we need to use SetFilePointer() to set the offset
-         */
-
-        if (file->offset != offset) {
-
-            /*
-             * the maximum file size on FAT16 is 2G, but on FAT32 it's 4G so we
-             * need to use high_offset because a single offset is signed value
-             */
-
-            high_offset = (long) (offset >> 32);
-            if (SetFilePointer(file->fd, (long) offset, &high_offset,
-                               FILE_BEGIN) == INVALID_SET_FILE_POINTER)
-            {
-                /*
-                 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid
-                 * value for large file so we need also to check GetLastError()
-                 */
-
-                err = ngx_errno;
-                if (err != NO_ERROR) {
-                    ngx_log_error(NGX_LOG_ERR, file->log, err,
-                                  "SeekFilePointer() failed");
-                    return NGX_ERROR;
-                }
-            }
-        }
-
-        povlp = NULL;
-
-    } else {
-
-#endif
-
-        ovlp.Internal = 0;
-        ovlp.InternalHigh = 0;
-        ovlp.Offset = (DWORD) offset;
-        ovlp.OffsetHigh = (DWORD) (offset >> 32);
-        ovlp.hEvent = NULL;
-
-        povlp = &ovlp;
-
-#if (WIN9X)
-    }
-#endif
 
     if (WriteFile(file->fd, buf, size, &n, povlp) == 0) {
         ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "WriteFile() failed");
@@ -142,15 +127,103 @@ ssize_t ngx_write_file(ngx_file_t *file,
 }
 
 
+ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl,
+                                off_t offset, ngx_pool_t *pool)
+{
+    char     *buf, *prev;
+    size_t    size;
+    ssize_t   total, n;
+
+    total = 0;
+
+    while (cl) {
+        buf = cl->hunk->pos;
+        prev = buf;
+        size = 0;
+
+        /* coalesce the neighbouring hunks */
+
+        while (cl && prev == cl->hunk->pos) {
+            size += cl->hunk->last - cl->hunk->pos;
+            prev = cl->hunk->last;
+            cl = cl->next;
+        }
+
+        n = ngx_write_file(file, buf, size, offset);
+
+        if (n == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        total += n;
+        offset += n;
+    }
+
+    return total;
+}
+
+
+int ngx_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_pool_t *pool)
+{
+    int         rc, collision;
+    u_int       num;
+    char       *name;
+    ngx_err_t   err;
+
+    name = ngx_palloc(pool, to->len + 1 + 10 + 1 + sizeof("DELETE"));
+    ngx_memcpy(name, to->data, to->len);
+
+    collision = 0;
+
+    /* mutex_lock() (per cache or single ?) */
+
+    do {
+        num = ngx_next_temp_number(collision);
+
+        ngx_snprintf(name + to->len, 1 + 10 + 1 + sizeof("DELETE"),
+                     ".%010u.DELETE", num);
+
+        if (MoveFile(to->data, name) == 0) {
+            err = ngx_errno;
+            if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+                return NGX_ERROR;
+            }
+
+            collision = 1;
+            ngx_log_error(NGX_LOG_ERR, pool->log, ngx_errno,
+                          "MoveFile() failed");
+        }
+
+    } while (collision);
+
+    if (ngx_win32_version >= NGX_WIN_NT) {
+        if (DeleteFile(name) == 0) {
+            ngx_log_error(NGX_LOG_ERR, pool->log, ngx_errno,
+                          "DeleteFile() failed");
+        }
+    }
+
+    if (MoveFile(from->data, to->data) == 0) {
+        rc = NGX_ERROR;
+
+    } else {
+        rc = NGX_OK;
+    }
+
+    if (rc == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ERR, pool->log, ngx_errno, "MoveFile() failed");
+    }
+
+    /* mutex_unlock() */
+
+    return rc;
+}
+
+
 int ngx_file_append_mode(ngx_fd_t fd)
 {
-    ngx_err_t  err;
-
     if (SetFilePointer(fd, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) {
-        err = ngx_errno;
-        if (err != NO_ERROR) {
-            ngx_log_error(NGX_LOG_ERR, file->log, err,
-                          "SeekFilePointer() failed");
+        if (ngx_errno != NO_ERROR) {
             return NGX_ERROR;
         }
     }
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -58,8 +58,7 @@ int ngx_file_append_mode(ngx_fd_t fd);
 #define ngx_close_file              CloseHandle
 #define ngx_close_file_n            "CloseHandle()"
 
-/* STUB */
-#define ngx_rename_file             MoveFile
+int ngx_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_pool_t *pool);
 #define ngx_rename_file_n           "MoveFile()"
 
 #define ngx_mkdir(name)             CreateDirectory(name, NULL)
--- a/src/os/win32/ngx_os.h
+++ b/src/os/win32/ngx_os.h
@@ -1,4 +1,4 @@
-ifndef _NGX_OS_H_INCLUDED_
+#ifndef _NGX_OS_H_INCLUDED_
 #define _NGX_OS_H_INCLUDED_
 
 
@@ -33,6 +33,11 @@ typedef struct {
 
 int ngx_os_init(ngx_log_t *log);
 
+ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size);
+ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, char *buf, size_t size);
+ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in);
+ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in);
+
 
 extern ngx_os_io_t  ngx_os_io;
 extern int          ngx_max_sockets;
deleted file mode 100644
--- a/src/os/win32/ngx_os_init.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _NGX_OS_INIT_H_INCLUDED_
-#define _NGX_OS_INIT_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-
-int ngx_os_init(ngx_log_t *log);
-
-ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size);
-
-
-#endif /* _NGX_OS_INIT_H_INCLUDED_ */
deleted file mode 100644
--- a/src/os/win32/ngx_recv.c
+++ /dev/null
@@ -1,93 +0,0 @@
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-
-
-ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size)
-{
-    int           rc;
-    u_int         flags;
-    size_t        bytes;
-    ngx_err_t     err;
-    WSABUF        wsabuf[1];
-    ngx_event_t  *ev;
-    LPWSAOVERLAPPED_COMPLETION_ROUTINE  handler;
-
-    ev = c->read;
-
-/* DEBUG */ bytes = 0;
-
-    if (ev->timedout) {
-        ngx_set_socket_errno(NGX_ETIMEDOUT);
-        ngx_log_error(NGX_LOG_ERR, ev->log, 0, "WSARecv() timed out");
-
-        return NGX_ERROR;
-    }
-
-    if (ev->ready) {
-        ev->ready = 0;
-
-#if (HAVE_IOCP_EVENT) /* iocp */
-
-        if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
-            if (ev->ovlp.error) {
-                ngx_log_error(NGX_LOG_ERR, c->log, ev->ovlp.error,
-                              "WSARecv() failed");
-                return NGX_ERROR;
-            }
-
-            return ev->available;
-        }
-
-#endif
-
-        if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &ev->ovlp,
-                                   &bytes, 0, NULL) == 0) {
-            err = ngx_socket_errno;
-            ngx_log_error(NGX_LOG_CRIT, ev->log, err,
-                         "WSARecv() or WSAGetOverlappedResult() failed");
-
-            return NGX_ERROR;
-        }
-
-        return bytes;
-    }
-
-    ngx_memzero(&ev->ovlp, sizeof(WSAOVERLAPPED));
-    wsabuf[0].buf = buf;
-    wsabuf[0].len = size;
-    flags = 0;
-
-#if 0
-    handler = ev->handler;
-#else
-    handler = NULL;
-#endif
-
-    rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags,
-                 (LPWSAOVERLAPPED) &ev->ovlp, handler);
-
-    ngx_log_debug(ev->log, "WSARecv: %d:%d" _ rc _ bytes);
-
-    if (rc == -1) {
-        err = ngx_socket_errno;
-        if (err == WSA_IO_PENDING) {
-            return NGX_AGAIN;
-
-        } else {
-            ngx_log_error(NGX_LOG_CRIT, ev->log, err, "WSARecv() failed");
-            return NGX_ERROR;
-        }
-    }
-
-#if (HAVE_IOCP_EVENT) /* iocp */
-
-    if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
-        return NGX_AGAIN;
-    }
-
-#endif
-
-    return bytes;
-}
--- a/src/os/win32/ngx_win32_init.c
+++ b/src/os/win32/ngx_win32_init.c
@@ -2,11 +2,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 
-/* STUB */
-ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size);
-ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in);
-/* */
-
 
 int  ngx_win32_version;
 int  ngx_max_sockets;
--- a/src/os/win32/ngx_wsarecv.c
+++ b/src/os/win32/ngx_wsarecv.c
@@ -6,6 +6,149 @@
 
 ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size)
 {
+    int           rc;
+    u_int         flags;
+    size_t        bytes;
+    WSABUF        wsabuf[1];
+    ngx_err_t     err;
+    ngx_event_t  *rev;
+
+    wsabuf[0].buf = buf;
+    wsabuf[0].len = size;
+    flags = 0;
+    bytes = 0;
+
+    rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL);
+
+    ngx_log_debug(c->log, "WSARecv: %d:%d" _ rc _ bytes);
+
+    rev = c->read;
+
+    if (rc == -1) {
+        rev->ready = 0;
+        err = ngx_socket_errno;
+
+        if (err == WSAEWOULDBLOCK) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "WSARecv() EAGAIN");
+            return NGX_AGAIN;
+        }
+
+        rev->error = 1;
+        ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSARecv() failed");
+        return NGX_ERROR;
+    }
+
+    if (bytes < size) {
+        rev->ready = 0;
+    }
+
+    if (bytes == 0) {
+        rev->eof = 1;
+    }
+
+    return bytes;
+}
+
+
+ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, char *buf, size_t size)
+{
+    int               rc;
+    u_int             flags;
+    size_t            bytes;
+    WSABUF            wsabuf[1];
+    ngx_err_t         err;
+    ngx_event_t      *rev;
+    LPWSAOVERLAPPED   ovlp;
+
+    rev = c->read;
+
+    if (!rev->ready) {
+        ngx_log_error(NGX_LOG_ALERT, rev->log, 0, "SECOND WSA POST");
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug(c->log, "rev->complete: %d" _ rev->complete);
+
+    if (rev->complete) {
+        rev->complete = 0;
+
+        if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+            if (rev->ovlp.error) {
+                ngx_log_error(NGX_LOG_ERR, c->log, rev->ovlp.error,
+                              "WSARecv() failed");
+                return NGX_ERROR;
+            }
+
+            return rev->available;
+        }
+
+        if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp,
+                                   &bytes, 0, NULL) == 0) {
+            ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
+                         "WSARecv() or WSAGetOverlappedResult() failed");
+
+            return NGX_ERROR;
+        }
+
+        return bytes;
+    }
+
+    ovlp = (LPWSAOVERLAPPED) &rev->ovlp;
+    ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+    wsabuf[0].buf = buf;
+    wsabuf[0].len = size;
+    flags = 0;
+    bytes = 0;
+
+    rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL);
+
+    rev->complete = 0;
+
+    ngx_log_debug(c->log, "WSARecv: %d:%d" _ rc _ bytes);
+
+    if (rc == -1) {
+        err = ngx_socket_errno;
+        if (err == WSA_IO_PENDING) {
+            rev->active = 1;
+            return NGX_AGAIN;
+        }
+
+        rev->error = 1;
+        ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSARecv() failed");
+        return NGX_ERROR;
+    }
+
+    if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+        /*
+         * if a socket was bound with I/O completion port
+         * then GetQueuedCompletionStatus() would anyway return its status
+         * despite that WSARecv() was already complete
+         */
+
+        rev->active = 1;
+        return NGX_AGAIN;
+    }
+
+    if (bytes == 0) {
+        rev->eof = 1;
+        rev->ready = 0;
+
+    } else {
+        rev->ready = 1;
+    }
+
+    rev->active = 0;
+
+    return bytes;
+}
+
+#if 0
+
+/* DELELTE IT WHEN ABOVE FUNC WOULD BE TESTED */
+
+ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size)
+{
     int               rc;
     u_int             flags;
     size_t            bytes;
@@ -88,3 +231,5 @@ ssize_t ngx_wsarecv(ngx_connection_t *c,
 
     return bytes;
 }
+
+#endif
--- a/src/os/win32/ngx_wsasend_chain.c
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -6,6 +6,249 @@
 
 ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in)
 {
+    int           rc;
+    char         *prev;
+    size_t        size, sent;
+    LPWSABUF      wsabuf;
+    ngx_err_t     err;
+    ngx_event_t  *wev;
+    ngx_array_t   wsabufs;
+    ngx_chain_t  *cl;
+
+    wev = c->write;
+
+    if (!wev->ready) {
+        return in;
+    }
+
+    /*
+     * 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->hunk->pos) {
+            wsabuf->len += cl->hunk->last - cl->hunk->pos;
+            prev = cl->hunk->last;
+
+        } else {
+            ngx_test_null(wsabuf, ngx_push_array(&wsabufs), NGX_CHAIN_ERROR);
+            wsabuf->buf = cl->hunk->pos;
+            wsabuf->len = cl->hunk->last - cl->hunk->pos;
+            prev = cl->hunk->last;
+        }
+    }
+
+    rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, NULL, NULL);
+
+    if (rc == -1) {
+        err = ngx_errno;
+
+        if (err == WSAEWOULDBLOCK) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "WSASend() EAGAIN");
+            wev->ready = 0;
+            return in;
+
+        } else {
+            wev->error = 1;
+            ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSASend() failed");
+            return NGX_CHAIN_ERROR;
+        }
+    }
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+    ngx_log_debug(c->log, "WSASend(): %d" _ sent);
+#endif
+
+    c->sent += sent;
+
+    for (cl = in; cl && sent > 0; cl = cl->next) {
+
+        size = cl->hunk->last - cl->hunk->pos;
+
+        if (sent >= size) {
+            sent -= size;
+
+            if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
+                cl->hunk->pos = cl->hunk->last;
+            }
+
+            continue;
+        }
+
+        if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
+            cl->hunk->pos += sent;
+        }
+
+        break;
+    }
+
+    if (cl) {
+        wev->ready = 0;
+    }
+
+    return cl;
+}
+
+
+ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in)
+{
+    int               rc;
+    char             *prev;
+    size_t            size, sent;
+    LPWSABUF          wsabuf;
+    ngx_err_t         err;
+    ngx_event_t      *wev;
+    ngx_array_t       wsabufs;
+    ngx_chain_t      *cl;
+    LPWSAOVERLAPPED   ovlp;
+
+    wev = c->write;
+
+    if (!wev->ready) {
+        return in;
+    }
+
+    if (!wev->complete) {
+
+        /* post the overlapped WSASend() */
+ 
+        /*
+         * 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->hunk->pos) {
+                wsabuf->len += cl->hunk->last - cl->hunk->pos;
+                prev = cl->hunk->last;
+ 
+            } else {
+                ngx_test_null(wsabuf, ngx_push_array(&wsabufs),
+                              NGX_CHAIN_ERROR);
+                wsabuf->buf = cl->hunk->pos;
+                wsabuf->len = cl->hunk->last - cl->hunk->pos;
+                prev = cl->hunk->last;
+            }
+        }
+
+        ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
+        ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+ 
+        rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, ovlp, NULL);
+
+        wev->complete = 0;
+
+        if (rc == -1) {
+            err = ngx_errno;
+
+            if (err == WSA_IO_PENDING) {
+                wev->active = 1;
+                return in;
+
+            } else {
+                wev->error = 1;
+                ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSASend() failed");
+                return NGX_CHAIN_ERROR;
+            }
+ 
+        } else if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+             /*
+              * if a socket was bound with I/O completion port then
+              * GetQueuedCompletionStatus() would anyway return its status
+              * despite that WSASend() was already complete
+              */
+
+            wev->active = 1;
+            return in;
+        }
+
+    } else {
+
+        /* the overlapped WSASend() complete */
+
+        wev->complete = 0;
+        wev->active = 0;
+
+        if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+            if (wev->ovlp.error) {
+                ngx_log_error(NGX_LOG_ERR, c->log, wev->ovlp.error,
+                              "WSASend() failed");
+                return NGX_CHAIN_ERROR;
+            }
+
+            sent = wev->available;
+
+        } else {
+            if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp,
+                                       &sent, 0, NULL) == 0) {
+                ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
+                             "WSASend() or WSAGetOverlappedResult() failed");
+    
+                return NGX_CHAIN_ERROR;
+            }
+        }
+    }
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+    ngx_log_debug(c->log, "WSASend(): %d" _ sent);
+#endif
+
+    c->sent += sent;
+
+    for (cl = in; cl && sent > 0; cl = cl->next) {
+
+        size = cl->hunk->last - cl->hunk->pos;
+
+        if (sent >= size) {
+            sent -= size;
+
+            if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
+                cl->hunk->pos = cl->hunk->last;
+            }
+
+            continue;
+        }
+
+        if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
+            cl->hunk->pos += sent;
+        }
+
+        break;
+    }
+
+    if (cl) {
+        wev->ready = 0;
+
+    } else {
+        wev->ready = 1;
+    }
+
+    return cl;
+}
+
+
+#if 0
+
+ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in)
+{
     int               rc;
     char             *prev;
     size_t            size, sent;
@@ -175,7 +418,7 @@ non-block
         break;
     }
 
-    ngx_destroy_array(&wsabufs);
-
     return ce;
 }
+
+#endif