changeset 3:34a521b1a148

nginx-0.0.1-2002-08-20-18:48:28 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 20 Aug 2002 14:48:28 +0000
parents ffffe1499bce
children c5f071d376e5
files src/core/nginx.c src/core/ngx_config.h src/core/ngx_connection.h src/core/ngx_hunk.c src/core/ngx_hunk.h src/core/ngx_listen.h src/core/ngx_log.h src/core/ngx_server.h src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_write.c src/http/modules/ngx_http_header_filter.c src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_event.c src/http/ngx_http_filter.c src/http/ngx_http_write_filter.c src/os/freebsd/ngx_os_thread.c src/os/freebsd/ngx_os_thread.h src/os/unix/freebsd/ngx_rfork_thread.c src/os/unix/freebsd/ngx_rfork_thread.h src/os/unix/freebsd/ngx_sendfile.c src/os/unix/ngx_errno.h src/os/unix/ngx_file.h src/os/unix/ngx_sendfile.c src/os/unix/ngx_sendfile.h src/os/unix/ngx_sendv.c src/os/unix/ngx_sendv.h src/os/unix/ngx_socket.h src/os/unix/ngx_stat.h src/os/unix/ngx_time.h src/os/unix/ngx_types.h src/os/win32/ngx_errno.h src/os/win32/ngx_file.h src/os/win32/ngx_sendfile.c src/os/win32/ngx_sendfile.h src/os/win32/ngx_socket.c src/os/win32/ngx_socket.h src/os/win32/ngx_stat.c src/os/win32/ngx_stat.h src/os/win32/ngx_time.h src/os/win32/ngx_types.h
diffstat 43 files changed, 905 insertions(+), 288 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -3,6 +3,8 @@
 
 #include <ngx_config.h>
 #include <ngx_string.h>
+#include <ngx_errno.h>
+#include <ngx_time.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
 #include <ngx_array.h>
@@ -16,80 +18,134 @@
 /* */
 
 
+static void ngx_open_listening_sockets(ngx_log_t *log);
 
+
+/* STUB */
 int ngx_max_conn = 512;
 
-ngx_pool_t   ngx_pool;
-ngx_log_t    ngx_log;
-ngx_server_t ngx_server;
+ngx_server_t  ngx_server;
+/* */
+
+ngx_log_t     ngx_log;
+ngx_pool_t   *ngx_pool;
 
 
-ngx_array_t ngx_listening_sockets;
+ngx_array_t  *ngx_listening_sockets;
 
 
 int main(int argc, char *const *argv)
 {
     int  i;
-    ngx_socket_t  s;
-    ngx_listen_t *ls;
 
-    int  reuseaddr = 1;
+    /* STUB */
+    ngx_log.log_level = NGX_LOG_DEBUG;
 
-    ngx_log.log_level = NGX_LOG_DEBUG;
-    ngx_pool.log = &ngx_log;
+    ngx_pool = ngx_create_pool(16 * 1024, &ngx_log);
+    /* */
 
     ngx_init_sockets(&ngx_log);
 
     /* TODO: read config */
 
+    ngx_test_null(ngx_listening_sockets,
+                  ngx_create_array(ngx_pool, 10, sizeof(ngx_listen_t)), 1);
+
     /* STUB */
     /* TODO: init chain of global modules (like ngx_http.c),
        they would init its modules and ngx_listening_sockets */
-    ngx_http_init();
-
-    /* for each listening socket */
-    ls = (ngx_listen_t *) ngx_listening_sockets.elts;
-    for (i = 0; i < ngx_listening_sockets.nelts; i++) {
-        s = socket(ls->family, ls->type, ls->protocol);
-        if (s == -1)
-            ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno,
-                          "nginx: socket %s falied", ls->addr_text);
-
-        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                       (const void *) &reuseaddr, sizeof(int)) == -1)
-            ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno,
-                         "nginx: setsockopt (SO_REUSEADDR) %s failed",
-                         ls->addr_text);
-
-        /* TODO: close on exit */
+    ngx_http_init(ngx_pool, &ngx_log);
 
-        if (ngx_nonblocking(s) == -1)
-            ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno,
-                          ngx_nonblocking_n " %s failed", ls->addr_text);
-
-        if (bind(s, (struct sockaddr *) ls->addr, ls->addr_len) == -1)
-            ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno,
-                         "bind to %s failed", ls->addr_text);
-
-        if (listen(s, ls->backlog) == -1)
-            ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno,
-                         "listen to %s failed", ls->addr_text);
-
-        /* TODO: deferred accept */
-
-        ls->fd = s;
-        ls->server = &ngx_http_server;
-        ls->log = &ngx_log;
-    }
+    ngx_open_listening_sockets(&ngx_log);
 
     /* TODO: daemon */
 
     /* TODO: fork */
 
-    /* TODO: events: init ngx_connections and listen slots */
+    ngx_pre_thread(ngx_listening_sockets, ngx_pool, &ngx_log);
 
     /* TODO: threads */
 
     /* STUB */
-    ngx_worker(&ls, 1, &ngx_pool, &ngx_log);
+    ngx_worker(&ngx_log);
 }
+
+static void 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;
+
+    reuseaddr = 1;
+
+    for (times = 10; times; times--) {
+         failed = 0;
+
+        /* for each listening socket */
+        ls = (ngx_listen_t *) ngx_listening_sockets->elts;
+        for (i = 0; i < ngx_listening_sockets->nelts; i++) {
+            if (ls[i].done)
+                continue;
+
+#if (WIN32)
+            s = WSASocket(ls[i].family, ls[i].type, ls[i].protocol, NULL, 0, 0);
+#else
+            s = socket(ls[i].family, ls[i].type, ls[i].protocol);
+#endif
+            if (s == -1)
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "nginx: socket %s falied", ls[i].addr_text);
+
+            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                           (const void *) &reuseaddr, sizeof(int)) == -1)
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "nginx: setsockopt (SO_REUSEADDR) %s failed",
+                              ls[i].addr_text);
+
+            /* TODO: close on exit */
+
+            if (ls[i].nonblocking) {
+                if (ngx_nonblocking(s) == -1)
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls[i].addr_text);
+            }
+
+            if (bind(s, (struct sockaddr *) ls[i].addr, ls[i].addr_len) == -1) {
+                err = ngx_socket_errno;
+                ngx_log_error(NGX_LOG_ALERT, log, err,
+                              "bind to %s failed", ls[i].addr_text);
+
+                if (err != NGX_EADDRINUSE)
+                    exit(1);
+
+                if (ngx_close_socket(s) == -1)
+                    ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %s failed",
+                                  ls[i].addr_text);
+
+                failed = 1;
+                continue;
+            }
+
+            if (listen(s, ls[i].backlog) == -1)
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "listen to %s failed", ls[i].addr_text);
+
+            /* TODO: deferred accept */
+
+            ls[i].fd = s;
+            ls[i].done = 1;
+        }
+
+        if (!failed)
+            break;
+
+        ngx_log_error(NGX_LOG_NOTICE, log, 0, "try to bind again after 500ms");
+        ngx_msleep(500);
+    }
+
+    if (failed)
+        ngx_log_error(NGX_LOG_EMERG, log, 0, "can't bind");
+}
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -28,6 +28,10 @@
 
 #define ngx_close_socket closesocket
 
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
 #ifndef HAVE_WIN32_TRANSMITPACKETS
 #define HAVE_WIN32_TRANSMITPACKETS  1
 #define HAVE_WIN32_TRANSMITFILE     0
@@ -88,6 +92,10 @@
 
 #include <osreldate.h>
 
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
 #if __FreeBSD_version >= 300007
 
 #ifndef HAVE_FREEBSD_SENDFILE
@@ -129,4 +137,13 @@
 #endif /* __FreeBSD__ */
 
 
+#ifdef __SOME_OS_TEMPLATE__
+
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
+#endif
+
+
 #endif /* _NGX_CONFIG_H_INCLUDED_ */
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -1,6 +1,7 @@
 #ifndef _NGX_CONNECTION_H_INCLUDED_
 #define _NGX_CONNECTION_H_INCLUDED_
 
+#include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
 #include <ngx_server.h>
@@ -21,14 +22,14 @@ struct ngx_connection_s {
 #endif
 
     ngx_log_t        *log;
+    int             (*handler)(ngx_connection_t *c);
     ngx_server_t     *server;
     ngx_server_t     *servers;
     ngx_pool_t       *pool;
 };
 
 
-/*
-
+#if 0
 cached file
     int      fd;       -2 unused, -1 closed (but read or mmaped), >=0 open
     char    *name;
@@ -49,6 +50,6 @@ cached file
 
 EV_VNODE        should notify by some signal if diretory tree is changed
                 or stat if aged >= N seconds (big enough)
-*/
+#endif
 
 #endif /* _NGX_CONNECTION_H_INCLUDED_ */
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -1,5 +1,5 @@
 
-#include <ngx_types.h>
+#include <ngx_file.h>
 #include <ngx_hunk.h>
 
 
--- a/src/core/ngx_hunk.h
+++ b/src/core/ngx_hunk.h
@@ -4,6 +4,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_file.h>
 #include <ngx_alloc.h>
 
 
--- a/src/core/ngx_listen.h
+++ b/src/core/ngx_listen.h
@@ -2,8 +2,40 @@
 #define _NGX_LISTEN_H_INCLUDED_
 
 
-ngx_socket_t ngx_listen(struct sockaddr *addr, int backlog,
-                        ngx_log_t *log, char *addr_text);
+#include <ngx_config.h>
+#include <ngx_log.h>
+#include <ngx_types.h>
+#include <ngx_socket.h>
+#include <ngx_connection.h>
+
+typedef struct {
+    ngx_socket_t  fd;
+
+    void         *addr;
+    size_t        addr_len;
+    char         *addr_text;
+
+    int           family;
+    int           type;
+    int           protocol;
+
+    ngx_log_t    *log;
+    void         *server;
+    int         (*handler)(ngx_connection_t *c);
+
+    int           backlog;
+
+    unsigned      done:1;
+    unsigned      close:1;
+    unsigned      nonblocking:1;
+#if 0
+    unsigned      overlapped:1;
+#endif
+    unsigned      shared:1;          /* shared between threads or processes */
+#if (HAVE_DEFERRED_ACCEPT)
+    unsigned      deferred_accept:1;
+#endif
+} ngx_listen_t;
 
 
 #endif /* _NGX_LISTEN_H_INCLUDED_ */
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -16,6 +16,21 @@ typedef enum {
 } ngx_log_e;
 
 /*
+    "[%time] [%level] %pid#%tid: %message:(%errno)%errstr, while %action"
+        " %peer and processing %context"
+
+    message = "recv() failed";
+    errno = 32;
+    action = "reading request headers from client";
+    peer = "192.168.1.1";
+    context = "URL /"
+
+    "[2002/08/20 12:00:00] [error] 412#3: recv() failed:(32)Broken pipe,"
+    " while reading request headers from client 192.168.1.1"
+    " and processing URL /"
+
+
+    OLD:
     "... while ", action = "reading client request headers"
     "... while reading client request headers"
     "... while ", action = "reading client request headers"
--- a/src/core/ngx_server.h
+++ b/src/core/ngx_server.h
@@ -14,28 +14,4 @@ typedef struct {
 } ngx_server_t;
 
 
-typedef struct {
-    ngx_socket_t  fd;
-
-    ngx_log_t    *log;
-    void         *server;
-
-    int           family;
-    int           type;
-    int           protocol;
-
-    void         *addr;
-    size_t        addr_len;
-    char         *addr_text;
-
-    int           backlog;
-
-    unsigned      non_blocking:1;
-    unsigned      shared:1;          /* shared between threads or processes */
-#if (HAVE_DEFERRED_ACCEPT)
-    unsigned      deferred_accept:1;
-#endif
-} ngx_listen_t;
-
-
 #endif /* _NGX_SERVER_H_INCLUDED_ */
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -3,6 +3,7 @@
 #include <ngx_types.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
+#include <ngx_listen.h>
 #include <ngx_connection.h>
 #include <ngx_event.h>
 #include <ngx_event_accept.h>
@@ -18,7 +19,7 @@ ngx_event_t         *ngx_read_events, *n
 
 #if !(USE_KQUEUE)
 
-#if 1
+#if 0
 ngx_event_type_e     ngx_event_type = NGX_SELECT_EVENT;
 #else
 ngx_event_type_e     ngx_event_type = NGX_KQUEUE_EVENT;
@@ -40,9 +41,10 @@ static void (*ngx_event_init[]) (int max
 #endif /* USE_KQUEUE */
 
 
-void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log)
+void ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log)
 {
     int  i, fd;
+    ngx_listen_t *s;
 
     /* per group */
     int max_connections = 512;
@@ -55,18 +57,21 @@ void ngx_worker(ngx_listen_t *sock, int 
                                                      * max_connections, log);
 
     /* for each listening socket */
-    for (i = 0; i < n; i++) {
-        fd = sock[i].fd;
+    s = (ngx_listen_t *) ls->elts;
+    for (i = 0; i < ls->nelts; i++) {
+
+        fd = s[i].fd;
 
         ngx_memzero(&ngx_read_events[fd], sizeof(ngx_event_t));
         ngx_memzero(&ngx_write_events[fd], sizeof(ngx_event_t));
         ngx_memzero(&ngx_connections[fd], sizeof(ngx_connection_t));
 
         ngx_connections[fd].fd = fd;
-        ngx_connections[fd].server = sock[i].server;
+        ngx_connections[fd].server = s[i].server;
         ngx_connections[fd].read = (void *) &ngx_read_events[fd].data;
+        ngx_connections[fd].handler = s[i].handler;
         ngx_read_events[fd].data = &ngx_connections[fd];
-        ngx_read_events[fd].log = ngx_connections[fd].log = sock[i].log;
+        ngx_read_events[fd].log = ngx_connections[fd].log = s[i].log;
         ngx_read_events[fd].data = &ngx_connections[fd];
         ngx_read_events[fd].event_handler = &ngx_event_accept;
         ngx_read_events[fd].listening = 1;
@@ -74,11 +79,14 @@ void ngx_worker(ngx_listen_t *sock, int 
         ngx_read_events[fd].available = 0;
 
 #if (HAVE_DEFERRED_ACCEPT)
-        ngx_read_events[fd].accept_filter = sock->accept_filter;
+        ngx_read_events[fd].accept_filter = s[i].accept_filter;
 #endif
         ngx_add_event(&ngx_read_events[fd], NGX_READ_EVENT, 0);
     }
+}
 
+void ngx_worker(ngx_log_t *log)
+{
     while (1) {
         ngx_log_debug(log, "ngx_worker cycle");
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -4,7 +4,10 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_socket.h>
 #include <ngx_log.h>
+#include <ngx_alloc.h>
+#include <ngx_array.h>
 
 typedef struct ngx_event_s       ngx_event_t;
 
@@ -76,13 +79,12 @@ typedef struct {
 */
 } ngx_event_actions_t;
 
+
 /*
-
 NGX_LEVEL_EVENT (default)  select, poll, kqueue
                                 requires to read whole data
 NGX_ONESHOT_EVENT          kqueue
 NGX_CLEAR_EVENT            kqueue
-
 */
 
 #if (HAVE_KQUEUE)
@@ -135,7 +137,8 @@ extern ngx_event_type_e      ngx_event_t
 #endif
 
 
-void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log);
+void ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log);
+void ngx_worker(ngx_log_t *log);
 
 
 #endif /* _NGX_EVENT_H_INCLUDED_ */
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -38,6 +38,12 @@ int ngx_event_accept(ngx_event_t *ev)
  
         ngx_log_debug(ev->log, "ngx_event_accept: accepted socket: %d" _ s);
 
+#if !(HAVE_INHERITED_NONBLOCK)
+        if (ngx_nonblocking(s) == -1)
+            ngx_log_error(NGX_LOG_ERR, log, ngx_socket_errno,
+                          ngx_nonblocking_n "failed");
+#endif
+
         ngx_memzero(&ngx_read_events[s], sizeof(ngx_event_t));
         ngx_memzero(&ngx_write_events[s], sizeof(ngx_event_t));
         ngx_memzero(&ngx_connections[s], sizeof(ngx_connection_t));
@@ -69,7 +75,7 @@ int ngx_event_accept(ngx_event_t *ev)
             ngx_read_events[s].ready = 1;
 #endif
 
-        cn->server->handler(&ngx_connections[s]);
+        cn->handler(&ngx_connections[s]);
 
 #if (HAVE_KQUEUE)
 #if !(USE_KQUEUE)
--- a/src/event/ngx_event_write.c
+++ b/src/event/ngx_event_write.c
@@ -99,6 +99,7 @@ ngx_chain_t *ngx_event_write(ngx_connect
             } else {
                 rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts,
                                header->nelts, (size_t *) &sent);
+                ngx_log_debug(cn->log, "sendv: %d" _ sent);
             }
 #if (HAVE_MAX_SENDFILE_IOVEC)
         }
@@ -110,14 +111,26 @@ ngx_chain_t *ngx_event_write(ngx_connect
 
         flush -= sent;
 
-        for (ch = in; ch && !(ch->hunk->type & NGX_HUNK_LAST); ch = ch->next) {
+        for (ch = in; ch; ch = ch->next) {
             if (sent >= ch->hunk->last.file - ch->hunk->pos.file) {
                 sent -= ch->hunk->last.file - ch->hunk->pos.file;
                 ch->hunk->last.file = ch->hunk->pos.file;
-                    continue;
+
+                ngx_log_debug(cn->log, "event write: %qx 0" _
+                              ch->hunk->pos.file);
+
+                if (ch->hunk->type & NGX_HUNK_LAST)
+                   break;
+
+                continue;
             }
 
             ch->hunk->pos.file += sent;
+
+            ngx_log_debug(cn->log, "event write: %qx %qd" _
+                          ch->hunk->pos.file _
+                          ch->hunk->last.file - ch->hunk->pos.file);
+
             break;
         }
 
--- a/src/http/modules/ngx_http_header_filter.c
+++ b/src/http/modules/ngx_http_header_filter.c
@@ -1,3 +1,10 @@
+
+#include <nginx.h>
+
+#include <ngx_config.h>
+#include <ngx_string.h>
+#include <ngx_hunk.h>
+#include <ngx_http.h>
 
 
 typedef struct {
@@ -18,44 +25,60 @@ int ngx_http_header_filter(ngx_http_requ
     ngx_hunk_t   *h;
     ngx_chain_t  *ch;
 
-    ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64), NGX_HTTP_FILTER_ERROR);
+    ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64),
+                  /* STUB */
+                  -1);
+/*
+                  NGX_HTTP_FILTER_ERROR);
+*/
 
-    status = r->headers_out->status - GX_HTTP_OK;
+    status = r->headers_out->status - NGX_HTTP_OK;
 
-    ngx_memcpy(h->pos.mem, "HTTP/1.0 ", 9);
-    h->pos.mem += 9;
-    ngx_memcpy(h->pos.mem, http_codes[status].line, http_codes[status].len);
-    h->pos.mem += http_codes[status].len;
-    *(h->pos.mem++) = CR; *(h->pos.mem++) = LF;
+    ngx_memcpy(h->last.mem, "HTTP/1.0 ", 9);
+    h->last.mem += 9;
+    ngx_memcpy(h->last.mem, http_codes[status].line, http_codes[status].len);
+    h->last.mem += http_codes[status].len;
+    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
 
-    memcpy(h->pos.mem, "Date: ", 6);
-    h->pos.mem += 6;
-    h->pos.mem += ngx_http_get_time(h->pos.mem, time());
-    *(h->pos.mem++) = CR; *(h->pos.mem++) = LF;
+/*
+    memcpy(h->last.mem, "Date: ", 6);
+    h->last.mem += 6;
+    h->last.mem += ngx_http_get_time(h->last.mem, time(NULL));
+    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+*/
 
     /* 2^64 is 20 characters  */
     if (r->headers_out->content_length)
-        h->pos.mem += ngx_snprintf(h->pos.mem, 49, "Content-Length: %d" CRLF,
-                                   r->headers_out->content_length);
+        h->last.mem += ngx_snprintf(h->last.mem, 49, "Content-Length: %d" CRLF,
+                                    r->headers_out->content_length);
 
     /* check */
 
-    memcpy(h->pos.mem, "Server: ", 8);
-    h->pos.mem += 8;
+    memcpy(h->last.mem, "Server: ", 8);
+    h->last.mem += 8;
     if (r->headers_out->server) {
-        h->pos.mem = ngx_cpystrn(h->pos.mem, r->headers_out->server,
-                                 h->last.mem - h->pos.mem);
-        check space
+        h->last.mem = ngx_cpystrn(h->last.mem, r->headers_out->server,
+                                  h->end - h->last.mem);
+
+        /* check space */
+
     } else {
-        ngx_memcpy(h->pos.mem, NGINX_VER, sizeof(NGINX_VER));
-        h->pos.mem += sizeof(NGINX_VER);
+        ngx_memcpy(h->last.mem, NGINX_VER, sizeof(NGINX_VER));
+        h->last.mem += sizeof(NGINX_VER);
     }
-    *(h->pos.mem++) = CR; *(h->pos.mem++) = LF;
+    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+
+    /* end of HTTP header */
+    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
 
     ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)),
+                  /* STUB */
+                  -1);
+/*
                   NGX_HTTP_FILTER_ERROR);
+*/
 
-    ch->hunk = in->hunk;
+    ch->hunk = h;
     ch->next = NULL;
 
     return ngx_http_write_filter(r, ch);
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -1,55 +1,114 @@
 
 #include <ngx_config.h>
+#include <ngx_string.h>
+#include <ngx_file.h>
+#include <ngx_hunk.h>
+#include <ngx_http.h>
 
-#include <ngx_strings.h>
-#include <ngx_open.h>
-#include <ngx_stat.h>
+ngx_http_module_t  ngx_http_static_module;
+
+
+#if 0
+/* STUB */
+static ngx_http_static_ctx_t module_ctx;
 
-#include <ngx_http.h>
+void ngx_http_static_init()
+{
+     module_ctx.out = NULL;
+
+     ngx_http_static_module.ctx = &module_ctx;
+}
+/* */
+#endif
+
 
 int ngx_http_static_handler(ngx_http_request_t *r)
 {
-    int          index_len, err, i;
-    char        *name, *loc, *file
-    ngx_file_t   fd;
+    int rc;
+    ngx_hunk_t  *h;
+    ngx_chain_t *ch;
 
-    ngx_http_header_out_t  out;
+/*
     ngx_http_event_static_handler_loc_conf_t  *cf;
 
     cf = (ngx_http_event_static_handler_loc_conf_t *)
              ngx_get_module_loc_conf(r, &ngx_http_event_static_handler_module);
 
-    ngx_assert(r->fd, return NGX_HTTP_INTERNAL_SERVER_ERROR,
-               r->connection->log, "ngx_http_static_handler: no file");
+*/
+
+    r->fd = ngx_open_file(r->filename, NGX_FILE_RDONLY);
+    if (r->fd == -1) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+                      "ngx_http_static_handler: "
+                      ngx_open_file_n " %s failed", r->filename);
+        /* STUB */
+        return -1;
+    }
 
-    out.status = NGX_HTTP_OK;
-    out.content_length = r->stat.sb_size;
-    out.last_modified = r->stat.sb_mtime;
+    if (ngx_stat_fd(r->fd, &r->file_info) == -1) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+                      "ngx_http_static_handler: "
+                      ngx_stat_fd_n " %s failed", r->filename);
+        /* STUB */
+        return -1;
+    }
 
-    /* */
-    out.content_type = "text/html";
+    r->headers_out->status = NGX_HTTP_OK;
+    r->headers_out->content_length = ngx_file_size(r->file_info);
+/*
+    r->headers_out->last_modified = ngx_file_mtime(r->file_info);
+*/
 
-    rc = ngx_send_http_header(&out);
+    /* STUB */
+    r->headers_out->content_type = "text/html";
+
+    /* STUB */
+    rc = ngx_http_header_filter(r);
+/*
+    rc = ngx_send_http_header(r->headers_out);
+*/
     if (r->header_only)
         return rc;
 
-    /* NGX_HTTP_INTERNAL_SERVER_ERROR is too late */
+    /* TODO: NGX_HTTP_INTERNAL_SERVER_ERROR is too late */
 
+    /* STUB */
+    ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64),
+                  /* STUB */
+                  -1);
+/*
     ngx_test_null(h, ngx_create_hunk(r->pool), NGX_HTTP_INTERNAL_SERVER_ERROR);
-    h->type = NGX_HUNK_FILE | NGX_HUNK_LAST;
+*/
+    h->type = NGX_HUNK_FILE|NGX_HUNK_LAST;
     h->fd = r->fd;
     h->pos.file = 0;
-    h->end.file = r->stat.sb_size;
+    h->last.file = ngx_file_size(r->file_info);
 
+    /* STUB */
+    ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)),
+                  /* STUB */
+                  -1);
+/*
+                  NGX_HTTP_FILTER_ERROR);
+*/
+
+/*
     ngx_test_null(ch, ngx_create_chain(r->pool),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
+*/
     ch->hunk = h;
     ch->next = NULL;
 
-    return ngx_http_filter(ch);
+    /* STUB */
+    rc = ngx_http_write_filter(r, ch);
+    ngx_log_debug(r->connection->log, "write_filter: %d" _ rc);
+    return rc;
+/*
+    return ngx_http_filter(r, ch);
+*/
 }
 
-/*
+#if 0
 
 static void *ngx_create_index_config()
 {
@@ -98,4 +157,4 @@ static void *ngx_set_index()
     *conf = cf;
 }
 
-*/
+#endif
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1,6 +1,10 @@
 
+#include <ngx_config.h>
+#include <ngx_string.h>
+#include <ngx_listen.h>
 #include <ngx_http.h>
 
+extern ngx_array_t *ngx_listening_sockets;
 
 /* STUB */
 
@@ -9,22 +13,25 @@ static char addr_text[22];
 
 static ngx_http_server_t ngx_http_server;
 
-int ngx_http_init(ngx_pool_t *pool)
+int ngx_http_init(ngx_pool_t *pool, ngx_log_t *log)
 {
     ngx_listen_t  *ls;
 
-    ngx_http_server.handler = ngx_http_init_connection;
+    ngx_http_server.buff_size = 1024;
+#if (WIN32)
+    ngx_http_server.doc_root = "html";
+#else
+    ngx_http_server.doc_root = "/home/is/work/xml/site-1.0.0/html";
+#endif
+    ngx_http_server.doc_root_len = strlen(ngx_http_server.doc_root) + 1;
 
-    ngx_http_server.buff_size = 1024;
-
-    ngx_http_server.doc_root = "/home/is/work/xml/site-1.0.0/html";
-    ngx_http_server.doc_root_len = strlen(server.doc_root);
+    ngx_http_write_filter_init();
 
     ls = ngx_push_array(ngx_listening_sockets);
-    ngx_memzero(ls, sizeof(nxg_listen_t));
+    ngx_memzero(ls, sizeof(ngx_listen_t));
 
     addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = inet_addr(optarg)
+    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
     addr.sin_port = htons(8000);
 
     ngx_snprintf(ngx_cpystrn(addr_text, inet_ntoa(addr.sin_addr), 16),
@@ -32,13 +39,17 @@ int ngx_http_init(ngx_pool_t *pool)
 
     ls->family = AF_INET;
     ls->type = SOCK_STREAM;
-    ls->protocol = 0;
+    ls->protocol = IPPROTO_IP;
     ls->addr = &addr;
-    ls->addr_len = sizeof(sockaddr_in);
-    ls->text = &addr_text;
+    ls->addr_len = sizeof(struct sockaddr_in);
+    ls->addr_text = addr_text;
     ls->backlog = -1;
     ls->nonblocking = 1;
 
+    ls->handler = ngx_http_init_connection;
+    ls->server = &ngx_http_server;
+    ls->log = log;
+
     return 1;
 }
 
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -4,6 +4,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_file.h>
 #include <ngx_connection.h>
 
 
@@ -22,6 +23,7 @@
 #define NGX_OK                          0
 
 #define NGX_HTTP_OK                     200
+#define NGX_HTTP_MOVED_PERMANENTLY      302
 #define NGX_HTTP_NOT_FOUND              404
 #define NGX_HTTP_INTERNAL_SERVER_ERROR  503
 
@@ -38,8 +40,9 @@ typedef struct {
 #define ngx_get_module_ctx(r, module)  (module)->ctx
 
 typedef struct {
-    char  *doc_root;
-    int    doc_root_len;
+    char   *doc_root;
+    size_t  doc_root_len;
+    size_t  buff_size;
 } ngx_http_server_t;
 
 typedef struct {
@@ -52,23 +55,30 @@ typedef struct {
 typedef struct {
     int     status;
     int     connection;
-    size_t  content_length;
+    off_t   content_length;
+    char   *location;
     char   *content_type;
     char   *charset;
     char   *etag;
+    char   *server;
     time_t  date;
     time_t  last_modified;
-} ngx_http_header_out_t;
+} ngx_http_headers_out_t;
 
 typedef struct ngx_http_request_s ngx_http_request_t;
 
 struct ngx_http_request_s {
     char  *filename;
     char  *location;
+    ngx_file_t  fd;
+
+    ngx_http_headers_out_t *headers_out;
 
     int    filename_len;
     int  (*handler)(ngx_http_request_t *r);
 
+    ngx_file_info_t file_info;
+
     int    method;
 
     int    http_version;
@@ -83,7 +93,7 @@ struct ngx_http_request_s {
     ngx_buff_t  *buff;
     ngx_pool_t  *pool;
 
-    /* internal */
+    unsigned  header_only:1;
     unsigned  unusual_uri:1;
     unsigned  complex_uri:1;
 
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -1,5 +1,6 @@
 
 #include <ngx_config.h>
+#include <ngx_file.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
 #include <ngx_hunk.h>
@@ -26,6 +27,9 @@ static int ngx_process_http_request(ngx_
 
 static int ngx_http_close_request(ngx_event_t *ev);
 
+/* STUB */
+static int ngx_http_writer(ngx_event_t *ev);
+
 /*
     returns
     -1 if error
@@ -62,6 +66,7 @@ int ngx_http_init_connection(ngx_connect
 int ngx_http_init_request(ngx_event_t *ev)
 {
     ngx_connection_t   *c = (ngx_connection_t *) ev->data;
+    ngx_http_server_t  *srv = (ngx_http_server_t *) c->server;
     ngx_http_request_t *r;
 
     ngx_log_debug(ev->log, "ngx_http_init_request: entered");
@@ -71,14 +76,14 @@ int ngx_http_init_request(ngx_event_t *e
 
     c->data = r;
     r->connection = c;
+    r->server = srv;
 
     ngx_test_null(r->pool, ngx_create_pool(16384, ev->log), -1);
     ngx_test_null(r->buff, ngx_palloc(r->pool, sizeof(ngx_buff_t)), -1);
-    ngx_test_null(r->buff->buff,
-                  ngx_pcalloc(r->pool, sizeof(c->server->buff_size)), -1);
+    ngx_test_null(r->buff->buff, ngx_palloc(r->pool, srv->buff_size), -1);
 
     r->buff->pos = r->buff->last = r->buff->buff;
-    r->buff->end = r->buff->buff + c->server->buff_size;
+    r->buff->end = r->buff->buff + srv->buff_size;
 
     r->state_handler = ngx_process_http_request_line;
 
@@ -180,11 +185,15 @@ static int ngx_process_http_request_head
 
 static int ngx_process_http_request(ngx_http_request_t *r)
 {
-    int   err;
+    int   err, rc;
     char *name, *loc, *file;
 
     ngx_log_debug(r->connection->log, "HTTP request");
 
+    ngx_test_null(r->headers_out,
+                  ngx_pcalloc(r->pool, sizeof(ngx_http_headers_out_t)),
+                  ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR));
+
     if (*(r->uri_end - 1) == '/') {
         r->handler = NGX_HTTP_DIRECTORY_HANDLER;
         return NGX_OK;
@@ -204,14 +213,11 @@ static int ngx_process_http_request(ngx_
 
     ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->filename);
 
-}
-#if 0
-
-    if (ngx_stat(r->filename, &r->stat) == -1) {
+    if (ngx_file_type(r->filename, &r->file_info) == -1) {
         err = ngx_errno;
-        ngx_log_error(GX_LOG_ERR, r->connection->log, err,
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
                      "ngx_process_http_request: "
-                      ngx_stat_n " %s failed", r->filename);
+                      ngx_file_type_n " %s failed", r->filename);
 
         if (err == NGX_ENOENT)
             return ngx_http_error(r, NGX_HTTP_NOT_FOUND);
@@ -219,29 +225,50 @@ static int ngx_process_http_request(ngx_
             return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
-    if (ngx_is_dir(r->stat)) {
+    if (ngx_is_dir(r->file_info)) {
+        ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->filename);
         *file++ = '/';
         *file = '\0';
         r->headers_out->location = r->location;
         return ngx_http_redirect(r, NGX_HTTP_MOVED_PERMANENTLY);
     }
 
-    r->stat_valid = 1;
+    /* STUB */
+    rc =  ngx_http_static_handler(r);
+    if (rc == 0) {
+        r->connection->write->event_handler = ngx_http_writer;
+        ngx_add_event(r->connection->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT);
+    }
+    return rc;
+
     r->handler = NGX_HTTP_STATIC_HANDLER;
     return NGX_OK;
 }
 
+
+static int ngx_http_writer(ngx_event_t *ev)
+{
+    int rc;
+    ngx_connection_t   *c = (ngx_connection_t *) ev->data;
+    ngx_http_request_t *r = (ngx_http_request_t *) c->data;
+
+    rc = ngx_http_write_filter(r, NULL);
+    ngx_log_debug(r->connection->log, "write_filter: %d" _ rc);
+    return rc;
+}
+
 static int ngx_http_handler(ngx_http_request_t *r, int handler)
 {
     if (handler == NGX_HTTP_STATIC_HANDLER) 
         return ngx_http_static_handler(r);
 
+#if 0
     elsif (handler == NGX_HTTP_DIRECTORY_HANDLER) 
         return ngx_http_index_handler(r);
+#endif
 
     return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
 }
-#endif
 
 static int ngx_http_redirect(ngx_http_request_t *r, int redirect)
 {
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_filter.c
@@ -0,0 +1,239 @@
+
+
+
+ngx_http_module_t  ngx_http_filter_module;
+
+
+/* STUB */
+static ngx_http_filter_ctx_t module_ctx;
+
+void ngx_http_filter_init()
+{
+     module_ctx.buffer_output = 10240;
+     module_ctx.out = NULL;
+     module_ctx.next_filter = ngx_http_write_filter;
+
+     ngx_http_filter_module.ctx = &module_ctx;
+}
+/* */
+
+
+/*
+int ngx_http_filter(ngx_http_request_t *r, ngx_chain_t *in)
+*/
+
+/*
+    flags NGX_HUNK_RECYCLED, NGX_HUNK_FLUSH, NGX_HUNK_LAST
+*/
+
+int ngx_http_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
+{
+    enum { NO = 0, COPY, FILE } temp;
+
+    ngx_http_write_ctx_t  *ctx;
+
+    ctx = (ngx_http_filter_ctx_t *)
+                              ngx_get_module_ctx(r->main ? r->main : r,
+                                                      &ngx_http_filter_module);
+
+
+
+    if (hunk == NULL)
+        if (in == NULL)
+            next_filter(NULL);
+        else
+
+
+
+
+
+    if (hunk != NULL)
+        if (in == NULL)
+            if (temp == NO)
+                fast_chain = hunk;
+                next_filter(fast_chain);
+            else
+                if (ctx->hunk busy)
+                    add hunk to ctx->in
+                    next_filter(NULL);
+                else
+                    if (hunk > ctx->hunk)
+                        copy hunk part to ctx->hunk
+                        add hunk to ctx->in
+                    else
+                        copy hunk to ctx->hunk
+                    fast_chain = ctx->hunk
+                    next_filter(fast_chain);
+
+        else /* in != NULL */
+           add hunk to ctx->in
+
+
+
+
+
+            
+
+
+
+    if ((r->filter & NGX_FILT_NEED_IN_MEMORY) && (hunk->type & NGX_HUNK_FILE))
+        temp = FILE;
+
+    else if ((r->filter & NGX_FILT_NEED_TEMP)
+             && (hunk->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP))
+        temp = COPY;
+
+    if (temp) {
+        size = hunk->last.mem - hunk->pos.mem;
+
+        if (hunk->type & NGX_HUNK_LAST) {
+            if (size > ctx->hunk_size)
+                size = ctx->hunk_size;
+
+            hunk_size = size;
+
+        } else {
+            hunk_size = ctx->hunk_size;
+        }
+    }
+
+    if (!ctx->hunk)
+        ngx_test_null(ctx->hunk, ngx_create_temp_hunk(hunk_size), ...);
+
+    if (temp == FILE) {
+        n = ngx_read_file(hunk->fd, ctx->hunk->pos.mem, size);
+
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+                          ngx_read_file_n " failed for client");
+            return -1;
+
+        } else {
+            ngx_assert((n == size), /* void */ ; ,
+                       r->connection->log, 0,
+                       ngx_read_file_n " reads only %d of %d for client",
+                       n, size);
+        }
+
+        hunk->pos.mem += n;
+        ctx->hunk->last.mem += n;
+
+    } else if (temp == COPY) {
+        ngx_memcpy(ctx->hunk->pos.mem, hunk->pos.mem, size);
+
+        hunk->pos.mem += size;
+        ctx->hunk->last.mem += size;
+    }
+
+
+
+
+
+
+    /* if no hunk is passed and there is no our hunk
+       or our hunk is still busy then call next filter */
+    if (hunk == NULL
+        && (ctx->hunk == NULL
+            || ((ctx->hunk != NULL)
+                && (ctx->hunk->pos.mem < ctx->hunk->last.mem))
+           )
+       )
+        ctx->next_filter(r, NULL);
+    }
+
+    /* hunk != NULL || ctx->hunk->pos.mem == ctx->hunk->last.mem */
+
+    /* find last link of saved chain */
+    prev = &ctx->out;
+    for (ch = ctx->out; ch; ch = ch->next) {
+        prev = &ch->next;
+    }
+
+    if hunk
+        if need our hunk - alloc it and add to our queue
+        else add hunk to our queue
+
+/*
+        size += ch->hunk->last.file - ch->hunk->pos.file;
+
+        ngx_log_debug(r->connection->log, "old chunk: %x %qx %qd" _
+                      ch->hunk->type _ ch->hunk->pos.file _
+                      ch->hunk->last.file - ch->hunk->pos.file);
+
+        if (ch->hunk->type & NGX_HUNK_FLUSH)
+            flush = size;
+
+        if (ch->hunk->type & NGX_HUNK_LAST)
+            last = 1;
+    }
+*/
+
+    /* add new chain to existent one */
+    for (/* void */; in; in = in->next) {
+        ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)),
+                      NGX_HTTP_FILTER_ERROR);
+
+        ch->hunk = h;
+        ch->next = NULL;
+        *prev = ch;
+        prev = &ch->next;
+        size += ch->hunk->last.file - ch->hunk->pos.file;
+
+        ngx_log_debug(r->connection->log, "new chunk: %x %qx %qd" _
+                      ch->hunk->type _ ch->hunk->pos.file _
+                      ch->hunk->last.file - ch->hunk->pos.file);
+
+        if (ch->hunk->type & NGX_HUNK_FLUSH)
+            flush = size;
+
+        if (ch->hunk->type & NGX_HUNK_LAST)
+            last = 1;
+    }
+
+
+
+
+
+/*
+    !(HAVE_SENDFILE) == NGX_FILT_NEED_IN_MEMORY
+*/
+
+    if ((r->filter & NGX_FILT_NEED_IN_MEMORY) && (h->type & NGX_HUNK_FILE)) {
+
+        size = h->last.mem - h->pos.mem;
+        if (size > ctx->hunk_size)
+            size = ctx->hunk_size;
+
+        if (!ctx->hunk)
+            ngx_test_null(ctx->hunk, ngx_create_temp_hunk(size), ...);
+
+        ngx_read_file(h->fd, ctx->hunk->pos.mem, size);
+
+        h->hunk->pos.mem += size;
+    }
+
+    if ((r->filter & NGX_FILT_NEED_TEMP)
+        && (h->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP))
+    {
+        size = h->last.mem - h->pos.mem;
+        if (size > ctx->hunk_size)
+            size = ctx->hunk_size;
+
+        if (!ctx->hunk)
+            ngx_test_null(ctx->hunk, ngx_create_temp_hunk(size), ...);
+
+        ngx_memcpy(ctx->hunk->pos.mem, h->pos.mem, size);
+
+        h->hunk->pos.mem += size;
+    }
+
+
+
+
+
+
+    rc = ctx->next_filter(r, ch);
+
+    /* STUB */
+    rc = ngx_http_write_filter(r, ch);
+}
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -34,7 +34,7 @@ int ngx_http_write_filter(ngx_http_reque
 
     ctx = (ngx_http_write_filter_ctx_t *)
                               ngx_get_module_ctx(r->main ? r->main : r,
-                                                &ngx_http_write_filter_module);
+                                                 &ngx_http_write_filter_module);
     size = flush = 0;
     last = 0;
     prev = &ctx->out;
@@ -44,6 +44,10 @@ int ngx_http_write_filter(ngx_http_reque
         prev = &ch->next;
         size += ch->hunk->last.file - ch->hunk->pos.file;
 
+        ngx_log_debug(r->connection->log, "old chunk: %x %qx %qd" _
+                      ch->hunk->type _ ch->hunk->pos.file _
+                      ch->hunk->last.file - ch->hunk->pos.file);
+
         if (ch->hunk->type & NGX_HUNK_FLUSH)
             flush = size;
 
@@ -62,6 +66,10 @@ int ngx_http_write_filter(ngx_http_reque
         prev = &ch->next;
         size += ch->hunk->last.file - ch->hunk->pos.file;
 
+        ngx_log_debug(r->connection->log, "new chunk: %x %qx %qd" _
+                      ch->hunk->type _ ch->hunk->pos.file _
+                      ch->hunk->last.file - ch->hunk->pos.file);
+
         if (ch->hunk->type & NGX_HUNK_FLUSH)
             flush = size;
 
@@ -69,7 +77,7 @@ int ngx_http_write_filter(ngx_http_reque
             last = 1;
     }
 
-    if (flush == 0 && size < ctx->buffer_output)
+    if (!last && flush == 0 && size < ctx->buffer_output)
         return NGX_HTTP_FILTER_DONE;
 
     chain = ngx_event_write(r->connection, ctx->out, flush);
deleted file mode 100644
--- a/src/os/freebsd/ngx_os_thread.c
+++ /dev/null
@@ -1,64 +0,0 @@
-
-#include <ngx_os_thread.h>
-
-char    *ngx_stacks_start;
-char    *ngx_stacks_end;
-size_t   ngx_stack_size;
-
-
-/* handle thread-safe errno */
-static int   errno0; /* errno for main thread */
-static int  *errnos;
-
-int *__error()
-{
-    ngx_tid_t tid = ngx_gettid();
-    return tid ? &(errnos[ngx_gettid()]) : &errno0;
-}
-
-
-int ngx_create_os_thread(ngx_os_tid_t *tid, void *stack,
-                     int (*func)(void *arg), void *arg, ngx_log_t log)
-{
-    int id, err;
-
-    id = rfork_thread(RFPROC|RFMEM, stack, func, arg);
-    err = ngx_errno;
-
-    if (id == -1)
-        ngx_log_error(NGX_LOG_ERR, log, err,
-                      "ngx_create_os_thread: rfork failed");
-    else
-        *tid = id;
-
-    return err;
-}
-
-
-int ngx_create_os_thread_env(int n, size_t size, ngx_log_t log)
-{
-    char *addr;
-
-    /* create thread stacks */
-    addr = mmap(NULL, n * size, PROT_READ|PROT_WRITE, MAP_ANON, -1, NULL);
-    if (addr == MAP_FAILED) {
-        ngx_log_error(NGX_LOG_ERR, log, ngx_errno,
-                      "ngx_create_os_thread_stacks: mmap failed");
-        return -1;
-    }
-
-    nxg_stacks_start = addr;
-    nxg_stacks_end = addr + n * size;
-    nxg_stack_size = size;
-
-    /* create thread errno array */
-    ngx_test_null(errnos, ngx_calloc(n * sizeof(int)), -1);
-
-    /* create thread tid array */
-    ngx_test_null(ngx_os_tids, ngx_calloc(n * sizeof(ngx_os_tid_t)), -1);
-
-    /* allow spinlock in malloc() */
-    __isthreaded = 1;
-
-    return 0;
-}
deleted file mode 100644
--- a/src/os/freebsd/ngx_os_thread.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _NGX_OS_THREAD_H_INCLUDED_
-#define _NGX_OS_THREAD_H_INCLUDED_
-
-
-typedef int  ngx_os_tid_t;
-typedef int  ngx_tid_t;
-
-
-extern char   *ngx_stacks_start;
-extern char   *ngx_stacks_end;
-extern size_t  ngx_stack_size;
-
-
-static inline ngx_tid_t ngx_gettid()
-{   
-    char *sp;
-
-    __asm__ ("mov %%esp,%0" : "=r" (sp));
-    return (sp > ngx_stacks_end) ? 0:
-           (sp - ngx_stacks_start) / ngx_stack_size + 1;
-}
-
-
-#endif /* _NGX_OS_THREAD_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/os/unix/freebsd/ngx_rfork_thread.c
@@ -0,0 +1,64 @@
+
+#include <ngx_os_thread.h>
+
+char    *ngx_stacks_start;
+char    *ngx_stacks_end;
+size_t   ngx_stack_size;
+
+
+/* handle thread-safe errno */
+static int   errno0; /* errno for main thread */
+static int  *errnos;
+
+int *__error()
+{
+    ngx_tid_t tid = ngx_gettid();
+    return tid ? &(errnos[ngx_gettid()]) : &errno0;
+}
+
+
+int ngx_create_thread(ngx_os_tid_t *tid, void *stack,
+                     int (*func)(void *arg), void *arg, ngx_log_t log)
+{
+    int id, err;
+
+    id = rfork_thread(RFPROC|RFMEM, stack, func, arg);
+    err = ngx_errno;
+
+    if (id == -1)
+        ngx_log_error(NGX_LOG_ERR, log, err,
+                      "ngx_create_os_thread: rfork failed");
+    else
+        *tid = id;
+
+    return err;
+}
+
+
+int ngx_create_thread_env(int n, size_t size, ngx_log_t log)
+{
+    char *addr;
+
+    /* create thread stacks */
+    addr = mmap(NULL, n * size, PROT_READ|PROT_WRITE, MAP_ANON, -1, NULL);
+    if (addr == MAP_FAILED) {
+        ngx_log_error(NGX_LOG_ERR, log, ngx_errno,
+                      "ngx_create_os_thread_stacks: mmap failed");
+        return -1;
+    }
+
+    nxg_stacks_start = addr;
+    nxg_stacks_end = addr + n * size;
+    nxg_stack_size = size;
+
+    /* create thread errno array */
+    ngx_test_null(errnos, ngx_calloc(n * sizeof(int)), -1);
+
+    /* create thread tid array */
+    ngx_test_null(ngx_os_tids, ngx_calloc(n * sizeof(ngx_os_tid_t)), -1);
+
+    /* allow spinlock in malloc() */
+    __isthreaded = 1;
+
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/src/os/unix/freebsd/ngx_rfork_thread.h
@@ -0,0 +1,24 @@
+#ifndef _NGX_OS_THREAD_H_INCLUDED_
+#define _NGX_OS_THREAD_H_INCLUDED_
+
+
+typedef int  ngx_os_tid_t;
+typedef int  ngx_tid_t;
+
+
+extern char   *ngx_stacks_start;
+extern char   *ngx_stacks_end;
+extern size_t  ngx_stack_size;
+
+
+static inline ngx_tid_t ngx_gettid()
+{   
+    char *sp;
+
+    __asm__ ("mov %%esp,%0" : "=r" (sp));
+    return (sp > ngx_stacks_end) ? 0:
+           (sp - ngx_stacks_start) / ngx_stack_size + 1;
+}
+
+
+#endif /* _NGX_OS_THREAD_H_INCLUDED_ */
rename from src/os/unix/ngx_sendfile.c
rename to src/os/unix/freebsd/ngx_sendfile.c
--- a/src/os/unix/ngx_sendfile.c
+++ b/src/os/unix/freebsd/ngx_sendfile.c
@@ -1,6 +1,8 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_file.h>
+#include <ngx_socket.h>
 #include <ngx_errno.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
@@ -56,8 +58,8 @@ int ngx_sendfile(ngx_socket_t s,
         }
     }
 
-    ngx_log_debug(log, "ngx_sendfile: %d, @%qd %d:%qd" _
-                  rc _ offset _ nbytes _ *sent);
+    ngx_log_debug(log, "ngx_sendfile: %d, @%qd %qd:%d" _
+                  rc _ offset _ *sent _ nbytes);
 
     return 0;
 }
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -10,6 +10,7 @@ typedef int               ngx_err_t;
 #define NGX_ENOENT        ENOENT
 #define NGX_EINTR         EINTR
 #define NGX_EAGAIN        EWOULDBLOCK
+#define NGX_EADDRINUSE    EADDRINUSE
 
 #define ngx_errno         errno
 #define ngx_socket_errno  errno
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_file.h
@@ -0,0 +1,29 @@
+#ifndef _NGX_FILE_H_INCLUDED_
+#define _NGX_FILE_H_INCLUDED_
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+typedef int                      ngx_file_t;
+typedef struct stat              ngx_file_info_t;
+
+
+#define ngx_open_file            open
+#define ngx_open_file_n          "open"
+
+#define NGX_FILE_RDONLY          O_RDONLY
+
+
+#define ngx_file_type(file, sb)  stat(file, sb)
+#define ngx_file_type_n          "stat"
+
+#define ngx_stat_fd(fd, sb)      fstat(fd, sb)
+#define ngx_stat_fd_n            "fstat"
+
+#define ngx_is_dir(sb)           (S_ISDIR(sb.st_mode))
+#define ngx_file_size(sb)        sb.st_size
+#define ngx_file_mtime(sb)       sb.st_mtime
+
+
+#endif /* _NGX_FILE_H_INCLUDED_ */
--- a/src/os/unix/ngx_sendfile.h
+++ b/src/os/unix/ngx_sendfile.h
@@ -3,6 +3,8 @@
 
 
 #include <ngx_types.h>
+#include <ngx_file.h>
+#include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
 
--- a/src/os/unix/ngx_sendv.c
+++ b/src/os/unix/ngx_sendv.c
@@ -1,5 +1,6 @@
 
 #include <ngx_types.h>
+#include <ngx_socket.h>
 #include <ngx_sendv.h>
 
 ssize_t ngx_sendv(ngx_socket_t s, ngx_iovec_t *iovec, int n, size_t *sent)
--- a/src/os/unix/ngx_sendv.h
+++ b/src/os/unix/ngx_sendv.h
@@ -3,6 +3,7 @@
 
 
 #include <ngx_types.h>
+#include <ngx_socket.h>
 
 typedef struct iovec  ngx_iovec_t;
 #define ngx_iov_base  iov_base
--- a/src/os/unix/ngx_socket.h
+++ b/src/os/unix/ngx_socket.h
@@ -12,5 +12,8 @@ typedef int  ngx_socket_t;
 #define ngx_nonblocking(s)  fcntl(s, F_SETFL, O_NONBLOCK)
 #define ngx_nonblocking_n   "fcntl (O_NONBLOCK)"
 
+#define ngx_close_socket    close
+#define ngx_close_socket_n  "close"
+
 
 #endif /* _NGX_SOCKET_H_INCLUDED_ */
deleted file mode 100644
--- a/src/os/unix/ngx_stat.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _NGX_STAT_H_INCLUDED_
-#define _NGX_STAT_H_INCLUDED_
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-typedef struct stat  ngx_stat_t;
-
-#define ngx_is_dir(sb)           (S_ISDIR(sb.st_mode))
-
-#define ngx_stat(file, sb)       stat(file, sb)
-#define ngx_stat_n               "stat"
-
-#define ngx_fstat(file, fd, sb)  fstat(fd, sb)
-#define ngx_fstat_n              "stat"
-
-
-#endif /* _NGX_STAT_H_INCLUDED_ */
--- a/src/os/unix/ngx_time.h
+++ b/src/os/unix/ngx_time.h
@@ -14,6 +14,8 @@ typedef struct tm      ngx_tm_t;
 #define ngx_tm_year    tm_year
 #define ngx_tm_wday    tm_wday
 
+#define ngx_msleep(ms) usleep(ms * 1000)
+
 void ngx_localtime(ngx_tm_t *tm);
 
 u_int ngx_msec(void);
--- a/src/os/unix/ngx_types.h
+++ b/src/os/unix/ngx_types.h
@@ -5,8 +5,6 @@
 #include <ngx_config.h>
 
 
-typedef int  ngx_file_t;
-typedef int  ngx_socket_t;
 
 
 #endif /* _NGX_TYPES_H_INCLUDED_ */
--- a/src/os/win32/ngx_errno.h
+++ b/src/os/win32/ngx_errno.h
@@ -11,6 +11,7 @@ typedef DWORD             ngx_err_t;
 
 #define NGX_ENOENT        ERROR_FILE_NOT_FOUND
 #define NGX_EAGAIN        WSAEWOULDBLOCK
+#define NGX_EADDRINUSE    WSAEADDRINUSE
 
 int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size);
 
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_file.h
@@ -0,0 +1,52 @@
+#ifndef _NGX_FILE_H_INCLUDED_
+#define _NGX_FILE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+
+/* INVALID_FILE_ATTRIBUTES specified but never defined at least in VC6SP2 */
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES  0xFFFFFFFF
+#endif
+
+typedef HANDLE                      ngx_file_t;
+typedef BY_HANDLE_FILE_INFORMATION  ngx_file_info_t;
+
+
+#define ngx_open_file(name, flags)                                          \
+            CreateFile(name, flags,                                         \
+                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,  \
+                       NULL, OPEN_EXISTING, 0, NULL)
+
+#define ngx_open_file_n             "CreateFile"
+
+#define NGX_FILE_RDONLY          GENERIC_READ
+
+
+int ngx_file_type(char *filename, ngx_file_info_t *fi);
+#define ngx_file_type_n          "GetFileAttributes"
+
+#define ngx_stat_fd(fd, fi)     GetFileInformationByHandle(fd, fi)
+#define ngx_stat_fd_n           "GetFileInformationByHandle"
+
+#define ngx_is_dir(fi)          (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+
+#define ngx_file_size(fi)                                                   \
+            fi.nFileSizeLow
+
+/*
+#define ngx_file_size(fi)                                                   \
+            ((off_t) fi.nFileSizeHigh << 32 & fi.nFileSizeLow)
+*/
+
+#define ngx_file_mtime(fi)       fi.ftLastWriteTime
+
+/*
+1970 - 1601:
+	116444736000000000
+	19DB1DED53E8000
+*/
+
+
+#endif /* _NGX_FILE_H_INCLUDED_ */
--- a/src/os/win32/ngx_sendfile.c
+++ b/src/os/win32/ngx_sendfile.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_socket.h>
 #include <ngx_errno.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
@@ -52,16 +53,22 @@ int ngx_sendfile(ngx_socket_t s,
         ptfb = NULL;
     }
 
+#if 0
     tfrc = TransmitFile(s, fd, nbytes, 0, &olp, ptfb, 0);
+#else
+    tfrc = TransmitFile(s, fd, nbytes, 0, NULL, ptfb, 0);
+#endif
 
     if (tfrc == 0)
         tf_err = ngx_socket_errno;
 
     /* set sent */
+#if 0
     rc = WSAGetOverlappedResult(s, &olp, (unsigned long *) sent, 0, NULL);
+#endif
 
-    ngx_log_debug(log, "ngx_sendfile: %d, @%qd %d:%qd" _
-                  tfrc _ offset _ nbytes _ *sent);
+    ngx_log_debug(log, "ngx_sendfile: %d, @%I64d %I64d:%d" _
+                  tfrc _ offset _ *sent _ nbytes);
 
     if (rc == 0) {
         err = ngx_socket_errno;
@@ -77,7 +84,8 @@ int ngx_sendfile(ngx_socket_t s,
         }
 
         ngx_log_error(NGX_LOG_INFO, log, tf_err,
-                     "ngx_sendfile: TransmitFile sent only %qd bytes", *sent);
+                      "ngx_sendfile: TransmitFile sent only %I64d bytes",
+                      *sent);
     }
 
     if (rc == 0)
--- a/src/os/win32/ngx_sendfile.h
+++ b/src/os/win32/ngx_sendfile.h
@@ -4,6 +4,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
 
--- a/src/os/win32/ngx_socket.c
+++ b/src/os/win32/ngx_socket.c
@@ -1,8 +1,8 @@
-#include <nxg_config.h>
+#include <ngx_config.h>
 
-#include <nxg_log.h>
-#include <nxg_errno.h>
-#include <nxg_socket.h>
+#include <ngx_log.h>
+#include <ngx_errno.h>
+#include <ngx_socket.h>
 
 
 void ngx_init_sockets(ngx_log_t *log)
@@ -12,6 +12,8 @@ void ngx_init_sockets(ngx_log_t *log)
     if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
         ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                       "ngx_init_sockets: WSAStartup failed");
+
+    /* get AcceptEx(), TransmitFile() functions */
 }
 
 int ngx_nonblocking(ngx_socket_t s)
@@ -20,3 +22,10 @@ int ngx_nonblocking(ngx_socket_t s)
 
     return ioctlsocket(s, FIONBIO, &nb);
 }
+
+int ngx_blocking(ngx_socket_t s)
+{
+    unsigned long  nb = 0;
+
+    return ioctlsocket(s, FIONBIO, &nb);
+}
--- a/src/os/win32/ngx_socket.h
+++ b/src/os/win32/ngx_socket.h
@@ -3,14 +3,17 @@
 
 
 #include <ngx_config.h>
+#include <ngx_log.h>
 
-typedef SOCKET            ngx_socket_t;
+typedef SOCKET  ngx_socket_t;
 
 void ngx_init_sockets(ngx_log_t *log);
 
 int ngx_nonblocking_n(s);
-#define ngx_nonblocking_n  "ioctlsocket (FIONBIO)"
+#define ngx_nonblocking_n   "ioctlsocket (FIONBIO)"
 
+#define ngx_close_socket    closesocket
+#define ngx_close_socket_n  "closesocket"
 
 
 #endif /* _NGX_SOCKET_H_INCLUDED_ */
--- a/src/os/win32/ngx_stat.c
+++ b/src/os/win32/ngx_stat.c
@@ -3,6 +3,18 @@
 
 #include <ngx_stat.h>
 
+int ngx_file_type(char *file, ngx_file_info_t *sb)
+{
+    sb->dwFileAttributes = GetFileAttributes(file);
+
+    if (sb->dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
 int ngx_stat(char *file, ngx_stat_t *sb)
 {
     *sb = GetFileAttributes(file);
@@ -13,3 +25,4 @@ int ngx_stat(char *file, ngx_stat_t *sb)
 
     return 0;
 }
+*/
--- a/src/os/win32/ngx_stat.h
+++ b/src/os/win32/ngx_stat.h
@@ -4,15 +4,17 @@
 
 #include <windows.h>
 
-/* INVALID_FILE_ATTRIBUTES specified but never defined */
+/* INVALID_FILE_ATTRIBUTES specified but never defined at least in VC6SP2 */
 #ifndef INVALID_FILE_ATTRIBUTES
 #define INVALID_FILE_ATTRIBUTES  0xFFFFFFFF
 #endif
 
-typedef DWORD  ngx_stat_t;
+typedef BY_HANDLE_FILE_INFORMATION  ngx_file_info_t;
 
 
-#define ngx_is_dir(sb)           (*sb & FILE_ATTRIBUTE_DIRECTORY) 
+#define ngx_file_type_n          "GetFileAttributes"
+
+#define ngx_is_dir(fi)          (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
 
 #define ngx_stat_n               "GetFileAttributes"
 
@@ -20,7 +22,9 @@ typedef DWORD  ngx_stat_t;
 #define ngx_fstat_n              "GetFileAttributes"
 
 
+/*
 int ngx_stat(char *file, ngx_stat_t *sb);
+*/
 
 
 #endif /* _NGX_STAT_H_INCLUDED_ */
--- a/src/os/win32/ngx_time.h
+++ b/src/os/win32/ngx_time.h
@@ -5,6 +5,7 @@
 #include <windows.h>
 
 typedef SYSTEMTIME     ngx_tm_t;
+typedef FILETIME       ngx_mtime_t;
 
 #define ngx_tm_sec     wSecond
 #define ngx_tm_min     wMinute
@@ -14,6 +15,7 @@ typedef SYSTEMTIME     ngx_tm_t;
 #define ngx_tm_year    wYear
 #define ngx_tm_wday    wDayOfWeek
 
+#define ngx_msleep     Sleep
 #define ngx_localtime  GetLocalTime
 #define ngx_msec       GetTickCount
 
--- a/src/os/win32/ngx_types.h
+++ b/src/os/win32/ngx_types.h
@@ -6,7 +6,6 @@
 
 
 typedef HANDLE            ngx_file_t;
-typedef SOCKET            ngx_socket_t;
 typedef long              time_t;
 typedef unsigned __int64  off_t;