nginx-0.0.1-2002-08-06-20:39:45 import

The first code that uses "ngx_" prefix, the previous one used "gx_" prefix.
At that point the code is not yet usable.  The first draft ideas are dated
back to 23.10.2001.
diff --git a/src/core/nginx.c b/src/core/nginx.c
new file mode 100644
index 0000000..f1671b3
--- /dev/null
+++ b/src/core/nginx.c
@@ -0,0 +1,118 @@
+
+#include <nginx.h>
+
+#include <ngx_config.h>
+#include <ngx_string.h>
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+#include <ngx_server.h>
+#include <ngx_connection.h>
+#include <ngx_listen.h>
+
+/*
+#include <ngx_http.h>
+*/
+
+
+#if !(WIN32)
+static int ngx_options(int argc, char *const *argv);
+#endif
+
+char *ngx_root = "/home/is/work/xml/xml/html";
+
+int ngx_http_init_connection(void *data);
+
+
+int ngx_max_conn = 512;
+struct sockaddr_in ngx_addr = {0, AF_INET, 0, 0, 0};
+
+
+ngx_pool_t   ngx_pool;
+ngx_log_t    ngx_log;
+ngx_server_t ngx_server;
+
+
+int main(int argc, char *const *argv)
+{
+    char addr_text[22];
+    ngx_socket_t fd;
+    ngx_listen_t ls;
+#if (WIN32)
+    WSADATA      wsd;
+#endif
+
+
+    ngx_log.log_level = NGX_LOG_DEBUG;
+    ngx_pool.log = &ngx_log;
+    ngx_addr.sin_port = htons(8000);
+    ngx_addr.sin_family = AF_INET;
+
+#if !(WIN32)
+    if (ngx_options(argc, argv) == -1)
+        ngx_log_error(NGX_LOG_EMERG, (&ngx_log), 0, "invalid argument");
+#endif
+
+    ngx_log_debug((&ngx_log), "%d, %s:%d" _ ngx_max_conn _
+                 inet_ntoa(ngx_addr.sin_addr) _ ntohs(ngx_addr.sin_port));
+
+#if (WIN32)
+    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
+        ngx_log_error(NGX_LOG_EMERG, (&ngx_log), ngx_socket_errno,
+                      "WSAStartup failed");
+#endif
+
+    ngx_snprintf(ngx_cpystrn(addr_text, inet_ntoa(ngx_addr.sin_addr), 16),
+                 7, ":%d", ntohs(ngx_addr.sin_port));
+    fd = ngx_listen((struct sockaddr *) &ngx_addr, -1, &ngx_log, addr_text);
+
+    ngx_server.buff_size = 1024;
+    ngx_server.handler = ngx_http_init_connection;
+
+    /* daemon */
+
+    ls.fd = fd;
+    ls.server = &ngx_server;
+    ls.log = &ngx_log;
+
+    /* fork */
+
+    ngx_worker(&ls, 1, &ngx_pool, &ngx_log);
+}
+
+#if !(WIN32)
+extern char *optarg;
+
+static int ngx_options(int argc, char *const *argv)
+{
+    char ch, *pos;
+    int port;
+
+    while ((ch = getopt(argc, argv, "l:c:")) != -1) {
+        switch (ch) {
+        case 'l':
+            if (pos = strchr(optarg, ':')) {
+                *(pos) = '\0';
+                if ((port = atoi(pos + 1)) <= 0)
+                    return -1;
+                ngx_addr.sin_port = htons(port);
+            }
+
+            if ((ngx_addr.sin_addr.s_addr = inet_addr(optarg)) == INADDR_NONE)
+                return -1;
+            break;
+
+        case 'c':
+            if ((ngx_max_conn = atoi(optarg)) <= 0)
+                return -1;
+            break;
+
+        case '?':
+        default:
+            return -1;
+        }
+
+    }
+
+    return 0;
+}
+#endif
diff --git a/src/core/nginx.h b/src/core/nginx.h
new file mode 100644
index 0000000..0f4b0de
--- /dev/null
+++ b/src/core/nginx.h
@@ -0,0 +1,8 @@
+#ifndef _NGINX_H_INCLUDED_
+#define _NGINX_H_INCLUDED_
+
+
+extern char *gx_root;
+
+
+#endif /* _NGINX_H_INCLUDED_ */
diff --git a/src/core/ngx_alloc.c b/src/core/ngx_alloc.c
new file mode 100644
index 0000000..61ecabc
--- /dev/null
+++ b/src/core/ngx_alloc.c
@@ -0,0 +1,136 @@
+
+#include <ngx_config.h>
+
+#include <ngx_errno.h>
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log)
+{
+    void *p;
+
+    p = malloc(size);
+    if (p == NULL)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                     "ngx_alloc: malloc %d bytes failed", size);
+    return p;
+}
+
+void *ngx_calloc(size_t size, ngx_log_t *log)
+{
+    void *p;
+
+    p = ngx_alloc(size, log);
+    if (p)
+        ngx_memzero(p, size);
+
+    return p;
+}
+
+ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)
+{
+    ngx_pool_t *p;
+
+    ngx_test_null(p, ngx_alloc(size, log), NULL);
+
+    p->last = (char *) p + sizeof(ngx_pool_t);
+    p->end = (char *) p + size;
+    p->next = NULL;
+    p->large = NULL;
+    p->log = log;
+
+    return p;
+}
+
+void ngx_destroy_pool(ngx_pool_t *pool)
+{
+    ngx_pool_t        *p, *n;
+    ngx_pool_large_t  *l;
+
+    for (l = pool->large; l; l = l->next)
+        free(l->alloc);
+
+    for (p = pool, n = pool->next; /* void */; p = n, n = n->next) {
+        free(p);
+
+        if (n == NULL)
+            break;
+    }
+}
+
+void *ngx_palloc(ngx_pool_t *pool, size_t size)
+{
+    void              *m;
+    ngx_pool_t        *p, *n;
+    ngx_pool_large_t  *large, *last;
+
+    if (size <= NGX_MAX_ALLOC_FROM_POOL) {
+
+        for (p = pool, n = pool->next; /* void */; p = n, n = n->next) {
+            if ((size_t) (p->end - p->last) >= size) {
+                m = p->last;
+                p->last += size;
+
+                return m;
+            }
+
+            if (n == NULL)
+                break;
+        }
+
+        /* alloc new pool block */
+        ngx_test_null(n, ngx_create_pool(p->end - (char *) p, p->log), NULL);
+        p->next = n;
+        m = n->last;
+        n->last += size;
+        return m;
+
+    /* alloc large block */
+    } else {
+        large = NULL;
+        last = NULL;
+
+        if (pool->large) {
+            for (last = pool->large; /* void */; last = last->next) {
+                if (last->alloc == NULL) {
+                    large = last;
+                    last = NULL;
+                    break;
+                }
+
+                if (last->next == NULL)
+                    break;
+            }
+        }
+
+        if (large == NULL) {
+            ngx_test_null(large, ngx_palloc(pool, sizeof(ngx_pool_large_t)),
+                          NULL);
+        }
+
+        ngx_test_null(p, ngx_alloc(size, pool->log), NULL);
+
+        if (pool->large == NULL) {
+            pool->large = large;
+
+        } else if (last) {
+            last->next = large;
+        }
+
+        large->alloc = p;
+
+        return p;
+    }
+}
+
+void *ngx_pcalloc(ngx_pool_t *pool, size_t size)
+{
+    void *p;
+
+    p = ngx_palloc(pool, size);
+    if (p)
+        ngx_memzero(p, size);
+
+    return p;
+}
diff --git a/src/core/ngx_alloc.h b/src/core/ngx_alloc.h
new file mode 100644
index 0000000..1d1ad84
--- /dev/null
+++ b/src/core/ngx_alloc.h
@@ -0,0 +1,42 @@
+#ifndef _NGX_ALLOC_H_INCLUDED_
+#define _NGX_ALLOC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+#include <ngx_log.h>
+
+
+#define NGX_MAX_ALLOC_FROM_POOL (8192 - sizeof(ngx_pool_t))
+#define NGX_DEFAULT_POOL_SIZE   (16 * 1024)
+
+#define ngx_test_null(p, alloc, rc)  if ((p = alloc) == NULL) return rc
+
+
+typedef struct ngx_pool_large_s  ngx_pool_large_t;
+struct ngx_pool_large_s {
+    ngx_pool_large_t  *next;
+    void              *alloc;
+};
+
+typedef struct ngx_pool_s  ngx_pool_t;
+struct ngx_pool_s {
+    char              *last;
+    char              *end;
+    ngx_pool_t        *next;
+    ngx_pool_large_t  *large;
+    ngx_log_t         *log;
+};
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log);
+void *ngx_calloc(size_t size, ngx_log_t *log);
+
+ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
+void ngx_destroy_pool(ngx_pool_t *pool);
+
+void *ngx_palloc(ngx_pool_t *pool, size_t size);
+void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
+
+
+#endif /* _NGX_ALLOC_H_INCLUDED_ */
diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c
new file mode 100644
index 0000000..08ad588
--- /dev/null
+++ b/src/core/ngx_array.c
@@ -0,0 +1,69 @@
+
+#include <ngx_config.h>
+
+#include <ngx_alloc.h>
+#include <ngx_array.h>
+
+ngx_array_t *ngx_create_array(ngx_pool_t *p, int n, size_t size)
+{
+    ngx_array_t *a;
+
+    a = ngx_palloc(p, sizeof(ngx_array_t));
+    if (a == NULL)
+        return NULL;
+
+    a->elts = ngx_palloc(p, n * size);
+    if (a->elts == NULL)
+        return NULL;
+
+    a->pool = p;
+    a->nelts = 0;
+    a->nalloc = n;
+    a->size = size;
+
+    return a;
+}
+
+void ngx_destroy_array(ngx_array_t *a)
+{
+    ngx_pool_t *p = a->pool;
+
+    if (a->elts + a->size * a->nalloc == p->last)
+        p->last -= a->size * a->nalloc;
+
+    if ((char *) a + sizeof(ngx_array_t) == p->last)
+        p->last = (char *) a;
+}
+
+void *ngx_push_array(ngx_array_t *a)
+{
+    void *elt;
+
+    /* array is full */
+    if (a->nelts == a->nalloc) {
+        ngx_pool_t *p = a->pool;
+
+        /* array allocation is the last in the pool */
+        if (a->elts + a->size * a->nelts == p->last
+            && (unsigned) (p->end - p->last) >= a->size)
+        {
+            p->last += a->size;
+            a->nalloc++;
+
+        /* allocate new array */
+        } else {
+            void *new = ngx_palloc(p, 2 * a->nalloc * a->size);
+            if (new == NULL)
+                return NULL;
+
+            memcpy(new, a->elts, a->nalloc * a->size);
+            a->elts = new;
+            a->nalloc *= 2;
+        }
+    }
+
+    elt = a->elts + a->size * a->nelts;
+    a->nelts++;
+
+    return elt;
+}
diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h
new file mode 100644
index 0000000..d110b76
--- /dev/null
+++ b/src/core/ngx_array.h
@@ -0,0 +1,23 @@
+#ifndef _NGX_ARRAY_H_INCLUDED_
+#define _NGX_ARRAY_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+#include <ngx_alloc.h>
+
+typedef struct {
+    char       *elts;
+    int         nelts;
+    size_t      size;
+    int         nalloc;
+    ngx_pool_t *pool;
+} ngx_array_t;
+
+
+ngx_array_t *ngx_create_array(ngx_pool_t *p, int n, size_t size);
+void ngx_destroy_array(ngx_array_t *a);
+void *ngx_push_array(ngx_array_t *a);
+
+
+#endif /* _NGX_ARRAY_H_INCLUDED_ */
diff --git a/src/core/ngx_auto_config.h b/src/core/ngx_auto_config.h
new file mode 100644
index 0000000..d9865c4
--- /dev/null
+++ b/src/core/ngx_auto_config.h
@@ -0,0 +1,4 @@
+
+#ifndef OFF_EQUAL_PTR
+#define OFF_EQUAL_PTR 0
+#endif
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
new file mode 100644
index 0000000..1412da8
--- /dev/null
+++ b/src/core/ngx_config.h
@@ -0,0 +1,130 @@
+#ifndef _NGX_CONFIG_H_INCLUDED_
+#define _NGX_CONFIG_H_INCLUDED_
+
+
+#include <ngx_auto_config.h>
+
+/*
+   auto_conf
+   ngx_inline inline __inline __inline__
+*/
+
+#define FD_SETSIZE  1024
+
+
+#ifdef _WIN32
+
+#define WIN32 1
+
+#include <winsock2.h>
+#include <mswsock.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+
+#define ngx_inline   __inline
+
+#define ngx_memzero  ZeroMemory
+
+#define ngx_close_socket closesocket
+
+#ifndef HAVE_WIN32_TRANSMITPACKETS
+#define HAVE_WIN32_TRANSMITPACKETS  1
+#define HAVE_WIN32_TRANSMITFILE     0
+#endif
+
+#ifndef HAVE_WIN32_TRANSMITFILE
+#define HAVE_WIN32_TRANSMITFILE  1
+#endif
+
+#if (HAVE_WIN32_TRANSMITPACKETS) || (HAVE_WIN32_TRANSMITFILE)
+#define HAVE_SENDFILE  1
+#endif
+
+#else /* POSIX */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define ngx_inline   inline
+
+#define ngx_memzero  bzero
+
+#define ngx_close_socket close
+
+#endif /* POSIX */
+
+
+
+#define LF     10
+#define CR     13
+#define CRLF   "\x0d\x0a"
+
+
+
+#if defined SO_ACCEPTFILTER || defined TCP_DEFER_ACCEPT
+
+#ifndef HAVE_DEFERRED_ACCEPT
+#define HAVE_DEFERRED_ACCEPT  1
+#endif
+
+#endif
+
+
+
+#ifdef __FreeBSD__
+
+#include <osreldate.h>
+
+#if __FreeBSD_version >= 300007
+
+#ifndef HAVE_FREEBSD_SENDFILE
+#define HAVE_FREEBSD_SENDFILE  1
+#endif
+
+#ifndef HAVE_FREEBSD_SENDFILE_NBYTES_BUG
+#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG  2
+#endif
+
+#endif
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460100) \
+    || __FreeBSD_version == 460001
+    || __FreeBSD_version >= 500029
+
+#if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG == 2)
+#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG  0
+#endif
+
+#endif
+
+#if (HAVE_FREEBSD_SENDFILE)
+#define HAVE_SENDFILE  1
+#endif
+
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 410000) \
+    || __FreeBSD_version >= 500011
+
+#ifndef HAVE_KQUEUE
+#define HAVE_KQUEUE  1
+#include <sys/event.h>
+#endif
+
+#endif
+
+
+#endif /* __FreeBSD__ */
+
+
+#endif /* _NGX_CONFIG_H_INCLUDED_ */
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
new file mode 100644
index 0000000..17bd58a
--- /dev/null
+++ b/src/core/ngx_connection.h
@@ -0,0 +1,54 @@
+#ifndef _NGX_CONNECTION_H_INCLUDED_
+#define _NGX_CONNECTION_H_INCLUDED_
+
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+#include <ngx_server.h>
+
+typedef struct ngx_connection_s  ngx_connection_t;
+
+#ifdef NGX_EVENT
+#include <ngx_event.h>
+#endif
+
+struct ngx_connection_s {
+    ngx_socket_t      fd;
+    void            *data;
+
+#ifdef NGX_EVENT
+    ngx_event_t      *read;
+    ngx_event_t      *write;
+#endif
+
+    ngx_log_t        *log;
+    ngx_server_t     *server;
+    ngx_server_t     *servers;
+    ngx_pool_t       *pool;
+};
+
+
+/*
+
+cached file
+    int      fd;       -2 unused, -1 closed (but read or mmaped), >=0 open
+    char    *name;
+
+    void    *buf;      addr if read or mmaped
+                       aiocb* if aio_read
+                       OVERLAPPED if TransmitFile or TransmitPackets
+                       NULL if sendfile
+
+    size_t   buf_size; for plain read
+    off_t    offset;   for plain read
+
+    size_t   size;
+    time_t   mod;
+    char    *last_mod; 'Sun, 17 Mar 2002 19:39:50 GMT'
+    char    *etag;     '"a6d08-1302-3c94f106"'
+    char    *len;      '4866'
+
+EV_VNODE        should notify by some signal if diretory tree is changed
+                or stat if aged >= N seconds (big enough)
+*/
+
+#endif /* _NGX_CONNECTION_H_INCLUDED_ */
diff --git a/src/core/ngx_hunk.c b/src/core/ngx_hunk.c
new file mode 100644
index 0000000..3defc6d
--- /dev/null
+++ b/src/core/ngx_hunk.c
@@ -0,0 +1,85 @@
+
+#include <ngx_types.h>
+#include <ngx_hunk.h>
+
+
+ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after)
+{
+    ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
+
+#ifndef OFF_EQUAL_PTR
+    h->pos.f = h->last.f = 0;
+#endif
+
+    h->pre_start = ngx_palloc(pool, size + before + after);
+    h->start = h->pos.p = h->last.p = h->pre_start + before;
+    h->end = h->last.p + size;
+    h->post_end = h->end + after;
+
+    h->type = NGX_HUNK_TEMP;
+    h->tag = 0;
+    h->fd = (ngx_file_t) -1;
+
+    return h;
+}
+    
+ngx_hunk_t *ngx_get_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
+{    
+    ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
+
+#ifndef OFF_EQUAL_PTR
+    h->pos.f = h->last.f = 0;
+#endif
+ 
+    if (hunk->type & NGX_HUNK_TEMP && hunk->pos.p - hunk->pre_start >= size) {
+        /* keep hunk->start unchanged - used in restore */
+        h->pre_start = hunk->pre_start;
+        h->end = h->post_end = hunk->pre_start = hunk->pos.p;
+        h->start = h->pos.p = h->last.p = h->end - size;
+
+        h->type = NGX_HUNK_TEMP;
+        h->tag = 0;
+        h->fd = (ngx_file_t) -1;
+
+    } else {
+        h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size);
+        h->end = h->post_end = h->start + size;
+
+        h->type = NGX_HUNK_TEMP;
+        h->tag = 0;
+        h->fd = (ngx_file_t) -1;
+    }
+
+    return h;
+}
+
+ngx_hunk_t *ngx_get_hunk_after(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
+{
+    ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
+
+#ifndef OFF_EQUAL_PTR
+    h->pos.f = h->last.f = 0;
+#endif
+
+    if (hunk->type & NGX_HUNK_TEMP
+        && hunk->last.p == hunk->end
+        && hunk->post_end - hunk->end >= size)
+    {
+        h->post_end = hunk->post_end;
+        h->pre_start = h->start = h->pos.p = h->last.p = hunk->post_end =
+                                                                  hunk->last.p;
+        h->type = NGX_HUNK_TEMP;
+        h->tag = 0;
+        h->fd = (ngx_file_t) -1;
+
+    } else {
+        h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size);
+        h->end = h->post_end = h->start + size;
+
+        h->type = NGX_HUNK_TEMP;
+        h->tag = 0;
+        h->fd = (ngx_file_t) -1;
+    }
+
+    return h;
+}
diff --git a/src/core/ngx_hunk.h b/src/core/ngx_hunk.h
new file mode 100644
index 0000000..e4238b4
--- /dev/null
+++ b/src/core/ngx_hunk.h
@@ -0,0 +1,57 @@
+#ifndef _NGX_CHUNK_H_INCLUDED_
+#define _NGX_CHUNK_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_alloc.h>
+
+
+/* type */
+#define NGX_HUNK_TEMP       0x0001
+#define NGX_HUNK_MEMORY     0x0002
+#define NGX_HUNK_MMAP       0x0004
+#define NGX_HUNK_FILE       0x0008
+#define NGX_HUNK_FLUSH      0x0010
+/* in thread state flush means to write the hunk completely before return
+   in event-driven state flush means to start to write the hunk */
+#define NGX_HUNK_LAST       0x0020
+
+#define NGX_HUNK_IN_MEMORY  (NGX_HUNK_TEMP | NGX_HUNK_MEMORY | NGX_HUNK_MMAP )
+#define NGX_HUNK_TYPE       0x0ffff
+
+/* flags */
+#define NGX_HUNK_SHUTDOWN   0x10000
+/* can be used with NGX_HUNK_LAST only */
+
+
+typedef struct ngx_hunk_s ngx_hunk_t;
+struct ngx_hunk_s {
+    union {
+        char    *p;             /* start of current data */
+        off_t    f;   
+    } pos;
+    union {
+        char    *p;             /* end of current data */
+        off_t    f;   
+    } last;
+    int          type;
+    char        *start;         /* start of hunk */
+    char        *end;           /* end of hunk */
+    char        *pre_start;     /* start of pre-allocated hunk */
+    char        *post_end;      /* end of post-allocated hunk */
+    int          tag;
+    ngx_file_t   fd;
+};
+
+typedef struct ngx_chain_s  ngx_chain_t;
+struct ngx_chain_s {
+    ngx_hunk_t  *hunk;
+    ngx_chain_t *next;
+};
+
+
+ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after);
+
+
+#endif /* _NGX_CHUNK_H_INCLUDED_ */
diff --git a/src/core/ngx_listen.c b/src/core/ngx_listen.c
new file mode 100644
index 0000000..873b18d
--- /dev/null
+++ b/src/core/ngx_listen.c
@@ -0,0 +1,44 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_errno.h>
+#include <ngx_log.h>
+#include <ngx_listen.h>
+
+ngx_socket_t ngx_listen(struct sockaddr *addr, int backlog,
+                        ngx_log_t *log, char *addr_text)
+{
+    ngx_socket_t   s;
+    int            reuseaddr = 1;
+#if (WIN32)
+    unsigned long  nb = 1;
+#endif
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "socket failed");
+
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                   (const void *) &reuseaddr, sizeof(int)) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                     "ngx_listen: setsockopt (SO_REUSEADDR) failed");
+
+#if (WIN32)
+    if (ioctlsocket(s, FIONBIO, &nb) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                     "ngx_listen: ioctlsocket (FIONBIO) failed");
+#else
+    if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                     "ngx_listen: fcntl (O_NONBLOCK) failed");
+#endif
+
+    if (bind(s, (struct sockaddr *) addr, sizeof(struct sockaddr_in)) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                     "ngx_listen: bind to %s failed", addr_text);
+
+    if (listen(s, backlog) == -1)
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                     "ngx_listen: listen to %s failed", addr_text);
+
+    return s;
+}
diff --git a/src/core/ngx_listen.h b/src/core/ngx_listen.h
new file mode 100644
index 0000000..3be7162
--- /dev/null
+++ b/src/core/ngx_listen.h
@@ -0,0 +1,9 @@
+#ifndef _NGX_LISTEN_H_INCLUDED_
+#define _NGX_LISTEN_H_INCLUDED_
+
+
+ngx_socket_t ngx_listen(struct sockaddr *addr, int backlog,
+                        ngx_log_t *log, char *addr_text);
+
+
+#endif /* _NGX_LISTEN_H_INCLUDED_ */
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
new file mode 100644
index 0000000..6fb02db
--- /dev/null
+++ b/src/core/ngx_log.c
@@ -0,0 +1,116 @@
+
+/*
+   TODO: log pid and tid
+*/
+
+/*
+   "[time as ctime()] [alert] 412:3 (32)Broken pipe: anything"
+
+   "[time as ctime()] [alert] (32)Broken pipe: anything"
+   "[time as ctime()] [alert] anything"
+*/
+
+#include <ngx_config.h>
+#include <ngx_errno.h>
+#include <ngx_time.h>
+#include <ngx_string.h>
+#include <ngx_log.h>
+
+
+static const char *err_levels[] = {
+    "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
+};
+
+#if (HAVE_VARIADIC_MACROS)
+void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
+                        const char *fmt, ...)
+#else
+void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
+                        const char *fmt, va_list args)
+#endif
+{
+    char       errstr[MAX_ERROR_STR];
+    ngx_tm_t   tm;
+    size_t     len;
+#if (HAVE_VARIADIC_MACROS)
+    va_list    args;
+#endif
+
+    ngx_localtime(&tm);
+    len = ngx_snprintf(errstr, sizeof(errstr), "%02d:%02d:%02d",
+                       tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+
+    if (err) {
+        if ((unsigned) err < 0x80000000)
+            len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
+                            " [%s] (%d)",
+                            err_levels[level], err);
+            len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
+                            " [%s] (%X)",
+                            err_levels[level], err);
+
+        len += ngx_strerror_r(err, errstr + len, sizeof(errstr) - len - 1);
+        if (len < sizeof(errstr) - 2) {
+            errstr[len++] = ':';
+            errstr[len++] = ' ';
+        } else {
+            len = sizeof(errstr) - 2;
+        }
+
+    } else {
+        len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
+                            " [%s] ", err_levels[level]);
+    }
+
+#if (HAVE_VARIADIC_MACROS)
+    va_start(args, fmt);
+    len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
+    va_end(args);
+#else
+    len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
+#endif
+
+    if (len > sizeof(errstr) - 2)
+        len = sizeof(errstr) - 2;
+    errstr[len] = '\n';
+    errstr[len + 1] = '\0';
+
+    fputs(errstr, stderr);
+
+    if (level == NGX_LOG_EMERG)
+        exit(1);
+}
+
+#if !(HAVE_VARIADIC_MACROS)
+
+void ngx_log_error(int level, ngx_log_t *log, ngx_err_t err,
+                   const char *fmt, ...)
+{
+    va_list    args;
+
+    if (log->log_level >= level) {
+        va_start(args, fmt);
+        ngx_log_error_core(level, log, err, fmt, args);
+        va_end(args);
+    }
+}
+
+void ngx_log_debug_core(ngx_log_t *log, const char *fmt, ...)
+{
+    va_list    args;
+
+    va_start(args, fmt);
+    ngx_log_error_core(NGX_LOG_DEBUG, log, 0, fmt, args);
+    va_end(args);
+}
+
+void ngx_assert_core(ngx_log_t *log, const char *fmt, ...)
+{
+    va_list    args;
+
+    va_start(args, fmt);
+    ngx_log_error_core(NGX_LOG_ALERT, log, 0, fmt, args);
+    va_end(args);
+}
+
+#endif
diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h
new file mode 100644
index 0000000..54c96d3
--- /dev/null
+++ b/src/core/ngx_log.h
@@ -0,0 +1,118 @@
+#ifndef _NGX_LOG_H_INCLUDED_
+#define _NGX_LOG_H_INCLUDED_
+
+
+#include <ngx_errno.h>
+
+typedef enum {
+    NGX_LOG_EMERG = 0,
+    NGX_LOG_ALERT,
+    NGX_LOG_CRIT,
+    NGX_LOG_ERR,
+    NGX_LOG_WARN,
+    NGX_LOG_NOTICE,
+    NGX_LOG_INFO,
+    NGX_LOG_DEBUG
+} ngx_log_e;
+
+/*
+    "... while ", action = "reading client request headers"
+    "... while reading client request headers"
+    "... while ", action = "reading client request headers"
+                  context: pop3 user account
+    "... while reading client command for 'john_doe'"
+*/
+
+typedef struct {
+    int    log_level;
+    char  *action;
+    char  *context;
+/*  char  *func(ngx_log_t *log); */
+} ngx_log_t;
+
+#define MAX_ERROR_STR	2048
+
+#define _               ,
+
+
+#if (HAVE_GCC_VARIADIC_MACROS)
+
+#define HAVE_VARIADIC_MACROS  1
+
+#define ngx_log_error(level, log, args...) \
+        if (log->log_level >= level) ngx_log_error_core(level, log, args)
+
+#ifdef NGX_DEBUG
+#define ngx_log_debug(log, args...) \
+    if (log->log_level == NGX_LOG_DEBUG) \
+        ngx_log_error_core(NGX_LOG_DEBUG, log, 0, args)
+#else
+#define ngx_log_debug(log, args...)
+#endif
+
+#define ngx_assert(assert, fallback, log, args...) \
+        if (!(assert)) { \
+            if (log->log_level >= NGX_LOG_ALERT) \
+                ngx_log_error_core(NGX_LOG_ALERT, log, 0, args); \
+            fallback; \
+        }
+
+void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
+                        const char *fmt, ...);
+
+#elif (HAVE_C99_VARIADIC_MACROS)
+
+#define HAVE_VARIADIC_MACROS  1
+
+#define ngx_log_error(level, log, ...) \
+        if (log->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
+
+#ifdef NGX_DEBUG
+#define ngx_log_debug(log, ...) \
+    if (log->log_level == NGX_LOG_DEBUG) \
+        ngx_log_error_core(NGX_LOG_DEBUG, log, 0, __VA_ARGS__)
+#else
+#define ngx_log_debug(log, ...)
+#endif
+
+#define ngx_assert(assert, fallback, log, ...) \
+        if (!(assert)) { \
+            if (log->log_level >= NGX_LOG_ALERT) \
+                ngx_log_error_core(NGX_LOG_ALERT, log, 0, __VA_ARGS__); \
+            fallback; \
+        }
+
+void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
+                        const char *fmt, ...);
+
+#else /* NO VARIADIC MACROS */
+
+#include <stdarg.h>
+
+#ifdef NGX_DEBUG
+#define ngx_log_debug(log, text) \
+    if (log->log_level == NGX_LOG_DEBUG) \
+        ngx_log_debug_core(log, text)
+#else
+#define ngx_log_debug(log, text)
+#endif
+
+#define ngx_assert(assert, fallback, log, text) \
+        if (!(assert)) { \
+            if (log->log_level >= NGX_LOG_ALERT) \
+                ngx_assert_core(log, text); \
+            fallback; \
+        }
+
+void ngx_log_error(int level, ngx_log_t *log, ngx_err_t err,
+                   const char *fmt, ...);
+void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
+                        const char *fmt, va_list args);
+void ngx_log_debug_core(ngx_log_t *log, const char *fmt, ...);
+void ngx_assert_core(ngx_log_t *log, const char *fmt, ...);
+
+
+#endif /* VARIADIC MACROS */
+
+
+#endif /* _NGX_LOG_H_INCLUDED_ */
diff --git a/src/core/ngx_server.h b/src/core/ngx_server.h
new file mode 100644
index 0000000..88eb438
--- /dev/null
+++ b/src/core/ngx_server.h
@@ -0,0 +1,30 @@
+#ifndef _NGX_SERVER_H_INCLUDED_
+#define _NGX_SERVER_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_alloc.h>
+
+typedef struct {
+    int          log_level;
+    ngx_pool_t  *pool;
+    int        (*handler)(void *data);
+    int          buff_size;
+} ngx_server_t;
+
+
+typedef struct {
+    ngx_socket_t  fd;
+
+    ngx_log_t    *log;
+    ngx_server_t *server;
+
+    unsigned      shared:1;
+#if (HAVE_DEFERRED_ACCEPT)
+    unsigned      accept_filter:1;
+#endif
+} ngx_listen_t;
+
+
+#endif /* _NGX_SERVER_H_INCLUDED_ */
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
new file mode 100644
index 0000000..9e32b56
--- /dev/null
+++ b/src/core/ngx_string.c
@@ -0,0 +1,21 @@
+
+#include <ngx_config.h>
+#include <ngx_string.h>
+
+
+char *ngx_cpystrn(char *dst, char *src, size_t n)
+{
+    if (n == 0)
+        return dst;
+
+    for (/* void */; --n; dst++, src++) {
+        *dst = *src;
+
+        if (*dst == '\0')
+            return dst;
+    }
+
+    *dst = '\0';
+
+    return dst;
+}
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
new file mode 100644
index 0000000..0a78a06
--- /dev/null
+++ b/src/core/ngx_string.h
@@ -0,0 +1,26 @@
+#ifndef _NGX_STRING_H_INCLUDED_
+#define _NGX_STRING_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+
+#if (WIN32)
+
+#define ngx_snprintf              _snprintf
+#define ngx_vsnprintf             _vsnprintf
+
+#else
+
+#define ngx_snprintf              snprintf
+#define ngx_vsnprintf             vsnprintf
+
+#endif
+
+#define ngx_memcpy(dst, src, n)   memcpy(dst, src, n)
+#define ngx_cpymem(dst, src, n)   memcpy(dst, src, n) + n
+
+char *ngx_cpystrn(char *dst, char *src, size_t n);
+
+
+#endif /* _NGX_STRING_H_INCLUDED_ */