changeset 103:6dfda4cf5200

nginx-0.0.1-2003-06-11-19:28:34 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 11 Jun 2003 15:28:34 +0000
parents 7e86d028d8f0
children 7db96f59bc29
files src/core/nginx.c src/core/ngx_conf_file.h src/core/ngx_connection.h src/core/ngx_log.c src/core/ngx_modules.c src/event/modules/ngx_iocp_module.c src/event/modules/ngx_iocp_module.h src/event/modules/ngx_select_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_acceptex.c src/event/ngx_event_timer.c src/event/ngx_event_timer.h src/http/modules/ngx_http_chunked_filter.c src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_range_filter.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_event.c src/http/ngx_http_output_filter.c src/http/ngx_http_special_response.c src/http/ngx_http_write_filter.c src/os/unix/ngx_aio_read.c src/os/unix/ngx_aio_write.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_readv_chain.c src/os/unix/ngx_recv.c src/os/unix/ngx_socket.c src/os/unix/ngx_solaris_config.h src/os/unix/ngx_writev_chain.c src/os/win32/ngx_errno.c src/os/win32/ngx_init.c src/os/win32/ngx_os_init.h src/os/win32/ngx_socket.h src/os/win32/ngx_types.h src/os/win32/ngx_win32_init.c src/os/win32/ngx_wsarecv.c src/os/win32/ngx_wsasend_chain.c
diffstat 41 files changed, 882 insertions(+), 303 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -2,9 +2,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-
-#include <ngx_listen.h>
-
+#include <ngx_event.h>
 #include <nginx.h>
 
 
@@ -61,7 +59,7 @@ int main(int argc, char *const *argv)
 
     {
         ngx_init_array(ngx_listening_sockets,
-                       ngx_pool, 10, sizeof(ngx_listen_t),
+                       ngx_pool, 10, sizeof(ngx_listening_t),
                        1);
 
         ngx_memzero(&conf, sizeof(ngx_conf_t));
@@ -126,10 +124,10 @@ int main(int argc, char *const *argv)
 
 static int ngx_open_listening_sockets(ngx_log_t *log)
 {
-    int           times, failed, reuseaddr, i;
-    ngx_err_t     err;
-    ngx_socket_t  s;
-    ngx_listen_t *ls;
+    int              times, failed, reuseaddr, i;
+    ngx_err_t        err;
+    ngx_socket_t     s;
+    ngx_listening_t *ls;
 
     reuseaddr = 1;
 
@@ -137,7 +135,8 @@ static int ngx_open_listening_sockets(ng
          failed = 0;
 
         /* for each listening socket */
-        ls = (ngx_listen_t *) ngx_listening_sockets.elts;
+
+        ls = ngx_listening_sockets.elts;
         for (i = 0; i < ngx_listening_sockets.nelts; i++) {
 
             if (ls[i].bound)
@@ -161,6 +160,19 @@ static int ngx_open_listening_sockets(ng
                 return NGX_ERROR;
             }
 
+#if (WIN32)
+            /*
+             * Winsock assignes a socket number divisible by 4
+             * so to find a connection we divide a socket number by 4.
+             */
+
+            if (s % 4) {
+                ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
+                              ngx_socket_n " created socket %d", s);
+                return NGX_ERROR;
+            }
+#endif
+
             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                            (const void *) &reuseaddr, sizeof(int)) == -1) {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -123,8 +123,8 @@ struct ngx_conf_s {
     }
 
 #define ngx_conf_merge_size_value(conf, prev, default)                       \
-    if (conf == (size_t) NGX_CONF_UNSET) {                                   \
-        conf = (prev == (size_t) NGX_CONF_UNSET) ? default : prev;           \
+    if (conf == (ssize_t) NGX_CONF_UNSET) {                                   \
+        conf = (prev == (ssize_t) NGX_CONF_UNSET) ? default : prev;           \
     }
 
 #define ngx_conf_merge_str_value(conf, prev, default)                        \
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -1,45 +1,98 @@
 #ifndef _NGX_CONNECTION_H_INCLUDED_
 #define _NGX_CONNECTION_H_INCLUDED_
 
+
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_event.h>
+
+
+typedef struct {
+    ngx_socket_t      fd;
+
+    struct sockaddr  *sockaddr;
+    socklen_t         socklen;    /* size of sockaddr */
+    int               addr;       /* offset to address in sockaddr */
+    int               addr_text_max_len;
+    ngx_str_t         addr_text;
+
+    int               family;
+    int               type;
+    int               protocol;
+    int               flags;      /* Winsock2 flags */
+
+    void            (*handler)(ngx_connection_t *c); /* handler of accepted
+                                                        connection */
+    void             *ctx;        /* ngx_http_conf_ctx_t, for example */
+    void             *servers;    /* array of ngx_http_in_addr_t, for example */
+
+    ngx_log_t        *log;
+    int               backlog;
+
+    int               pool_size;
+    int               post_accept_buffer_size; /* should be here because
+                                                  of the AcceptEx() preread */
+    time_t            post_accept_timeout;     /* should be here because
+                                                  of the deferred accept */
+
+    unsigned          bound:1;       /* already bound */
+    unsigned          inherited:1;   /* inherited from previous process */
+    unsigned          nonblocking_accept:1;
+    unsigned          nonblocking:1;
+#if 0
+    unsigned          overlapped:1;  /* Winsock2 overlapped */
+#endif
+    unsigned          shared:1;    /* shared between threads or processes */
+#if (HAVE_DEFERRED_ACCEPT)
+    unsigned          deferred_accept:1;
+#endif
+} ngx_listening_t;
 
 
 struct ngx_connection_s {
-    ngx_socket_t     fd;
-    void            *data;
-
-#ifdef NGX_EVENT
+    void             *data;
     ngx_event_t      *read;
     ngx_event_t      *write;
-#endif
+
+    ngx_socket_t      fd;
+
+    ngx_listening_t  *listening;
 
     off_t             sent;
 
+#if 0
     void            (*handler)(ngx_connection_t *c);
+#endif
     void             *ctx;
     void             *servers;
 
+
     ngx_log_t        *log;
 
     ngx_pool_t       *pool;
+#if 0
     int               pool_size;
 
     int               family;
+#endif
+
     struct sockaddr  *sockaddr;
     socklen_t         socklen;
+    ngx_str_t         addr_text;
+
 #if (HAVE_IOCP)
     struct sockaddr  *local_sockaddr;
     socklen_t         local_socklen;
-    void             *listening;
 #endif
+
+#if 0
     int               addr;
     int               addr_text_max_len;
-    ngx_str_t         addr_text;
+#endif
 
     ngx_hunk_t       *buffer;
+#if 0
     unsigned int      post_accept_timeout;
+#endif
 
     int               number;
 
@@ -47,9 +100,15 @@ struct ngx_connection_s {
     unsigned          unexpected_eof:1;
     unsigned          tcp_nopush:1;
     unsigned          tcp_nopush_enabled:1;
+#if (HAVE_IOCP)
+    unsigned          accept_context_updated:1;
+#endif
 };
 
 
+
+
+
 #if 0
 cached file
     int      fd;       -2 unused, -1 closed (but read or mmaped), >=0 open
@@ -84,10 +143,11 @@ typedef struct {
 #endif
 
 
+
+extern ngx_array_t  ngx_listening_sockets;
 extern ngx_os_io_t  ngx_io;
 
 
-
 extern ngx_chain_t *(*ngx_write_chain_proc)
                                         (ngx_connection_t *c, ngx_chain_t *in);
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -77,7 +77,7 @@ void ngx_log_error_core(int level, ngx_l
 
     /* pid#tid */
     len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
-                        "%d#%d: ", ngx_getpid(), 0);
+                        PID_FMT "#%d: ", ngx_getpid(), 0);
 
 #if (HAVE_VARIADIC_MACROS)
     va_start(args, fmt);
--- a/src/core/ngx_modules.c
+++ b/src/core/ngx_modules.c
@@ -17,11 +17,10 @@ extern ngx_module_t  ngx_kqueue_module;
 #if (HAVE_DEVPOLL)
 extern ngx_module_t  ngx_devpoll_module;
 #endif
-#if (HAVE_AIO)
-extern ngx_module_t  ngx_aio_module;
-#endif
 #if (HAVE_IOCP)
 extern ngx_module_t  ngx_iocp_module;
+#elif (HAVE_AIO)
+extern ngx_module_t  ngx_aio_module;
 #endif
 
 
@@ -64,11 +63,10 @@ ngx_module_t *ngx_modules[] = {
 #if (HAVE_DEVPOLL)
     &ngx_devpoll_module,
 #endif
-#if (HAVE_AIO)
-    &ngx_aio_module,
-#endif
 #if (HAVE_IOCP)
     &ngx_iocp_module,
+#elif (HAVE_AIO)
+    &ngx_aio_module,
 #endif
 
     /* http */
--- a/src/event/modules/ngx_iocp_module.c
+++ b/src/event/modules/ngx_iocp_module.c
@@ -7,16 +7,13 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-
-
-typedef struct {
-    int  threads;
-} ngx_iocp_conf_t;
+#include <ngx_iocp_module.h>
 
 
 static int ngx_iocp_init(ngx_log_t *log);
 static void ngx_iocp_done(ngx_log_t *log);
 static int ngx_iocp_add_event(ngx_event_t *ev, int event, u_int key);
+static int ngx_iocp_del_connection(ngx_connection_t *c);
 static int ngx_iocp_process_events(ngx_log_t *log);
 static void *ngx_iocp_create_conf(ngx_pool_t *pool);
 static char *ngx_iocp_init_conf(ngx_pool_t *pool, void *conf);
@@ -33,6 +30,20 @@ static ngx_command_t  ngx_iocp_commands[
      offsetof(ngx_iocp_conf_t, threads),
      NULL},
 
+    {ngx_string("acceptex"),
+     NGX_EVENT_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_num_slot,
+     0,
+     offsetof(ngx_iocp_conf_t, acceptex),
+     NULL},
+
+    {ngx_string("acceptex_read"),
+     NGX_EVENT_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_flag_slot,
+     0,
+     offsetof(ngx_iocp_conf_t, acceptex_read),
+     NULL},
+
     ngx_null_command
 };
 
@@ -48,7 +59,7 @@ ngx_event_module_t  ngx_iocp_module_ctx 
         NULL,                              /* enable an event */
         NULL,                              /* disable an event */
         NULL,                              /* add an connection */
-        NULL,                              /* delete an connection */
+        ngx_iocp_del_connection,           /* delete an connection */
         ngx_iocp_process_events,           /* process the events */
         ngx_iocp_init,                     /* init the events */
         ngx_iocp_done                      /* done the events */
@@ -111,10 +122,13 @@ static int ngx_iocp_add_event(ngx_event_
 
     c = (ngx_connection_t *) ev->data;
 
-    ngx_log_debug(ev->log, "iocp add: %d, %08x:%08x" _ c->fd _ key _ &ev->ovlp);
+    c->read->active = 1;
+    c->write->active = 1;
+
+    ngx_log_debug(ev->log, "iocp add: %d, %d:%08x" _ c->fd _ key _ &ev->ovlp);
 
     if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) {
-        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                       "CreateIoCompletionPort() failed");
         return NGX_ERROR;
     }
@@ -123,6 +137,17 @@ static int ngx_iocp_add_event(ngx_event_
 }
 
 
+static int ngx_iocp_del_connection(ngx_connection_t *c)
+{
+    if (CancelIo((HANDLE) c->fd) == 0) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
 static int ngx_iocp_process_events(ngx_log_t *log)
 {
     int                rc;
@@ -148,7 +173,7 @@ static int ngx_iocp_process_events(ngx_l
     rc = GetQueuedCompletionStatus(iocp, &bytes, (LPDWORD) &key,
                                    (LPOVERLAPPED *) &ovlp, timer);
 
-    ngx_log_debug(log, "iocp: %d, %d:%08x:%08x" _ rc _ bytes _ key _ ovlp);
+    ngx_log_debug(log, "iocp: %d, %d, %d:%08x" _ rc _ bytes _ key _ ovlp);
 
     if (rc == 0) {
         err = ngx_errno;
@@ -179,13 +204,17 @@ ngx_log_debug(log, "iocp ev: %08x" _ ev)
         switch (key) {
         case NGX_IOCP_IO:
             ev->ready = 1;
-            ev->available = bytes;
             break;
 
         case NGX_IOCP_ACCEPT:
+            if (bytes) {
+                ev->ready = 1;
+            }
             break;
         }
 
+        ev->available = bytes;
+
 ngx_log_debug(log, "iocp ev handler: %08x" _ ev->event_handler);
 
         ev->event_handler(ev);
@@ -203,6 +232,8 @@ static void *ngx_iocp_create_conf(ngx_po
                   NGX_CONF_ERROR);
 
     cf->threads = NGX_CONF_UNSET;
+    cf->acceptex = NGX_CONF_UNSET;
+    cf->acceptex_read = NGX_CONF_UNSET;
 
     return cf;
 }
@@ -213,6 +244,8 @@ static char *ngx_iocp_init_conf(ngx_pool
     ngx_iocp_conf_t *cf = conf;
 
     ngx_conf_init_value(cf->threads, 0);
+    ngx_conf_init_value(cf->acceptex, 10);
+    ngx_conf_init_value(cf->acceptex_read, 1);
 
     return NGX_CONF_OK;
 }
--- a/src/event/modules/ngx_iocp_module.h
+++ b/src/event/modules/ngx_iocp_module.h
@@ -2,14 +2,14 @@
 #define _NGX_IOCP_MODULE_H_INCLUDED_
 
 
-#include <ngx_types.h>
-#include <ngx_log.h>
-#include <ngx_event.h>
+typedef struct {
+    int  threads;
+    int  acceptex;
+    int  acceptex_read;
+} ngx_iocp_conf_t;
 
 
-int ngx_iocp_init(int max_connections, ngx_log_t *log);
-int ngx_iocp_add_event(ngx_event_t *ev);
-int ngx_iocp_process_events(ngx_log_t *log);
+extern ngx_module_t  ngx_iocp_module;
 
 
 #endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -378,7 +378,9 @@ static char *ngx_select_init_conf(ngx_po
 
     ecf = ngx_event_get_conf(ngx_event_module);
 
-    if (ecf->connections > FD_SETSIZE) {
+    /* the default FD_SETSIZE is 1024U in FreeBSD 5.x */
+
+    if ((unsigned) ecf->connections > FD_SETSIZE) {
         return "maximum number of connections "
                "supported by select() is " ngx_value(FD_SETSIZE);
     }
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -1,8 +1,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_listen.h>
-#include <ngx_connection.h>
 #include <ngx_event.h>
 
 
@@ -23,11 +21,6 @@ extern ngx_module_t ngx_devpoll_module;
 #include <ngx_aio_module.h>
 #endif
 
-#if (HAVE_IOCP)
-#include <ngx_event_acceptex.h>
-#include <ngx_iocp_module.h>
-#endif
-
 
 static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -123,11 +116,14 @@ ngx_module_t  ngx_event_module = {
 int ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log)
 {
     int                  m, i, fd;
-    ngx_listen_t        *s;
-    ngx_event_t         *ev;
+    ngx_event_t         *rev, *wev;
+    ngx_listening_t     *s;
     ngx_connection_t    *c;
     ngx_event_conf_t    *ecf;
     ngx_event_module_t  *module;
+#if (WIN32)
+    ngx_iocp_conf_t     *iocpcf;
+#endif
 
     ecf = ngx_event_get_conf(ngx_event_module);
 
@@ -161,71 +157,76 @@ ngx_log_debug(log, "TYPE: %d" _ ecf->use
                   NGX_ERROR);
 
     /* for each listening socket */
-    s = (ngx_listen_t *) ls->elts;
-    for (i = 0; i < ls->nelts; i++) {
+
+    for (s = ls->elts, i = 0; i < ls->nelts; i++) {
 
         fd = s[i].fd;
 
+#if (WIN32)
+        /*
+         * Winsock assignes a socket number divisible by 4
+         * so to find a connection we divide a socket number by 4.
+         */
+
+        c = &ngx_connections[fd / 4];
+        rev = &ngx_read_events[fd / 4];
+        wev = &ngx_write_events[fd / 4];
+#else
         c = &ngx_connections[fd];
-        ev = &ngx_read_events[fd];
+        rev = &ngx_read_events[fd];
+        wev = &ngx_write_events[fd];
+#endif
 
         ngx_memzero(c, sizeof(ngx_connection_t));
-        ngx_memzero(ev, sizeof(ngx_event_t));
+        ngx_memzero(rev, sizeof(ngx_event_t));
 
         c->fd = fd;
-        c->family = s[i].family;
-        c->socklen = s[i].socklen;
-        c->sockaddr = ngx_palloc(pool, s[i].socklen);
-        c->addr = s[i].addr;
-        c->addr_text = s[i].addr_text;
-        c->addr_text_max_len = s[i].addr_text_max_len;
-        c->post_accept_timeout = s[i].post_accept_timeout;
+        c->listening = &s[i];
 
-        c->handler = s[i].handler;
         c->ctx = s[i].ctx;
         c->servers = s[i].servers;
         c->log = s[i].log;
-        c->pool_size = s[i].pool_size;
 
-        ngx_test_null(ev->log,
-                      ngx_palloc(pool, sizeof(ngx_log_t)),
-                      NGX_ERROR);
+        ngx_test_null(rev->log, ngx_palloc(pool, sizeof(ngx_log_t)), NGX_ERROR);
 
-        ngx_memcpy(ev->log, c->log, sizeof(ngx_log_t));
-        c->read = ev;
-        ev->data = c;
-        ev->index = NGX_INVALID_INDEX;
+        ngx_memcpy(rev->log, c->log, sizeof(ngx_log_t));
+        c->read = rev;
+        c->write = wev;
+        rev->data = c;
+        rev->index = NGX_INVALID_INDEX;
 #if 0
-        ev->listening = 1;
+        rev->listening = 1;
 #endif
 
-        ev->available = 0;
+        rev->available = 0;
 
 #if (HAVE_DEFERRED_ACCEPT)
-        ev->deferred_accept = s[i].deferred_accept;
+        rev->deferred_accept = s[i].deferred_accept;
 #endif
 
-#if (HAVE_IOCP)
+#if (WIN32)
 
         if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
-            ev->event_handler = &ngx_event_acceptex;
+            rev->event_handler = &ngx_event_acceptex;
 
-            /* LOOK: we call ngx_iocp_add_event() also
-               in ngx_event_post_acceptex() */
-            if (ngx_iocp_add_event(ev) == NGX_ERROR) {
+            if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
-            ngx_event_post_acceptex(&s[i], 1);
+            iocpcf = ngx_event_get_conf(ngx_iocp_module);
+            if (ngx_event_post_acceptex(&s[i], iocpcf->acceptex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
 
         } else {
-            ev->event_handler = &ngx_event_accept;
+            rev->event_handler = &ngx_event_accept;
+            ngx_add_event(rev, NGX_READ_EVENT, 0);
         }
 
 #else
 
-        ev->event_handler = &ngx_event_accept;
-        ngx_add_event(ev, NGX_READ_EVENT, 0);
+        rev->event_handler = &ngx_event_accept;
+        ngx_add_event(rev, NGX_READ_EVENT, 0);
 
 #endif
     }
@@ -384,14 +385,6 @@ static char *ngx_event_init_conf(ngx_poo
 
 #endif
 
-#if (WIN32)
-    /*
-     * Winsock assignes a socket number according to 4 * N + M,
-     * where M is the constant 32 (98SE), 88 (NT) or 100 (W2K).
-     * So to find a connection we divide a socket number by 4.
-     */
-#endif
-
     ngx_conf_init_value(ecf->timer_queues, 10);
 
     return NGX_CONF_OK;
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -270,11 +270,6 @@ typedef struct {
 #define ngx_del_conn         ngx_event_actions.del_conn
 
 #if 0
-#define ngx_add_timer        ngx_event_actions.timer
-#else
-#define ngx_add_timer        ngx_event_add_timer
-#endif
-
 #if (HAVE_IOCP_EVENT)
 #define ngx_event_recv       ngx_event_wsarecv
 #elif (HAVE_AIO_EVENT)
@@ -283,17 +278,33 @@ typedef struct {
 #define ngx_event_recv       ngx_io.recv
 #define ngx_write_chain      ngx_io.send_chain
 #endif
+#endif
 
 #endif
 
 
+
+
+
+/* ***************************** */
+
+#define ngx_recv             ngx_io.recv
+#define ngx_write_chain      ngx_io.send_chain
+
+
+#define ngx_add_timer        ngx_event_add_timer
+#define ngx_del_timer        ngx_event_del_timer
+
+
 #if (HAVE_IOCP_EVENT)
 #define NGX_IOCP_ACCEPT      0
 #define NGX_IOCP_IO          1
 #endif
 
+/* ***************************** */
 
-#define ngx_del_timer        ngx_event_del_timer
+
+
 
 
 
@@ -309,6 +320,8 @@ extern int                   ngx_event_f
 
 
 
+/* ***************************** */
+
 #define NGX_EVENT_MODULE      0x544E5645  /* "EVNT" */
 
 #define NGX_EVENT_CONF        0x00200000
@@ -342,6 +355,16 @@ extern ngx_module_t        ngx_event_mod
 
 void ngx_event_accept(ngx_event_t *ev);
 
+#if (WIN32)
+void ngx_event_acceptex(ngx_event_t *ev);
+int ngx_event_post_acceptex(ngx_listening_t *ls, int n);
+#endif
+
+/* ***************************** */
+
+
+
+
 
 ssize_t ngx_event_recv_core(ngx_connection_t *c, char *buf, size_t size);
 int ngx_event_close_connection(ngx_event_t *ev);
@@ -351,7 +374,15 @@ int  ngx_pre_thread(ngx_array_t *ls, ngx
 void ngx_worker(ngx_log_t *log);
 
 
+/* ***************************** */
+
+
 #include <ngx_event_timer.h>
+#if (WIN32)
+#include <ngx_iocp_module.h>
+#endif
+
+/* ***************************** */
 
 
 #endif /* _NGX_EVENT_H_INCLUDED_ */
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -30,21 +30,23 @@ void ngx_event_accept(ngx_event_t *ev)
 
         /*
          * Create the pool before accept() to avoid copy the sockaddr.
-         * Although accept() can fail it's uncommon case
+         * Although accept() can fail it's an uncommon case
          * and the pool can be got from the free pool list
          */
 
-        pool = ngx_create_pool(ls->pool_size, ev->log);
+        pool = ngx_create_pool(ls->listening->pool_size, ev->log);
         if (pool == NULL) {
             return;
         }
 
-        sa = ngx_palloc(pool, ls->socklen);
+        sa = ngx_palloc(pool, ls->listening->socklen);
         if (sa == NULL) {
             return;
         }
 
-        len = ls->socklen;
+        len = ls->listening->socklen;
+
+ngx_log_debug(ev->log, "ADDR %s" _ ls->listening->addr_text.data);
 
         s = accept(ls->fd, sa, &len);
         if (s == -1) {
@@ -52,12 +54,13 @@ void ngx_event_accept(ngx_event_t *ev)
 
             if (err == NGX_EAGAIN) {
                 ngx_log_error(NGX_LOG_NOTICE, ev->log, err,
-                              "EAGAIN while accept() %s", ls->addr_text.data);
+                              "EAGAIN while accept() %s",
+                              ls->listening->addr_text.data);
                 return;
             }
 
             ngx_log_error(NGX_LOG_ALERT, ev->log, err,
-                          "accept() %s failed", ls->addr_text.data);
+                          "accept() %s failed", ls->listening->addr_text.data);
 
             ngx_destroy_pool(pool);
             return;
@@ -70,12 +73,12 @@ void ngx_event_accept(ngx_event_t *ev)
                           "accept() %s returned socket #%d while "
                           "only %d connections was configured, "
                           "sleeping for 1 second",
-                          ls->addr_text.data, s, ecf->connections);
+                          ls->listening->addr_text.data, s, ecf->connections);
 
             if (ngx_close_socket(s) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                               ngx_close_socket_n " %s failed",
-                              ls->addr_text.data);
+                              ls->listening->addr_text.data);
             }
 
             ngx_msleep(1000);
@@ -91,12 +94,12 @@ void ngx_event_accept(ngx_event_t *ev)
                 if (ngx_blocking(s) == -1) {
                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                   ngx_blocking_n " %s failed",
-                                  ls->addr_text.data);
+                                  ls->listening->addr_text.data);
 
                     if (ngx_close_socket(s) == -1) {
                         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                       ngx_close_socket_n " %s failed",
-                                      ls->addr_text.data);
+                                      ls->listening->addr_text.data);
                     }
 
                     ngx_destroy_pool(pool);
@@ -109,12 +112,12 @@ void ngx_event_accept(ngx_event_t *ev)
                 if (ngx_nonblocking(s) == -1) {
                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                   ngx_nonblocking_n " %s failed",
-                                  ls->addr_text.data);
+                                  ls->listening->addr_text.data);
 
                     if (ngx_close_socket(s) == -1) {
                         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                       ngx_close_socket_n " %s failed",
-                                      ls->addr_text.data);
+                                      ls->listening->addr_text.data);
                     }
 
                     ngx_destroy_pool(pool);
@@ -123,9 +126,26 @@ void ngx_event_accept(ngx_event_t *ev)
             }
         }
 
+#if (WIN32)
+        /*
+         * Winsock assignes a socket number divisible by 4
+         * so to find a connection we divide a socket number by 4.
+         */
+
+        if (s % 4) {
+            ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
+                          ngx_socket_n " created socket %d", s);
+            exit(1);
+        }
+
+        rev = &ngx_read_events[s / 4];
+        wev = &ngx_write_events[s / 4];
+        c = &ngx_connections[s / 4];
+#else
         rev = &ngx_read_events[s];
         wev = &ngx_write_events[s];
         c = &ngx_connections[s];
+#endif
 
         instance = rev->instance;
 
@@ -135,12 +155,9 @@ void ngx_event_accept(ngx_event_t *ev)
 
         c->pool = pool;
 
+        c->listening = ls->listening;
         c->sockaddr = sa;
-        c->family = ls->family;
         c->socklen = len;
-        c->addr = ls->addr;
-        c->addr_text_max_len = ls->addr_text_max_len;
-        c->post_accept_timeout = ls->post_accept_timeout;
 
         rev->instance = wev->instance = !instance;
 
@@ -182,7 +199,7 @@ void ngx_event_accept(ngx_event_t *ev)
                 if (ngx_close_socket(s) == -1) {
                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                   ngx_close_socket_n " %s failed",
-                                  ls->addr_text.data);
+                                  ls->listening->addr_text.data);
                 }
 
                 ngx_destroy_pool(pool);
@@ -190,7 +207,7 @@ void ngx_event_accept(ngx_event_t *ev)
             }
         }
 
-        ls->handler(c);
+        ls->listening->handler(c);
 
         if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
             ev->available--;
--- a/src/event/ngx_event_acceptex.c
+++ b/src/event/ngx_event_acceptex.c
@@ -1,14 +1,8 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-
-#include <ngx_listen.h>
-
 #include <ngx_event.h>
-#if 0
-#include <ngx_event_close.h>
-#include <ngx_iocp_module.h>
-#endif
+#include <nginx.h>
 
 
 void ngx_event_acceptex(ngx_event_t *rev)
@@ -17,11 +11,9 @@ void ngx_event_acceptex(ngx_event_t *rev
 
     c = (ngx_connection_t *) rev->data;
 
-ngx_log_debug(rev->log, "ADDR: %s" _ c->addr_text.data);
-
     if (rev->ovlp.error) {
-        ngx_log_error(NGX_LOG_CRIT, rev->log, rev->ovlp.error,
-                      "AcceptEx() failed for %s", c->addr_text.data);
+        ngx_log_error(NGX_LOG_CRIT, c->log, rev->ovlp.error,
+                      "AcceptEx() %s failed", c->listening->addr_text.data);
         return;
     }
 
@@ -30,36 +22,45 @@ ngx_log_debug(rev->log, "ADDR: %s" _ c->
     if (setsockopt(c->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
                    (char *)&c->listening->fd, sizeof(ngx_socket_t)) == -1)
     {
-        ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
                       "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed for %s",
                       c->addr_text.data);
     } else {
-        accept_context_updated = 1;
+        c->accept_context_updated = 1;
     }
 
-    getacceptexsockaddrs(c->data, 0,
-                         c->socklen + 16, c->socklen + 16,
+    getacceptexsockaddrs(c->buffer->pos, c->listening->post_accept_buffer_size,
+                         c->listening->socklen + 16,
+                         c->listening->socklen + 16,
                          &c->local_sockaddr, &c->local_socklen,
                          &c->sockaddr, &c->socklen);
 
+    if (c->listening->post_accept_buffer_size) {
+        c->buffer->last += rev->available;
+        c->buffer->end = c->buffer->start
+                                       + c->listening->post_accept_buffer_size;
+
+    } else {
+        c->buffer = NULL;
+    }
+
     ngx_event_post_acceptex(c->listening, 1);
 
-    /* STUB: InterlockedInc() */
+    /* TODO: MT */
     c->number = ngx_connection_counter++;
 
-    c->handler(c);
+    c->listening->handler(c);
 
     return;
 
 }
 
 
-int ngx_event_post_acceptex(ngx_listen_t *ls, int n)
+int ngx_event_post_acceptex(ngx_listening_t *ls, int n)
 {
     int                i;
     u_int              rcvd;
     ngx_err_t          err;
-    ngx_pool_t        *pool;
     ngx_event_t       *rev, *wev;
     ngx_socket_t       s;
     ngx_connection_t  *c;
@@ -68,29 +69,36 @@ int ngx_event_post_acceptex(ngx_listen_t
 
         /* TODO: look up reused sockets */
 
-        ngx_log_debug(ls->log, "socket: %x" _ ls->flags);
-
         s = ngx_socket(ls->family, ls->type, ls->protocol, ls->flags);
+        ngx_log_debug(ls->log, ngx_socket_n ": %d:%d" _ s _ ls->flags);
 
         if (s == -1) {
             ngx_log_error(NGX_LOG_ALERT, ls->log, ngx_socket_errno,
-                          ngx_socket_n " for AcceptEx() post failed");
+                          ngx_socket_n " for AcceptEx() %s post failed",
+                          ls->addr_text.data);
 
             return NGX_ERROR;
         }
 
-        ngx_test_null(pool, ngx_create_pool(ls->pool_size, ls->log), NGX_ERROR);
+        /*
+         * Winsock assignes a socket number divisible by 4
+         * so to find a connection we divide a socket number by 4.
+         */
 
-        rev = &ngx_read_events[s];
-        wev = &ngx_write_events[s];
-        c = &ngx_connections[s];
+        if (s % 4) {
+            ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
+                          ngx_socket_n " created socket %d", s);
+            exit(1);
+        }
+
+        rev = &ngx_read_events[s / 4];
+        wev = &ngx_write_events[s / 4];
+        c = &ngx_connections[s / 4];
 
         ngx_memzero(rev, sizeof(ngx_event_t));
         ngx_memzero(wev, sizeof(ngx_event_t));
         ngx_memzero(c, sizeof(ngx_connection_t));
 
-        c->pool = pool;
-
         rev->index = wev->index = NGX_INVALID_INDEX;
 
         rev->ovlp.event = rev;
@@ -100,53 +108,55 @@ int ngx_event_post_acceptex(ngx_listen_t
         c->read = rev;
         c->write = wev;
 
-        c->family = ls->family;
-        c->socklen = ls->socklen;
-        c->addr = ls->addr;
-        c->addr_text_max_len = ls->addr_text_max_len;
-        c->post_accept_timeout = ls->post_accept_timeout;
-
         c->listening = ls;
         c->fd = s;
 
-        c->unexpected_eof = 1;
-        wev->write = 1;
-
-        c->handler = ls->handler;
-        rev->event_handler = ngx_event_acceptex;
-
         c->ctx = ls->ctx;
         c->servers = ls->servers;
 
-        ngx_test_null(c->data, ngx_palloc(pool, 2 * (c->socklen + 16)),
+        c->unexpected_eof = 1;
+        wev->write = 1;
+        rev->event_handler = ngx_event_acceptex;
+
+        ngx_test_null(c->pool,
+                      ngx_create_pool(ls->pool_size, ls->log),
                       NGX_ERROR);
-        ngx_test_null(c->local_sockaddr, ngx_palloc(pool, c->socklen),
+
+        ngx_test_null(c->buffer,
+                      ngx_create_temp_hunk(c->pool,
+                                           ls->post_accept_buffer_size
+                                           + 2 * (c->listening->socklen + 16),
+                                           0, 0),
                       NGX_ERROR);
-        ngx_test_null(c->sockaddr, ngx_palloc(pool, c->socklen),
+
+        ngx_test_null(c->local_sockaddr, ngx_palloc(c->pool, ls->socklen),
+                      NGX_ERROR);
+
+        ngx_test_null(c->sockaddr, ngx_palloc(c->pool, ls->socklen),
                       NGX_ERROR);
 
         ngx_test_null(c->log, ngx_palloc(c->pool, sizeof(ngx_log_t)),
                       NGX_ERROR);
+
         ngx_memcpy(c->log, ls->log, sizeof(ngx_log_t));
-        rev->log = wev->log = c->log;
+        c->read->log = c->write->log = c->log;
 
         if (ngx_add_event(rev, 0, NGX_IOCP_IO) == NGX_ERROR) {
             return NGX_ERROR;
         }
 
-        if (acceptex(ls->fd, s, c->data, 0,
-                     c->socklen + 16, c->socklen + 16,
-                     &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0) {
+        if (acceptex(ls->fd, s, c->buffer->pos, ls->post_accept_buffer_size,
+                     ls->socklen + 16, ls->socklen + 16,
+                     &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0)
+        {
 
             err = ngx_socket_errno;
-            if (err == WSA_IO_PENDING) {
-                return NGX_OK;
-            }
+            if (err != WSA_IO_PENDING) {
+                ngx_log_error(NGX_LOG_ALERT, ls->log, err,
+                              "AcceptEx() %s falied", ls->addr_text.data);
 
-            ngx_log_error(NGX_LOG_ALERT, ls->log, err,
-                          "AcceptEx(%s) falied", ls->addr_text.data);
-
-            return NGX_ERROR;
+                return NGX_ERROR;
+            }
         }
     }
 
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -1,14 +1,8 @@
 
 #include <ngx_config.h>
-
 #include <ngx_core.h>
-#include <ngx_log.h>
-#include <ngx_alloc.h>
-#include <ngx_connection.h>
 #include <ngx_event.h>
 
-#include <ngx_event_timer.h>
-
 
 static ngx_event_t  *ngx_timer_queue;
 static int           ngx_timer_cur_queue;
@@ -49,7 +43,7 @@ void ngx_event_add_timer(ngx_event_t *ev
     ngx_event_t  *e;
 
 #if (NGX_DEBUG_EVENT)
-    ngx_connection_t *c = (ngx_connection_t *) ev->data;
+    ngx_connection_t *c = ev->data;
     ngx_log_debug(ev->log, "set timer: %d:%d, slot: %d" _
                   c->fd _ timer _ ngx_timer_cur_queue);
 #endif
--- a/src/event/ngx_event_timer.h
+++ b/src/event/ngx_event_timer.h
@@ -3,9 +3,7 @@
 
 
 #include <ngx_config.h>
-
-#include <ngx_log.h>
-#include <ngx_connection.h>
+#include <ngx_core.h>
 #include <ngx_event.h>
 
 
@@ -20,8 +18,8 @@ void ngx_event_expire_timers(ngx_msec_t 
 ngx_inline static void ngx_event_del_timer(ngx_event_t *ev)
 {
 #if (NGX_DEBUG_EVENT)
-    /* STUB - we can not cast (ngx_connection_t *) here */
-    ngx_log_debug(ev->log, "del timer: %d" _ *(int *)(ev->data));
+    ngx_connection_t *c = ev->data;
+    ngx_log_debug(ev->log, "del timer: %d" _ c->fd);
 #endif
 
     if (!ev->timer_next || !ev->timer_prev) {
--- a/src/http/modules/ngx_http_chunked_filter.c
+++ b/src/http/modules/ngx_http_chunked_filter.c
@@ -85,7 +85,7 @@ static int ngx_http_chunked_body_filter(
     }
 
     ngx_test_null(chunk, ngx_palloc(r->pool, 11), NGX_ERROR);
-    len = ngx_snprintf(chunk, 11, "%x" CRLF, size);
+    len = ngx_snprintf(chunk, 11, SIZEX_FMT CRLF, size);
 
     ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
     h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -240,7 +240,7 @@ static char *ngx_http_index_merge_conf(n
 
     if (conf->max_index_len == 0) {
         if (prev->max_index_len != 0) {
-            ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t)); 
+            ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t));
             return NGX_CONF_OK;
         }
 
--- a/src/http/modules/ngx_http_range_filter.c
+++ b/src/http/modules/ngx_http_range_filter.c
@@ -61,6 +61,10 @@ static int ngx_http_range_header_filter(
     ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t),
                    NGX_ERROR);
 
+#if (NGX_SUPPRESS_WARN)
+    range = NULL;
+#endif
+
     rc = 0;
     p = r->headers_in.range->value.data + 6;
 
@@ -149,7 +153,7 @@ static int ngx_http_range_header_filter(
                       ngx_palloc(r->pool, 8 + 20 + 1),
                       NGX_ERROR);
 
-        r->headers_out.content_range->value.len = 
+        r->headers_out.content_range->value.len =
                         ngx_snprintf(r->headers_out.content_range->value.data,
                                      8 + 20 + 1, "bytes */" OFF_FMT,
                                      r->headers_out.content_length);
@@ -170,7 +174,7 @@ static int ngx_http_range_header_filter(
                           ngx_palloc(r->pool, 6 + 20 + 1 + 20 + 1 + 20 + 1),
                           NGX_ERROR);
 
-            r->headers_out.content_range->value.len = 
+            r->headers_out.content_range->value.len =
                          ngx_snprintf(r->headers_out.content_range->value.data,
                                       6 + 20 + 1 + 20 + 1 + 20 + 1,
                                       "bytes " OFF_FMT "-" OFF_FMT "/" OFF_FMT,
@@ -244,7 +248,7 @@ static int ngx_http_range_header_filter(
                                ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5),
                                NGX_ERROR);
 
-                 range[i].content_range.len = 
+                 range[i].content_range.len =
                         ngx_snprintf(range[i].content_range.data,
                                      20 + 1 + 20 + 1 + 20 + 5,
                                      OFF_FMT "-" OFF_FMT "/" OFF_FMT CRLF CRLF,
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1,13 +1,10 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-
-#include <ngx_listen.h>
-
+#include <ngx_event.h>
 #include <ngx_http.h>
 
 
-static void ngx_http_init_filters(ngx_pool_t *pool, ngx_module_t **modules);
 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
@@ -54,17 +51,20 @@ static char *ngx_http_block(ngx_conf_t *
     char                        *rv;
     struct sockaddr_in          *addr_in;
     ngx_array_t                  in_ports;
-    ngx_listen_t                *ls;
+    ngx_listening_t             *ls;
     ngx_http_module_t           *module;
     ngx_conf_t                   pcf;
     ngx_http_conf_ctx_t         *ctx;
     ngx_http_in_port_t          *in_port, *inport;
     ngx_http_in_addr_t          *in_addr, *inaddr;
     ngx_http_core_main_conf_t   *cmcf;
-    ngx_http_core_srv_conf_t   **cscfp;
+    ngx_http_core_srv_conf_t   **cscfp, *cscf;
     ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_listen_t           *lscf;
     ngx_http_server_name_t      *s_name, *name;
+#if (WIN32)
+    ngx_iocp_conf_t             *iocpcf;
+#endif
 
     /* the main http context */
     ngx_test_null(ctx,
@@ -431,7 +431,7 @@ static char *ngx_http_block(ngx_conf_t *
 
             ngx_test_null(ls, ngx_push_array(&ngx_listening_sockets),
                           NGX_CONF_ERROR);
-            ngx_memzero(ls, sizeof(ngx_listen_t));
+            ngx_memzero(ls, sizeof(ngx_listening_t));
 
             ngx_test_null(addr_in,
                           ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)),
@@ -456,7 +456,7 @@ static char *ngx_http_block(ngx_conf_t *
             ls->family = AF_INET;
             ls->type = SOCK_STREAM;
             ls->protocol = IPPROTO_IP;
-#if (NGX_OVERLAPPED)
+#if (WIN32)
             ls->flags = WSA_FLAG_OVERLAPPED;
 #endif
             ls->sockaddr = (struct sockaddr *) addr_in;
@@ -468,8 +468,18 @@ static char *ngx_http_block(ngx_conf_t *
 
             ls->handler = ngx_http_init_connection;
             ls->log = cf->log;
-            ls->pool_size = cmcf->connection_pool_size;
-            ls->post_accept_timeout = cmcf->post_accept_timeout;
+
+            cscf = in_addr[a].core_srv_conf;
+            ls->pool_size = cscf->connection_pool_size;
+            ls->post_accept_timeout = cscf->post_accept_timeout;
+
+#if (WIN32)
+            iocpcf = ngx_event_get_conf(ngx_iocp_module);
+            if (iocpcf->acceptex_read) {
+                ls->post_accept_buffer_size = cscf->client_header_buffer_size;
+            }
+#endif
+
             ls->ctx = ctx;
 
             if (in_port[p].addrs.nelts > 1) {
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1,10 +1,6 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-
-/* ???? */
-#include <ngx_listen.h>
-
 #include <ngx_http.h>
 #include <nginx.h>
 
@@ -46,17 +42,17 @@ static ngx_command_t  ngx_http_core_comm
      NULL},
 
     {ngx_string("connection_pool_size"),
-     NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_size_slot,
-     NGX_HTTP_MAIN_CONF_OFFSET,
-     offsetof(ngx_http_core_main_conf_t, connection_pool_size),
+     NGX_HTTP_SRV_CONF_OFFSET,
+     offsetof(ngx_http_core_srv_conf_t, connection_pool_size),
      NULL},
 
     {ngx_string("post_accept_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
-     NGX_HTTP_MAIN_CONF_OFFSET,
-     offsetof(ngx_http_core_main_conf_t, post_accept_timeout),
+     NGX_HTTP_SRV_CONF_OFFSET,
+     offsetof(ngx_http_core_srv_conf_t, post_accept_timeout),
      NULL},
 
     {ngx_string("request_pool_size"),
@@ -738,9 +734,6 @@ static void *ngx_http_core_create_main_c
                   ngx_palloc(pool, sizeof(ngx_http_core_main_conf_t)),
                   NGX_CONF_ERROR);
 
-    cmcf->connection_pool_size = NGX_CONF_UNSET;
-    cmcf->post_accept_timeout = NGX_CONF_UNSET;
-
     ngx_init_array(cmcf->servers, pool, 5, sizeof(ngx_http_core_srv_conf_t *),
                    NGX_CONF_ERROR);
 
@@ -752,8 +745,7 @@ static char *ngx_http_core_init_main_con
 {
     ngx_http_core_main_conf_t *cmcf = conf;
 
-    ngx_conf_init_size_value(cmcf->connection_pool_size, 16384);
-    ngx_conf_init_msec_value(cmcf->post_accept_timeout, 30000);
+    /* TODO: remove it if no directives */
 
     return NGX_CONF_OK;
 }
@@ -773,6 +765,8 @@ static void *ngx_http_core_create_srv_co
     ngx_init_array(cscf->server_names, pool, 5, sizeof(ngx_http_server_name_t),
                    NGX_CONF_ERROR);
 
+    cscf->connection_pool_size = NGX_CONF_UNSET;
+    cscf->post_accept_timeout = NGX_CONF_UNSET;
     cscf->request_pool_size = NGX_CONF_UNSET;
     cscf->client_header_timeout = NGX_CONF_UNSET;
     cscf->client_header_buffer_size = NGX_CONF_UNSET;
@@ -827,6 +821,10 @@ static char *ngx_http_core_merge_srv_con
         n->core_srv_conf = conf;
     }
 
+    ngx_conf_merge_size_value(conf->connection_pool_size,
+                              prev->connection_pool_size, 16384);
+    ngx_conf_merge_msec_value(conf->post_accept_timeout,
+                              prev->post_accept_timeout, 30000);
     ngx_conf_merge_size_value(conf->request_pool_size,
                               prev->request_pool_size, 16384);
     ngx_conf_merge_msec_value(conf->client_header_timeout,
@@ -945,7 +943,7 @@ static char *ngx_set_listen(ngx_conf_t *
     ngx_str_t          *args;
     ngx_http_listen_t  *ls;
 
-    /* TODO: check duplicate 'listen' directives, 
+    /* TODO: check duplicate 'listen' directives,
              add resolved name to server names ??? */
 
     ngx_test_null(ls, ngx_push_array(&scf->listen), NGX_CONF_ERROR);
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -18,9 +18,6 @@ typedef struct {
 
 
 typedef struct {
-    int          connection_pool_size;
-    int          post_accept_timeout;
-
     ngx_array_t  servers;      /* array of ngx_http_core_srv_conf_t */
 } ngx_http_core_main_conf_t;
 
@@ -36,6 +33,8 @@ typedef struct {
 
     ngx_http_conf_ctx_t *ctx;  /* server ctx */
 
+    ngx_msec_t   post_accept_timeout;
+    ssize_t      connection_pool_size;
     size_t       request_pool_size;
     ngx_msec_t   client_header_timeout;
     size_t       client_header_buffer_size;
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -67,14 +67,15 @@ void ngx_http_init_connection(ngx_connec
     ngx_event_t         *rev;
     ngx_http_log_ctx_t  *lcx;
 
-    c->addr_text.data = ngx_palloc(c->pool, c->addr_text_max_len);
+    c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len);
     if (c->addr_text.data == NULL) {
         ngx_http_close_connection(c);
         return;
     }
 
-    c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr,
-                                     c->addr_text.data, c->addr_text_max_len);
+    c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr,
+                                     c->addr_text.data,
+                                     c->listening->addr_text_max_len);
     if (c->addr_text.len == 0) {
         ngx_http_close_connection(c);
         return;
@@ -100,7 +101,7 @@ void ngx_http_init_connection(ngx_connec
         return;
     }
 
-    ngx_add_timer(rev, c->post_accept_timeout);
+    ngx_add_timer(rev, c->listening->post_accept_timeout);
     rev->timer_set = 1;
 
     if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
@@ -158,19 +159,30 @@ static void ngx_http_init_request(ngx_ev
 
     if (in_port->addrs.nelts > 1) {
 
-        /* there're the several addresses on this port and one of them
-           is "*:port" so getsockname() is needed to determine
-           the server address */
+        /*
+         * there're the several addresses on this port and one of them
+         * is "*:port" so getsockname() is needed to determine
+         * the server address.
+         * AcceptEx() already gave this address.
+         */
 
-        /* TODO: AcceptEx() already gave this sockaddr_in */
+#if (WIN32)
+        if (c->local_sockaddr) {
+            r->in_addr =
+                   ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
 
-        len = sizeof(struct sockaddr_in);
-        if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno,
-                          "getsockname() failed");
-            ngx_http_close_connection(c);
-            return;
+        } else {
+#endif
+            len = sizeof(struct sockaddr_in);
+            if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
+                ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno,
+                              "getsockname() failed");
+                ngx_http_close_connection(c);
+                return;
+            }
+#if (WIN32)
         }
+#endif
 
         r->in_addr = addr_in.sin_addr.s_addr;
 
@@ -689,18 +701,19 @@ static ssize_t ngx_http_read_request_hea
     ngx_event_t               *rev;
     ngx_http_core_srv_conf_t  *cscf;
 
+    rev = r->connection->read;
+
     n = r->header_in->last - r->header_in->pos;
 
     if (n > 0) {
+        rev->ready = 0;
         return n;
     }
 
-    n = ngx_event_recv(r->connection, r->header_in->last,
-                       r->header_in->end - r->header_in->last);
+    n = ngx_recv(r->connection, r->header_in->last,
+                 r->header_in->end - r->header_in->last);
 
     if (n == NGX_AGAIN) {
-        rev = r->connection->read;
-
         if (!r->header_timeout_set) {
             if (rev->timer_set) {
                 ngx_del_timer(rev);
@@ -773,6 +786,20 @@ void ngx_http_finalize_request(ngx_http_
         }
 
         rc = ngx_http_special_response_handler(r, rc);
+
+        if (rc == NGX_AGAIN) {
+            return;
+        }
+
+        if (rc == NGX_ERROR) {
+            ngx_http_close_request(r, 0);
+            ngx_http_close_connection(r->connection);
+            return;
+        }
+
+    } else if (rc == NGX_ERROR) {
+        r->keepalive = 0;
+        r->lingering_close = 0;
     }
 
     rev = r->connection->read;
@@ -1028,7 +1055,7 @@ static int ngx_http_read_discarded_body(
         size = clcf->discarded_buffer_size;
     }
 
-    n = ngx_event_recv(r->connection, r->discarded_buffer, size);
+    n = ngx_recv(r->connection, r->discarded_buffer, size);
     if (n == NGX_ERROR) {
         return NGX_HTTP_BAD_REQUEST;
     }
@@ -1169,7 +1196,7 @@ static void ngx_http_keepalive_handler(n
 
     rev->ignore_econnreset = 1;
     ngx_set_socket_errno(0);
-    n = ngx_event_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
+    n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
     rev->ignore_econnreset = 0;
 
     if (n == NGX_AGAIN) {
@@ -1307,7 +1334,7 @@ static void ngx_http_lingering_close_han
     }
 
     do {
-        n = ngx_event_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
+        n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
 
         ngx_log_debug(c->log, "lingering read: %d" _ n);
 
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -5,7 +5,7 @@
 
 
 typedef struct {
-    size_t        hunk_size;
+    ssize_t  hunk_size;
 } ngx_http_output_filter_conf_t;
 
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -12,6 +12,16 @@ static char error_tail[] =
 ;
 
 
+static char msie_stub[] =
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+"<!-- The padding to disable MSIE's friendly error page -->" CRLF
+;
+
+
 static char error_302_page[] =
 "<html>" CRLF
 "<head><title>302 Found</title></head>" CRLF
@@ -134,8 +144,8 @@ static ngx_str_t error_pages[] = {
 
 int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
 {
-    int          err;
-    ngx_hunk_t  *message, *tail;
+    int          err, rc;
+    ngx_hunk_t  *h;
 
     r->headers_out.status = error;
 
@@ -172,7 +182,8 @@ int ngx_http_special_response_handler(ng
 
     if (error_pages[err].len) {
         r->headers_out.content_length = error_pages[err].len
-                                        + sizeof(error_tail);
+                                        + sizeof(error_tail) - 1
+                                        + sizeof(msie_stub) - 1;
 
         ngx_test_null(r->headers_out.content_type,
                       ngx_push_table(r->headers_out.headers),
@@ -187,29 +198,63 @@ int ngx_http_special_response_handler(ng
         r->headers_out.content_length = -1;
     }
 
-    if (ngx_http_send_header(r) == NGX_ERROR) {
+    rc = ngx_http_send_header(r);
+    if (rc == NGX_ERROR) {
         return NGX_ERROR;
     }
 
+    if (r->header_only) {
+        if (rc == NGX_AGAIN) {
+            ngx_http_set_write_handler(r);
+            return NGX_AGAIN;
+        }
+
+        return NGX_OK;
+    }
+
     if (error_pages[err].len == 0) {
         return NGX_OK;
     }
 
-    ngx_test_null(message, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR);
+    ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
 
-    message->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY;
-    message->pos = error_pages[err].data;
-    message->last = error_pages[err].data + error_pages[err].len;
+    h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY;
+    h->pos = error_pages[err].data;
+    h->last = error_pages[err].data + error_pages[err].len;
 
-    if (ngx_http_output_filter(r, message) == NGX_ERROR) {
+    if (ngx_http_output_filter(r, h) == NGX_ERROR) {
         return NGX_ERROR;
     }
 
-    ngx_test_null(tail, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR);
+    ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+
+    h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY;
+    h->pos = error_tail;
+    h->last = error_tail + sizeof(error_tail) - 1;
+
+    if (1) {
+        if (ngx_http_output_filter(r, h) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
 
-    tail->type = NGX_HUNK_MEMORY|NGX_HUNK_LAST|NGX_HUNK_IN_MEMORY;
-    tail->pos = error_tail;
-    tail->last = error_tail + sizeof(error_tail);
+        h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY;
+        h->pos = msie_stub;
+        h->last = msie_stub + sizeof(msie_stub) - 1;
+    }
+
+    h->type |= NGX_HUNK_LAST;
+
+    rc = ngx_http_output_filter(r, h);
 
-    return ngx_http_output_filter(r, tail);
+    if (r->main == NULL) {
+        if (rc == NGX_AGAIN) {
+            ngx_http_set_write_handler(r);
+            return NGX_AGAIN;
+        }
+    }
+
+    return NGX_OK;
+
 }
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -1,11 +1,12 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 #include <ngx_http.h>
 
 
 typedef struct {
-    size_t        buffer_output;
+    ssize_t  buffer_output;
 } ngx_http_write_filter_conf_t;
 
 
@@ -139,11 +140,7 @@ int ngx_http_write_filter(ngx_http_reque
         return NGX_AGAIN;
     }
 
-#if 1
     chain = ngx_write_chain(r->connection, ctx->out);
-#else
-    chain = ngx_write_chain(r->connection, ctx->out, flush);
-#endif
 
 #if (NGX_DEBUG_WRITE_FILTER)
     ngx_log_debug(r->connection->log, "write filter %x" _ chain);
--- a/src/os/unix/ngx_aio_read.c
+++ b/src/os/unix/ngx_aio_read.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 #include <ngx_aio.h>
 
 #if (HAVE_KQUEUE)
--- a/src/os/unix/ngx_aio_write.c
+++ b/src/os/unix/ngx_aio_write.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 #include <ngx_aio.h>
 
 #if (HAVE_KQUEUE)
@@ -29,6 +30,7 @@ ssize_t ngx_aio_write(ngx_connection_t *
 ngx_log_debug(ev->log, "aio: ev->ready: %d" _ ev->ready);
 ngx_log_debug(ev->log, "aio: aiocb: %08x" _ &ev->aiocb);
 
+#if 0
     if (ev->timedout) {
         ngx_set_socket_errno(NGX_ETIMEDOUT);
         ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_write() timed out");
@@ -46,6 +48,7 @@ ngx_log_debug(ev->log, "aio: aiocb: %08x
 
         ev->ready = 1;
     }
+#endif
 
     first = 0;
 
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -22,9 +22,22 @@
 #include <osreldate.h>
 
 
-#define  QD_FMT   "%qd"
-#define  QX_FMT   "%qx"
-#define  OFF_FMT  "%qd"
+/* STUB */
+#define  QD_FMT   "%lld"
+#define  QX_FMT   "%llx"
+/**/
+
+#if (i386)
+#define  OFF_FMT    "%lld"
+#define  SIZE_FMT   "%d"
+#define  SIZEX_FMT  "%x"
+#else
+#define  OFF_FMT    "%ld"
+#define  SIZE_FMT   "%ld"
+#define  SIZEX_FMT  "%lx"
+#endif
+
+#define  PID_FMT  "%d"
 
 
 #ifndef HAVE_SELECT
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -15,7 +15,8 @@
 
    Until FreeBSD 4.5 the turning TCP_NOPUSH off does not not flush
    the pending data that less than MSS and the data sent with 5 second delay.
-   So we use TCP_NOPUSH on FreeBSD 4.5+ only.
+   So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection
+   is not needed not keepalive.
 */
 
 
@@ -23,7 +24,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 {
     int              rc, eintr, tcp_nopush;
     char            *prev;
-    size_t           hsize, size;
+    ssize_t          hsize, size;
     off_t            sent;
     struct iovec    *iov;
     struct sf_hdtr   hdtr;
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -29,14 +29,11 @@
 #include <netdb.h>
 
 
-typedef unsigned int    u_int;
-typedef unsigned short  u_short;
-typedef unsigned char   u_char;
 
-
-#define  QD_FMT         "%qd"
-#define  QX_FMT         "%qx"
-#define  OFF_FMT        "%qd"
+#define  QD_FMT   "%qd"
+#define  QX_FMT   "%qx"
+#define  OFF_FMT  "%qd"
+#define  PID_FMT  "%d"
 
 
 #ifndef HAVE_SELECT
@@ -63,7 +60,7 @@ typedef unsigned char   u_char;
 
 
 #ifndef HAVE_FIONBIO
-#define HAVE_FIONBIO   1         
+#define HAVE_FIONBIO   1
 #endif
 
 
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 
 
 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
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 
 
 static int ngx_unix_recv_error(ngx_event_t *rev, ngx_err_t err);
--- a/src/os/unix/ngx_socket.c
+++ b/src/os/unix/ngx_socket.c
@@ -55,8 +55,7 @@ int ngx_tcp_push(ngx_socket_t s)
                       (const void *) &tcp_nopush, sizeof(int));
 }
 
-#else 
-
+#else
 
 int ngx_tcp_nopush(ngx_socket_t s)
 {
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -30,6 +30,7 @@ typedef uint32_t  u_int32_t;
 #define  QD_FMT   "%lld"
 #define  QX_FMT   "%llx"
 #define  OFF_FMT  "%lld"
+#define  PID_FMT  "%ld"
 
 
 #ifndef HAVE_SELECT
@@ -62,7 +63,7 @@ typedef uint32_t  u_int32_t;
 
 
 #ifndef HAVE_FIONBIO
-#define HAVE_FIONBIO   1         
+#define HAVE_FIONBIO   1
 #endif
 
 
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -6,15 +6,14 @@
 ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in)
 {
     char            *prev;
-    size_t           size;
-    ssize_t          n;
+    ssize_t          n, size;
     off_t            sent;
     struct iovec    *iov;
     ngx_err_t        err;
-    ngx_array_t      io;
+    ngx_array_t      iovecs;
     ngx_chain_t     *ce;
 
-    ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR);
+    ngx_init_array(iovecs, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR);
 
     prev = NULL;
     iov = NULL;
@@ -27,14 +26,14 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
             prev = ce->hunk->last;
 
         } else {
-            ngx_test_null(iov, ngx_push_array(&io), NGX_CHAIN_ERROR);
+            ngx_test_null(iov, ngx_push_array(&iovecs), NGX_CHAIN_ERROR);
             iov->iov_base = ce->hunk->pos;
             iov->iov_len = ce->hunk->last - ce->hunk->pos;
             prev = ce->hunk->last;
         }
     }
 
-    n = writev(c->fd, (struct iovec *) io.elts, io.nelts);
+    n = writev(c->fd, iovecs.elts, iovecs.nelts);
 
     if (n == -1) {
         err = ngx_errno;
@@ -93,7 +92,7 @@ ngx_log_debug(c->log, "SIZE: %d" _ size)
         break;
     }
 
-    ngx_destroy_array(&io);
+    ngx_destroy_array(&iovecs);
 
     return ce;
 }
--- a/src/os/win32/ngx_errno.c
+++ b/src/os/win32/ngx_errno.c
@@ -9,9 +9,29 @@
 #include <ngx_core.h>
 
 
+ngx_str_t wsa_errors[] = {
+    ngx_string("Invalid argument"),                          /* 10022 */
+    ngx_null_string,                                         /* 10023 */
+    ngx_null_string,                                         /* 10024 */
+    ngx_null_string,                                         /* 10025 */
+    ngx_null_string,                                         /* 10026 */
+    ngx_null_string,                                         /* 10027 */
+    ngx_null_string,                                         /* 10028 */
+    ngx_null_string,                                         /* 10029 */
+    ngx_null_string,                                         /* 10030 */
+    ngx_null_string,                                         /* 10031 */
+    ngx_null_string,                                         /* 10032 */
+    ngx_null_string,                                         /* 10033 */
+    ngx_null_string,                                         /* 10034 */
+    ngx_string("Resource temporarily unavailable")           /* 10035 */
+};
+
+
 int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size)
 {
-    int len;
+    int        n;
+    u_int      len;
+    ngx_err_t  format_error;
 
     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                         | FORMAT_MESSAGE_IGNORE_INSERTS,
@@ -19,12 +39,28 @@ int ngx_strerror_r(ngx_err_t err, char *
                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                         errstr, size, NULL);
 
-    /* add WSA error messages */
+    if (len == 0) {
+        format_error = GetLastError();
+
+        if (format_error == ERROR_MR_MID_NOT_FOUND) {
+            n = err - WSABASEERR - 22;
+
+            if (n >= 0 && n < 14) {
+                len = wsa_errors[n].len;
 
-    if (len == 0) {
+                if (len) {
+                    if (len > size) {
+                        len = size;
+                    }
+
+                    ngx_memcpy(errstr, wsa_errors[n].data, len);
+                    return len;
+                }
+            }
+        }
 
         len = ngx_snprintf(errstr, size,
-                           "FormatMessage error:(%d)", GetLastError());
+                           "FormatMessage() error:(%d)", format_error);
         return len;
 
     }
--- a/src/os/win32/ngx_os_init.h
+++ b/src/os/win32/ngx_os_init.h
@@ -8,5 +8,7 @@
 
 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_ */
--- a/src/os/win32/ngx_socket.h
+++ b/src/os/win32/ngx_socket.h
@@ -16,6 +16,7 @@ typedef int     socklen_t;
 
 #define ngx_socket(af, type, proto, flags)                                    \
             WSASocket(af, type, proto, NULL, 0, flags)
+
 #define ngx_socket_n        "WSASocket()"
 
 int ngx_nonblocking(ngx_socket_t s);
@@ -36,4 +37,11 @@ extern LPFN_GETACCEPTEXSOCKADDRS  getacc
 extern LPFN_TRANSMITFILE          transmitfile;
 
 
+ngx_inline int ngx_tcp_push(s) {
+     return 0;
+}
+
+#define ngx_tcp_push_n        "tcp_push()"
+
+
 #endif /* _NGX_SOCKET_H_INCLUDED_ */
--- a/src/os/win32/ngx_types.h
+++ b/src/os/win32/ngx_types.h
@@ -19,6 +19,7 @@ typedef BY_HANDLE_FILE_INFORMATION  ngx_
 #define QD_FMT            "%I64d"
 #define QX_FMT            "%I64x"
 #define OFF_FMT           "%I64d"
+#define PID_FMT           "%d"
 
 
 #endif /* _NGX_TYPES_H_INCLUDED_ */
rename from src/os/win32/ngx_init.c
rename to src/os/win32/ngx_win32_init.c
--- a/src/os/win32/ngx_init.c
+++ b/src/os/win32/ngx_win32_init.c
@@ -2,15 +2,23 @@
 #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;
+int  ngx_inherited_nonblocking = 1;
 
 
 ngx_os_io_t ngx_os_io = {
     ngx_wsarecv,
     NULL,
     NULL,
-    NULL
+    ngx_wsasend_chain,
+    0
 };
 
 
@@ -26,7 +34,7 @@ static GUID tf_guid = WSAID_TRANSMITFILE
 
 int ngx_os_init(ngx_log_t *log)
 {
-    u_int            sp;
+    u_int            osviex;
     DWORD            bytes;
     SOCKET           s;
     WSADATA          wsd;
@@ -34,14 +42,14 @@ int ngx_os_init(ngx_log_t *log)
 
     /* get Windows version */
 
-    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+    ngx_memzero(&osvi, sizeof(OSVERSIONINFOEX));
     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
 
     osviex = GetVersionEx((OSVERSIONINFO *) &osvi);
 
     if (osviex == 0) {
         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-        if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0)
+        if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) {
             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                           "GetVersionEx() failed");
             return NGX_ERROR;
@@ -49,27 +57,36 @@ int ngx_os_init(ngx_log_t *log)
     }
 
     /*
-     *  Windows 95       1400
-     *  Windows 98       1410
-     *  Windows ME       1490
-     *  Windows NT 3.51  2351
-     *  Windows NT 4.0   2400
-     *  Windows 2000     2500
-     *  Windows XP       2501
-     *  Windows 2003     2502
+     *  Windows 95           140000
+     *  Windows 98           141000
+     *  Windows ME           149000
+     *  Windows NT 3.51      235100
+     *  Windows NT 4.0       240000
+     *  Windows NT 4.0 SP5   240050
+     *  Windows 2000         250000
+     *  Windows XP           250100
+     *  Windows 2003         250200
      */
 
-    ngx_win32_version = osvi.dwPlatformId * 1000
-                        + osvi.dwMajorVersion * 100
-                        + osvi.dwMinorVersion;
+    ngx_win32_version = osvi.dwPlatformId * 100000
+                        + osvi.dwMajorVersion * 10000
+                        + osvi.dwMinorVersion * 100;
 
     if (osviex) {
-        sp = osvi.wServicePackMajor * 100 + osvi.wServicePackMinor;
+        ngx_win32_version += osvi.wServicePackMajor * 10
+                             + osvi.wServicePackMinor;
 
         ngx_log_error(NGX_LOG_INFO, log, 0,
-                      "OS: %u build:%u, %s, SP:%u, suite:%x, type:%u",
+                      "OS: %u build:%u, %s, suite:%x, type:%u",
                       ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion,
-                      sp, osvi.wSuiteMask, osvi.wProductType);
+                      osvi.wReserved[0], osvi.wReserved[1]);
+
+#if 0
+        ngx_log_error(NGX_LOG_INFO, log, 0,
+                      "OS: %u build:%u, %s, suite:%x, type:%u",
+                      ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion,
+                      osvi.wSuiteMask, osvi.wProductType);
+#endif
 
     } else {
         ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %u build:%u, %s",
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_wsarecv.c
@@ -0,0 +1,90 @@
+
+#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;
+    WSABUF            wsabuf[1];
+    ngx_err_t         err;
+    ngx_event_t      *rev;
+    LPWSAOVERLAPPED   ovlp;
+
+    rev = c->read;
+    bytes = 0;
+
+    if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) && rev->ready) {
+        rev->ready = 0;
+
+        /* the overlapped WSARecv() completed */
+
+        if (ngx_event_flags & NGX_HAVE_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) {
+            err = ngx_socket_errno;
+            ngx_log_error(NGX_LOG_CRIT, c->log, err,
+                         "WSARecv() or WSAGetOverlappedResult() failed");
+
+            return NGX_ERROR;
+        }
+
+        return bytes;
+    }
+
+    if (ngx_event_flags & NGX_HAVE_AIO_EVENT) {
+        ovlp = (LPWSAOVERLAPPED) &c->read->ovlp;
+        ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+
+    } else {
+        ovlp = NULL;
+    }
+
+    wsabuf[0].buf = buf;
+    wsabuf[0].len = size;
+    flags = 0;
+
+    rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL);
+
+    ngx_log_debug(c->log, "WSARecv: %d:%d" _ rc _ bytes);
+
+    if (rc == -1) {
+        err = ngx_socket_errno;
+        if (err == WSA_IO_PENDING) {
+            return NGX_AGAIN;
+
+        } else if (err == WSAEWOULDBLOCK) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "WSARecv() EAGAIN");
+            return NGX_AGAIN;
+
+        } else {
+            ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSARecv() failed");
+            return NGX_ERROR;
+        }
+    }
+
+    if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
+
+        /*
+         * If a socket was bound with I/O completion port
+         * then GetQueuedCompletionStatus() would anyway return its status
+         * despite that WSARecv() was already completed.
+         */
+
+        return NGX_AGAIN;
+    }
+
+    return bytes;
+}
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -0,0 +1,181 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+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      *ce;
+    LPWSAOVERLAPPED   ovlp;
+
+#if 0
+
+iocp:
+    if ready
+       get result
+       update chain
+       return if done;
+    wsasend
+
+non-block
+    for ( ;; ) {
+       wsasend
+       if no again
+          update chain
+          return if done;
+    }
+
+
+    for ( ;; ) {
+
+        make buffers and limit data for both ovlp and nonblocked,
+                     configured in events module
+
+        if (iocp && ready) {
+            get result
+
+        } else {
+            if (file)
+                transmitfile
+            else
+                wsasend
+
+            if (iocp)
+                return chain
+            return chain if again
+            here is result
+        }
+
+        if (result)
+            update chain;
+            return chain if done
+        }
+    }
+
+
+#endif
+
+    wev = c->write;
+
+    if (((ngx_event_flags & NGX_HAVE_AIO_EVENT) && !wev->ready)
+        || ((ngx_event_flags & NGX_HAVE_AIO_EVENT) == 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 chain entries */
+        for (ce = in; ce; ce = ce->next) {
+
+            if (prev == ce->hunk->pos) {
+                wsabuf->len += ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
+
+            } else {
+                ngx_test_null(wsabuf, ngx_push_array(&wsabufs),
+                              NGX_CHAIN_ERROR);
+                wsabuf->buf = ce->hunk->pos;
+                wsabuf->len = ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
+            }
+        }
+
+        if (ngx_event_flags & NGX_HAVE_AIO_EVENT) {
+            ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
+            ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+
+        } else {
+            ovlp = NULL;
+        }
+
+        rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, ovlp, NULL);
+
+        if (rc == -1) {
+            err = ngx_errno;
+            if (err == WSA_IO_PENDING) {
+                sent = 0;
+
+            } else if (err == WSAEWOULDBLOCK) {
+                sent = 0;
+                ngx_log_error(NGX_LOG_INFO, c->log, err, "WSASend() EAGAIN");
+
+            } else {
+                ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSASend() failed");
+                return NGX_CHAIN_ERROR;
+            }
+
+        } else {
+
+            if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
+
+                /*
+                 * If a socket was bound with I/O completion port then
+                 * GetQueuedCompletionStatus() would anyway return its status
+                 * despite that WSASend() was already completed.
+                 */
+
+                sent = 0;
+            }
+        }
+
+    } else {
+        if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
+            wev->ready = 0;
+
+            /* the overlapped WSASend() completed */
+
+            if (wev->ovlp.error) {
+                ngx_log_error(NGX_LOG_ERR, c->log, wev->ovlp.error,
+                              "WSASend() failed");
+                return NGX_CHAIN_ERROR;
+            }
+
+            sent = wev->available;
+        }
+    }
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+    ngx_log_debug(c->log, "WSASend(): %d" _ sent);
+#endif
+
+    c->sent += sent;
+
+    for (ce = in; ce && sent > 0; ce = ce->next) {
+
+        size = ce->hunk->last - ce->hunk->pos;
+
+        if (sent >= size) {
+            sent -= size;
+
+            if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+                ce->hunk->pos = ce->hunk->last;
+            }
+
+            continue;
+        }
+
+        if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+            ce->hunk->pos += sent;
+        }
+
+        break;
+    }
+
+    ngx_destroy_array(&wsabufs);
+
+    return ce;
+}