changeset 92:45945fa8b8ba NGINX_0_2_0

nginx 0.2.0 *) The pid-file names used during online upgrade was changed and now is not required a manual rename operation. The old master process adds the ".oldbin" suffix to its pid-file and executes a new binary file. The new master process creates usual pid-file without the ".newbin" suffix. If the master process exits, then old master process renames back its pid-file with the ".oldbin" suffix to the pid-file without suffix. *) Change: the "worker_connections" directive, new name of the "connections" directive; now the directive specifies maximum number of connections, but not maximum socket descriptor number. *) Feature: SSL supports the session cache inside one worker process. *) Feature: the "satisfy_any" directive. *) Change: the ngx_http_access_module and ngx_http_auth_basic_module do not run for subrequests. *) Feature: the "worker_rlimit_nofile" and "worker_rlimit_sigpending" directives. *) Bugfix: if all backend using in load-balancing failed after one error, then nginx did not try do connect to them during 60 seconds. *) Bugfix: in IMAP/POP3 command argument parsing. Thanks to Rob Mueller. *) Bugfix: errors while using SSL in IMAP/POP3 proxy. *) Bugfix: errors while using SSI and gzipping. *) Bugfix: the "Expires" and "Cache-Control" header lines were omitted from the 304 responses. Thanks to Alexandr Kukushkin.
author Igor Sysoev <http://sysoev.ru>
date Fri, 23 Sep 2005 00:00:00 +0400
parents c3eee83ea942
children dc5348c07fbf
files CHANGES CHANGES.ru auto/init auto/summary src/core/nginx.c src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_connection.c src/core/ngx_connection.h src/core/ngx_cycle.c src/core/ngx_cycle.h src/core/ngx_log.h src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_poll_module.c src/event/modules/ngx_rtsig_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_connect.c src/event/ngx_event_connect.h src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_static_module.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c src/imap/ngx_imap.h src/imap/ngx_imap_auth_http_module.c src/imap/ngx_imap_core_module.c src/imap/ngx_imap_handler.c src/imap/ngx_imap_parse.c src/imap/ngx_imap_proxy_module.c src/imap/ngx_imap_ssl_module.c src/os/unix/ngx_channel.c src/os/unix/ngx_channel.h src/os/unix/ngx_errno.h src/os/unix/ngx_process.c src/os/unix/ngx_process.h src/os/unix/ngx_process_cycle.c
diffstat 46 files changed, 1163 insertions(+), 678 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,40 @@
+
+Changes with nginx 0.2.0                                         23 Sep 2005
+
+    *) The pid-file names used during online upgrade was changed and now is 
+       not required a manual rename operation. The old master process adds 
+       the ".oldbin" suffix to its pid-file and executes a new binary file. 
+       The new master process creates usual pid-file without the ".newbin" 
+       suffix. If the master process exits, then old master process renames 
+       back its pid-file with the ".oldbin" suffix to the pid-file without 
+       suffix.
+
+    *) Change: the "worker_connections" directive, new name of the 
+       "connections" directive; now the directive specifies maximum number 
+       of connections, but not maximum socket descriptor number.
+
+    *) Feature: SSL supports the session cache inside one worker process.
+
+    *) Feature: the "satisfy_any" directive.
+
+    *) Change: the ngx_http_access_module and ngx_http_auth_basic_module do 
+       not run for subrequests.
+
+    *) Feature: the "worker_rlimit_nofile" and "worker_rlimit_sigpending" 
+       directives.
+
+    *) Bugfix: if all backend using in load-balancing failed after one 
+       error, then nginx did not try do connect to them during 60 seconds.
+
+    *) Bugfix: in IMAP/POP3 command argument parsing. Thanks to Rob Mueller.
+
+    *) Bugfix: errors while using SSL in IMAP/POP3 proxy.
+
+    *) Bugfix: errors while using SSI and gzipping.
+
+    *) Bugfix: the "Expires" and "Cache-Control" header lines were omitted 
+       from the 304 responses. Thanks to Alexandr Kukushkin.
+
 
 Changes with nginx 0.1.45                                        08 Sep 2005
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,45 @@
+
+Изменения в nginx 0.2.0                                           23.09.2005
+
+    *) Изменились имена pid-файлов, используемые во время обновления 
+       исполняемого файла. Ручное переименование теперь не нужно. Старый 
+       основной процесс добавляет к своему pid-файл суффикс ".oldbin" и 
+       запускает новый исполняемый файл. Новый основной процесс создаёт 
+       обычный pid-файл без суффикса ".newbin". Если новый основной процесс 
+       выходит, то старый процесс переименовывает свой pid-файл c суффиксом 
+       ".oldbin" в pid-файл без суффикса. При обновлении с версии 0.1.х до 
+       0.2.0 нужно учитывать, что старый процесс 0.1.x и новый процесс 
+       0.2.0 оба используют pid-файл без суффиксов.
+
+    *) Изменение: директива worker_connections, новое название директивы 
+       connections; директива теперь задаёт максимальное число соединений, 
+       а не максимально возможный номер дескриптора для сокета.
+
+    *) Добавление: SSL поддерживает кэширование сессий в пределах одного 
+       рабочего процесса.
+
+    *) Добавление: директива satisfy_any.
+
+    *) Изменение: модули ngx_http_access_module и 
+       ngx_http_auth_basic_module не работают для подзапросов.
+
+    *) Добавление: директивы worker_rlimit_nofile и 
+       worker_rlimit_sigpending.
+
+    *) Исправление: если все бэкенды, используемые для балансировки 
+       нагрузки, оказывались в нерабочем состоянии после одной ошибки, то 
+       nginx не обращался к ним в течение 60 секунд.
+
+    *) Исправление: в парсинге аргументов IMAP/POP3 команд. Спасибо Rob 
+       Mueller.
+
+    *) Исправление: ошибки при использовании SSL в IMAP/POP3 прокси.
+
+    *) Исправление: ошибки при использовании SSI и сжатия.
+
+    *) Исправление: в ответах 304 не добавлялись строки заголовка ответа 
+       "Expires" и "Cache-Control". Спасибо Александру Кукушкину.
+
 
 Изменения в nginx 0.1.45                                          08.09.2005
 
--- a/auto/init
+++ b/auto/init
@@ -54,8 +54,16 @@ clean:
 
 upgrade:
 	$NGX_SBIN_PATH -t
+
+	# upgrade compatibility from 0.1.x to 0.2.x
+	cp $NGX_PID_PATH $NGX_PID_PATH.oldbin
+
 	kill -USR2 \`cat $NGX_PID_PATH\`
 	sleep 1
-	test -f $NGX_PID_PATH.newbin
-	kill -WINCH \`cat $NGX_PID_PATH\`
+	test -f $NGX_PID_PATH.oldbin
+
+	# upgrade compatibility from 0.1.x to 0.2.x
+	cp $NGX_PID_PATH $NGX_PID_PATH.newbin
+
+	kill -WINCH \`cat $NGX_PID_PATH.oldbin\`
 END
--- a/auto/summary
+++ b/auto/summary
@@ -2,6 +2,21 @@
 # Copyright (C) Igor Sysoev
 
 
+### STUB
+
+if [ $USE_THREADS != NO ]; then
+
+cat << END
+
+$0: error: the threads support is broken now.
+
+END
+        exit 1
+    fi
+
+###
+
+
 echo
 echo "Configuration summary"
 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -42,6 +42,13 @@ static ngx_command_t  ngx_core_commands[
       offsetof(ngx_core_conf_t, master),
       NULL },
 
+    { ngx_string("pid"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      0,
+      offsetof(ngx_core_conf_t, pid),
+      NULL },
+
     { ngx_string("worker_processes"),
       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
@@ -56,6 +63,41 @@ static ngx_command_t  ngx_core_commands[
       offsetof(ngx_core_conf_t, debug_points),
       &ngx_debug_points },
 
+    { ngx_string("user"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,
+      ngx_set_user,
+      0,
+      0,
+      NULL },
+
+    { ngx_string("worker_priority"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_set_priority,
+      0,
+      0,
+      NULL },
+
+    { ngx_string("worker_rlimit_nofile"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      0,
+      offsetof(ngx_core_conf_t, rlimit_nofile),
+      NULL },
+
+    { ngx_string("worker_rlimit_sigpending"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      0,
+      offsetof(ngx_core_conf_t, rlimit_sigpending),
+      NULL },
+
+    { ngx_string("working_directory"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      0,
+      offsetof(ngx_core_conf_t, working_directory),
+      NULL },
+
 #if (NGX_THREADS)
 
     { ngx_string("worker_threads"),
@@ -74,34 +116,6 @@ static ngx_command_t  ngx_core_commands[
 
 #endif
 
-    { ngx_string("user"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,
-      ngx_set_user,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("worker_priority"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
-      ngx_set_priority,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("pid"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
-      0,
-      offsetof(ngx_core_conf_t, pid),
-      NULL },
-
-    { ngx_string("working_directory"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
-      0,
-      offsetof(ngx_core_conf_t, working_directory),
-      NULL },
-
       ngx_null_command
 };
 
@@ -324,13 +338,15 @@ ngx_add_inherited_sockets(ngx_cycle_t *c
 }
 
 
-ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
+ngx_pid_t
+ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
 {
     char             *env[3], *var;
     u_char           *p;
     ngx_uint_t        i;
     ngx_pid_t         pid;
     ngx_exec_ctx_t    ctx;
+    ngx_core_conf_t  *ccf;
     ngx_listening_t  *ls;
 
     ctx.path = argv[0];
@@ -374,15 +390,42 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_
 
     ctx.envp = (char *const *) &env;
 
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+    if (ngx_rename_file((char *) ccf->pid.data, (char *) ccf->oldpid.data)
+        != NGX_OK)
+    {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      ngx_rename_file_n " %s to %s failed "
+                      "before executing new binary process \"%s\"",
+                      ccf->pid.data, ccf->oldpid.data, argv[0]);
+
+        ngx_free(var);
+
+        return NGX_INVALID_PID;
+    }
+
     pid = ngx_execute(cycle, &ctx);
 
+    if (pid == NGX_INVALID_PID) {
+        if (ngx_rename_file((char *) ccf->oldpid.data, (char *) ccf->pid.data)
+            != NGX_OK)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          ngx_rename_file_n " %s back to %s failed "
+                          "after try to executing new binary process \"%s\"",
+                          ccf->oldpid.data, ccf->pid.data, argv[0]);
+        }
+    }
+
     ngx_free(var);
 
     return pid;
 }
 
 
-static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv)
+static ngx_int_t
+ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv)
 {
     ngx_int_t  i;
 
@@ -485,7 +528,7 @@ ngx_core_module_create_conf(ngx_cycle_t 
      * set by pcalloc()
      *
      *     ccf->pid = NULL;
-     *     ccf->newpid = NULL;
+     *     ccf->oldpid = NULL;
      *     ccf->priority = 0;
      */
 
@@ -493,8 +536,13 @@ ngx_core_module_create_conf(ngx_cycle_t 
     ccf->master = NGX_CONF_UNSET;
     ccf->worker_processes = NGX_CONF_UNSET;
     ccf->debug_points = NGX_CONF_UNSET;
+
+    ccf->rlimit_nofile = NGX_CONF_UNSET;
+    ccf->rlimit_sigpending = NGX_CONF_UNSET;
+
     ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT;
     ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT;
+
 #if (NGX_THREADS)
     ccf->worker_threads = NGX_CONF_UNSET;
     ccf->thread_stack_size = NGX_CONF_UNSET_SIZE;
@@ -558,15 +606,15 @@ ngx_core_module_init_conf(ngx_cycle_t *c
         return NGX_CONF_ERROR;
     }
 
-    ccf->newpid.len = ccf->pid.len + sizeof(NGX_NEWPID_EXT);
+    ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT);
 
-    ccf->newpid.data = ngx_palloc(cycle->pool, ccf->newpid.len);
-    if (ccf->newpid.data == NULL) {
+    ccf->oldpid.data = ngx_palloc(cycle->pool, ccf->oldpid.len);
+    if (ccf->oldpid.data == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    ngx_memcpy(ngx_cpymem(ccf->newpid.data, ccf->pid.data, ccf->pid.len),
-               NGX_NEWPID_EXT, sizeof(NGX_NEWPID_EXT));
+    ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len),
+               NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT));
 
 #endif
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,10 +8,10 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.45"
+#define NGINX_VER          "nginx/0.2.0"
 
 #define NGINX_VAR          "NGINX"
-#define NGX_NEWPID_EXT     ".newbin"
+#define NGX_OLDPID_EXT     ".oldbin"
 
 
 #endif /* _NGINX_H_INCLUDED_ */
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -62,6 +62,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
     char             *rv;
     ngx_fd_t          fd;
     ngx_int_t         rc;
+    ngx_uint_t        block;
     ngx_conf_file_t  *prev;
 
 #if (NGX_SUPPRESS_WARN)
@@ -103,13 +104,20 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
         cf->conf_file->file.offset = 0;
         cf->conf_file->file.log = cf->log;;
         cf->conf_file->line = 1;
+
+        block = 0;
+
+    } else {
+        block = 1;
     }
 
+
     for ( ;; ) {
         rc = ngx_conf_read_token(cf);
 
         /*
          * ngx_conf_read_token() may return
+         *
          *    NGX_ERROR             there is error
          *    NGX_OK                the token terminated by ";" was found
          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
@@ -121,6 +129,19 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
             break;
         }
 
+        if (rc == NGX_CONF_BLOCK_DONE) {
+            block = 0;
+        }
+
+        if (rc == NGX_CONF_FILE_DONE && block) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                         "unexpected end of file in %s:%ui, expecting \"}\"",
+                         cf->conf_file->file.name.data,
+                         cf->conf_file->line);
+            rc = NGX_ERROR;
+            break;
+        }
+
         if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) {
             break;
         }
@@ -639,7 +660,7 @@ ngx_conf_full_name(ngx_cycle_t *cycle, n
 
     name->len = cycle->root.len + old.len;
 
-    if (cycle->connections) {
+    if (cycle->connections0) {
         name->data = ngx_palloc(cycle->pool, name->len + 1);
         if (name->data == NULL) {
             return  NGX_ERROR;
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -237,13 +237,14 @@ ngx_open_listening_sockets(ngx_cycle_t *
             }
 
 #if (NGX_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_log_error(NGX_LOG_EMERG, log, 0,
                               ngx_socket_n " created socket %d", s);
                 return NGX_ERROR;
             }
@@ -329,9 +330,9 @@ ngx_open_listening_sockets(ngx_cycle_t *
 void
 ngx_close_listening_sockets(ngx_cycle_t *cycle)
 {
-    ngx_uint_t        i;
-    ngx_socket_t      fd;
-    ngx_listening_t  *ls;
+    ngx_uint_t         i;
+    ngx_listening_t   *ls;
+    ngx_connection_t  *c;
 
     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
         return;
@@ -342,35 +343,87 @@ ngx_close_listening_sockets(ngx_cycle_t 
 
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
-        fd = ls[i].fd;
 
-#if (NGX_WIN32)
-        /*
-         * Winsock assignes a socket number divisible by 4
-         * so to find a connection we divide a socket number by 4.
-         */
-
-        fd /= 4;
-#endif
+        c = ls[i].connection;
 
         if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
-            if (cycle->connections[fd].read->active) {
-                ngx_del_conn(&cycle->connections[fd], NGX_CLOSE_EVENT);
+            if (c->read->active) {
+                ngx_del_conn(c, NGX_CLOSE_EVENT);
             }
 
         } else {
-            if (cycle->read_events[fd].active) {
-                ngx_del_event(&cycle->read_events[fd],
-                              NGX_READ_EVENT, NGX_CLOSE_EVENT);
+            if (c->read->active) {
+                ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
             }
         }
 
-        if (ngx_close_socket(fd) == -1) {
+        ngx_free_connection(c);
+
+        c->fd = (ngx_socket_t) -1;
+
+        if (ngx_close_socket(ls[i].fd) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
         }
+    }
+}
 
-        cycle->connections[fd].fd = (ngx_socket_t) -1;
+
+ngx_connection_t *
+ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
+{
+    ngx_connection_t *c;
+
+    /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
+
+    if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "the new socket has number %d, "
+                      "but only %ui files are available",
+                      s, ngx_cycle->files_n);
+        return NULL;
+    }
+
+    /* ngx_mutex_lock */
+
+    c = ngx_cycle->free_connections;
+
+    if (c == NULL) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "%ui worker_connections is not enough",
+                      ngx_cycle->connection_n);
+
+        /* ngx_mutex_unlock */
+
+        return NULL;
+    }
+
+    ngx_cycle->free_connections = c->data;
+    ngx_cycle->free_connection_n--;
+
+    /* ngx_mutex_unlock */
+
+    if (ngx_cycle->files) {
+        ngx_cycle->files[s] = c;
+    }
+
+    return c;
+}
+
+
+void
+ngx_free_connection(ngx_connection_t *c)
+{
+    /* ngx_mutex_lock */
+
+    c->data = ngx_cycle->free_connections;
+    ngx_cycle->free_connections = c;
+    ngx_cycle->free_connection_n++;
+
+    /* ngx_mutex_unlock */
+
+    if (ngx_cycle->files) {
+        ngx_cycle->files[c->fd] = NULL;
     }
 }
 
@@ -451,9 +504,10 @@ ngx_close_connection(ngx_connection_t *c
 
 #endif
 
+    ngx_free_connection(c);
+
     fd = c->fd;
     c->fd = (ngx_socket_t) -1;
-    c->data = NULL;
 
     if (ngx_close_socket(fd) == -1) {
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -12,54 +12,60 @@
 #include <ngx_core.h>
 
 
-typedef struct {
-    ngx_socket_t      fd;
+typedef struct ngx_listening_s  ngx_listening_t;
+
+struct ngx_listening_s {
+    ngx_socket_t        fd;
 
-    struct sockaddr  *sockaddr;
-    socklen_t         socklen;    /* size of sockaddr */
-    size_t            addr;       /* offset to address in sockaddr */
-    size_t            addr_text_max_len;
-    ngx_str_t         addr_text;
+    struct sockaddr    *sockaddr;
+    socklen_t           socklen;    /* size of sockaddr */
+    size_t              addr;       /* offset to address in sockaddr */
+    size_t              addr_text_max_len;
+    ngx_str_t           addr_text;
 
-    int               family;
-    int               type;
+    int                 family;
+    int                 type;
+    int                 backlog;
 
-    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 */
+    /* handler of accepted connection */
+    void              (*handler)(ngx_connection_t *c);
+
+    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;
+    ngx_log_t           log;
 
-    size_t            pool_size;
-    size_t            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 */
+    size_t              pool_size;
+    /* should be here because of the AcceptEx() preread */
+    size_t              post_accept_buffer_size;
+    /* should be here because of the deferred accept */
+    time_t              post_accept_timeout;
+
+    ngx_listening_t    *previous;
+    ngx_connection_t   *connection;
 
-    unsigned          open:1;
-    unsigned          remain:1;
-    unsigned          ignore:1;
+    unsigned            open:1;
+    unsigned            remain:1;
+    unsigned            ignore:1;
 
-    unsigned          bound:1;       /* already bound */
-    unsigned          inherited:1;   /* inherited from previous process */
-    unsigned          nonblocking_accept:1;
-    unsigned          change_backlog:1;
-    unsigned          nonblocking:1;
-    unsigned          shared:1;    /* shared between threads or processes */
-    unsigned          addr_ntop:1;
+    unsigned            bound:1;       /* already bound */
+    unsigned            inherited:1;   /* inherited from previous process */
+    unsigned            nonblocking_accept:1;
+    unsigned            change_backlog:1;
+    unsigned            nonblocking:1;
+    unsigned            shared:1;    /* shared between threads or processes */
+    unsigned            addr_ntop:1;
 
 #if (NGX_HAVE_DEFERRED_ACCEPT)
-    unsigned          deferred_accept:1;
-    unsigned          delete_deferred:1;
-    unsigned          add_deferred:1;
+    unsigned            deferred_accept:1;
+    unsigned            delete_deferred:1;
+    unsigned            add_deferred:1;
 #ifdef SO_ACCEPTFILTER
-    char             *accept_filter;
+    char               *accept_filter;
 #endif
 #endif
 
-} ngx_listening_t;
+};
 
 
 typedef enum {
@@ -160,8 +166,8 @@ void ngx_close_listening_sockets(ngx_cyc
 void ngx_close_connection(ngx_connection_t *c);
 ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text);
 
-
-extern ngx_os_io_t  ngx_io;
+ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
+void ngx_free_connection(ngx_connection_t *c);
 
 
 #endif /* _NGX_CONNECTION_H_INCLUDED_ */
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -336,7 +336,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
                         }
 
                         nls[n].fd = ls[i].fd;
-                        nls[n].remain = 1;
+                        nls[n].previous = &ls[i];
                         ls[i].remain = 1;
 
                         if (ls[n].backlog != nls[i].backlog) {
@@ -594,7 +594,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
 
         if (ngx_close_socket(ls[i].fd) == -1) {
             ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                          ngx_close_socket_n " %V failed",
+                          ngx_close_socket_n " listening socket on %V failed",
                           &ls[i].addr_text);
         }
     }
@@ -627,7 +627,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
         }
     }
 
-    if (old_cycle->connections == NULL) {
+    if (old_cycle->connections0 == NULL) {
         /* an old cycle is an init cycle */
         ngx_destroy_pool(old_cycle->pool);
         return cycle;
@@ -742,7 +742,8 @@ ngx_int_t ngx_create_pidfile(ngx_cycle_t
     }
 
     ngx_memzero(&file, sizeof(ngx_file_t));
-    file.name = (ngx_inherited && getppid() > 1) ? ccf->newpid : ccf->pid;
+
+    file.name = ccf->pid;
     file.log = cycle->log;
 
     trunc = ngx_test_config ? 0: NGX_FILE_TRUNCATE;
@@ -786,12 +787,7 @@ void ngx_delete_pidfile(ngx_cycle_t *cyc
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
-    if (ngx_inherited && getppid() > 1) {
-        name = ccf->newpid.data;
-
-    } else { 
-        name = ccf->pid.data;
-    }
+    name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data;
 
     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
@@ -963,7 +959,7 @@ static void ngx_clean_old_cycles(ngx_eve
         found = 0;
 
         for (n = 0; n < cycle[i]->connection_n; n++) {
-            if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) {
+            if (cycle[i]->connections0[n].fd != (ngx_socket_t) -1) {
                 found = 1;
 
                 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%d", n);
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -28,14 +28,20 @@ struct ngx_cycle_s {
     ngx_log_t                *log;
     ngx_log_t                *new_log;
 
+    ngx_connection_t        **files;
+    ngx_connection_t         *free_connections;
+    ngx_uint_t                free_connection_n;
+
     ngx_array_t               listening;
     ngx_array_t               pathes;
     ngx_list_t                open_files;
 
     ngx_uint_t                connection_n;
-    ngx_connection_t         *connections;
-    ngx_event_t              *read_events;
-    ngx_event_t              *write_events;
+    ngx_uint_t                files_n;
+
+    ngx_connection_t         *connections0;
+    ngx_event_t              *read_events0;
+    ngx_event_t              *write_events0;
 
     ngx_cycle_t              *old_cycle;
 
@@ -51,6 +57,9 @@ typedef struct {
      ngx_int_t                worker_processes;
      ngx_int_t                debug_points;
 
+     ngx_int_t                rlimit_nofile;
+     ngx_int_t                rlimit_sigpending;
+
      int                      priority;
 
      char                    *username;
@@ -60,7 +69,7 @@ typedef struct {
      ngx_str_t                working_directory;
 
      ngx_str_t                pid;
-     ngx_str_t                newpid;
+     ngx_str_t                oldpid;
 
 #if (NGX_THREADS)
      ngx_int_t                worker_threads;
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -72,13 +72,13 @@ struct ngx_log_s {
 #define NGX_HAVE_VARIADIC_MACROS  1
 
 #define ngx_log_error(level, log, args...)                                    \
-    if (log->log_level >= level) ngx_log_error_core(level, log, args)
+    if ((log)->log_level >= level) ngx_log_error_core(level, log, args)
 
 void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
     const char *fmt, ...);
 
 #define ngx_log_debug(level, log, args...)                                    \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_error_core(NGX_LOG_DEBUG, log, args)
 
 /*********************************/
@@ -88,13 +88,13 @@ void ngx_log_error_core(ngx_uint_t level
 #define NGX_HAVE_VARIADIC_MACROS  1
 
 #define ngx_log_error(level, log, ...)                                        \
-    if (log->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
+    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
 
 void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
     const char *fmt, ...);
 
 #define ngx_log_debug(level, log, ...)                                        \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)
 
 /*********************************/
@@ -134,43 +134,43 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo
 #else /* NO VARIADIC MACROS */
 
 #define ngx_log_debug0(level, log, err, fmt)                                  \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt)
 
 #define ngx_log_debug1(level, log, err, fmt, arg1)                            \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1)
 
 #define ngx_log_debug2(level, log, err, fmt, arg1, arg2)                      \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1, arg2)
 
 #define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3)                \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3)
 
 #define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4)          \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4)
 
 #define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5)    \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5)
 
 #define ngx_log_debug6(level, log, err, fmt,                                  \
                        arg1, arg2, arg3, arg4, arg5, arg6)                    \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
 
 #define ngx_log_debug7(level, log, err, fmt,                                  \
                        arg1, arg2, arg3, arg4, arg5, arg6, arg7)              \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt,                                     \
                        arg1, arg2, arg3, arg4, arg5, arg6, arg7)
 
 #define ngx_log_debug8(level, log, err, fmt,                                  \
                        arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)        \
-    if (log->log_level & level)                                               \
+    if ((log)->log_level & level)                                             \
         ngx_log_debug_core(log, err, fmt,                                     \
                        arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
 
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -177,7 +177,7 @@ ngx_devpoll_init(ngx_cycle_t *cycle)
 
     ngx_event_actions = ngx_devpoll_module_ctx.actions;
 
-    ngx_event_flags = NGX_USE_LEVEL_EVENT;
+    ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
 
     return NGX_OK;
 }
@@ -449,10 +449,10 @@ ngx_devpoll_process_events(ngx_cycle_t *
     lock = 1;
 
     for (i = 0; i < events; i++) {
-        c = &ngx_cycle->connections[event_list[i].fd];
+        c = ngx_cycle->files[event_list[i].fd];
 
         if (c->fd == -1) {
-            if (ngx_cycle->read_events[event_list[i].fd].closed) {
+            if (c->read->closed) {
                 continue;
             }
 
@@ -460,26 +460,6 @@ ngx_devpoll_process_events(ngx_cycle_t *
             continue;
         }
 
-#if 0
-        if (c->fd == -1) {
-            old_cycle = ngx_old_cycles.elts;
-            for (j = 0; j < ngx_old_cycles.nelts; j++) {
-                if (old_cycle[j] == NULL) {
-                    continue;
-                }
-                c = &old_cycle[j]->connections[event_list[i].fd];
-                if (c->fd != -1) {
-                    break;
-                }
-            }
-        }
-
-        if (c->fd == -1) {
-            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "unknown cycle");
-            exit(1);
-        }
-#endif
-
         revents = event_list[i].revents;
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -109,7 +109,9 @@ ngx_poll_init(ngx_cycle_t *cycle)
 
     ngx_event_actions = ngx_poll_module_ctx.actions;
 
-    ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_ONESHOT_EVENT;
+    ngx_event_flags = NGX_USE_LEVEL_EVENT
+                      |NGX_USE_ONESHOT_EVENT
+                      |NGX_USE_FD_EVENT;
 
     return NGX_OK;
 }
@@ -229,7 +231,7 @@ ngx_poll_del_event(ngx_event_t *ev, int 
 
             event_list[ev->index] = event_list[nevents];
 
-            c = &ngx_cycle->connections[event_list[nevents].fd];
+            c = ngx_cycle->files[event_list[nevents].fd];
 
             if (c->fd == -1) {
                 cycle = ngx_old_cycles.elts;
@@ -237,7 +239,7 @@ ngx_poll_del_event(ngx_event_t *ev, int 
                     if (cycle[i] == NULL) {
                         continue;
                     }
-                    c = &cycle[i]->connections[event_list[nevents].fd];
+                    c = cycle[i]->files[event_list[nevents].fd];
                     if (c->fd != -1) {
                         break;
                     }
@@ -425,7 +427,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
             continue;
         }
 
-        c = &ngx_cycle->connections[event_list[i].fd];
+        c = ngx_cycle->files[event_list[i].fd];
 
         if (c->fd == -1) {
             old_cycle = ngx_old_cycles.elts;
@@ -433,7 +435,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
                 if (old_cycle[n] == NULL) {
                     continue;
                 }
-                c = &old_cycle[n]->connections[event_list[i].fd];
+                c = old_cycle[n]->files[event_list[i].fd];
                 if (c->fd != -1) {
                     break;
                 }
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -165,7 +165,9 @@ ngx_rtsig_init(ngx_cycle_t *cycle)
 
     ngx_event_actions = ngx_rtsig_module_ctx.actions;
 
-    ngx_event_flags = NGX_USE_RTSIG_EVENT|NGX_USE_GREEDY_EVENT;
+    ngx_event_flags = NGX_USE_RTSIG_EVENT
+                      |NGX_USE_GREEDY_EVENT
+                      |NGX_USE_FD_EVENT;
 
     return NGX_OK;
 }
@@ -428,7 +430,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
 
         /* TODO: old_cycles */
 
-        c = &ngx_cycle->connections[si.si_fd];
+        c = ngx_cycle->files[si.si_fd];
 
         instance = signo - rtscf->signo;
 
@@ -596,7 +598,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
                 break;
             }
 
-            c = &cycle->connections[overflow_current++];
+            c = cycle->files[overflow_current++];
 
             if (c->fd == -1) {
                 continue;
@@ -652,7 +654,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
         }
 
         for (i = 0; i < n; i++) {
-            c = &cycle->connections[overflow_list[i].fd];
+            c = cycle->files[overflow_list[i].fd];
 
             rev = c->read;
 
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -113,6 +113,13 @@ static ngx_conf_post_t  ngx_accept_mutex
 
 static ngx_command_t  ngx_event_core_commands[] = {
 
+    { ngx_string("worker_connections"),
+      NGX_EVENT_CONF|NGX_CONF_TAKE1,
+      ngx_event_connections,
+      0,
+      0,
+      NULL },
+
     { ngx_string("connections"),
       NGX_EVENT_CONF|NGX_CONF_TAKE1,
       ngx_event_connections,
@@ -322,13 +329,15 @@ ngx_handle_write_event(ngx_event_t *wev,
 static ngx_int_t
 ngx_event_module_init(ngx_cycle_t *cycle)
 {
+    void              ***cf;
+    ngx_event_conf_t    *ecf;
 #if !(NGX_WIN32)
-
+    char                *shared;
     size_t               size;
-    void              ***cf;
-    char                *shared;
+    ngx_int_t            limit;
+    struct rlimit        rlmt;
     ngx_core_conf_t     *ccf;
-    ngx_event_conf_t    *ecf;
+#endif
 
     cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);
 
@@ -343,9 +352,30 @@ ngx_event_module_init(ngx_cycle_t *cycle
     ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                   "using the \"%s\" event method", ecf->name);
 
+#if !(NGX_WIN32)
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
+    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "getrlimit(RLIMIT_NOFILE) failed, ignored");
+
+    } else {
+        if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur
+            && (ccf->rlimit_nofile == NGX_CONF_UNSET
+                || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile))
+        {
+            limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ?
+                         (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile;
+
+            ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
+                          "%ui worker_connections are more than "
+                          "open file resource limit: %i",
+                          ecf->connections, limit);
+        }
+    }
+
+
     if (ccf->master == 0 || ngx_accept_mutex_ptr) {
         return NGX_OK;
     }
@@ -390,7 +420,7 @@ ngx_event_module_init(ngx_cycle_t *cycle
                    "counter: %p, %d",
                    ngx_connection_counter, *ngx_connection_counter);
 
-#endif
+#endif /* !(NGX_WIN32) */
 
     return NGX_OK;
 }
@@ -400,15 +430,16 @@ static ngx_int_t
 ngx_event_process_init(ngx_cycle_t *cycle)
 {
     ngx_uint_t           m, i;
-    ngx_socket_t         fd;
     ngx_event_t         *rev, *wev;
-    ngx_listening_t     *s;
-    ngx_connection_t    *c;
+    ngx_listening_t     *ls;
+    ngx_connection_t    *c, *next, *old;
     ngx_core_conf_t     *ccf;
     ngx_event_conf_t    *ecf;
     ngx_event_module_t  *module;
 #if (NGX_WIN32)
     ngx_iocp_conf_t     *iocpcf;
+#else
+    struct rlimit        rlmt;
 #endif
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
@@ -449,28 +480,42 @@ ngx_event_process_init(ngx_cycle_t *cycl
         }
     }
 
-    cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections,
+#if !(NGX_WIN32)
+
+    if (ngx_event_flags & NGX_USE_FD_EVENT) {
+
+        if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "getrlimit(RLIMIT_NOFILE) failed");
+            return NGX_ERROR;
+        }
+
+        cycle->files_n = (ngx_uint_t) rlmt.rlim_cur;
+
+        cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n,
+                                  cycle->log);
+        if (cycle->files == NULL) {
+            return NGX_ERROR;
+        }
+    }
+
+#endif
+
+    cycle->connections0 = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections,
                                    cycle->log);
-    if (cycle->connections == NULL) {
+    if (cycle->connections0 == NULL) {
         return NGX_ERROR;
     }
 
-    c = cycle->connections;
-    for (i = 0; i < cycle->connection_n; i++) {
-        c[i].fd = (ngx_socket_t) -1;
-        c[i].data = NULL;
-#if (NGX_THREADS)
-        c[i].lock = 0;
-#endif
-    }
+    c = cycle->connections0;
 
-    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,
+    cycle->read_events0 = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,
                                    cycle->log);
-    if (cycle->read_events == NULL) {
+    if (cycle->read_events0 == NULL) {
         return NGX_ERROR;
     }
 
-    rev = cycle->read_events;
+    rev = cycle->read_events0;
     for (i = 0; i < cycle->connection_n; i++) {
         rev[i].closed = 1;
         rev[i].instance = 1;
@@ -480,13 +525,13 @@ ngx_event_process_init(ngx_cycle_t *cycl
 #endif
     }
 
-    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,
+    cycle->write_events0 = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,
                                     cycle->log);
-    if (cycle->write_events == NULL) {
+    if (cycle->write_events0 == NULL) {
         return NGX_ERROR;
     }
 
-    wev = cycle->write_events;
+    wev = cycle->write_events0;
     for (i = 0; i < cycle->connection_n; i++) {
         wev[i].closed = 1;
 #if (NGX_THREADS)
@@ -495,41 +540,57 @@ ngx_event_process_init(ngx_cycle_t *cycl
 #endif
     }
 
+    i = cycle->connection_n;
+    next = NULL;
+
+    do {
+        i--;
+
+        c[i].data = next;
+        c[i].read = &cycle->read_events0[i];
+        c[i].write = &cycle->write_events0[i];
+        c[i].fd = (ngx_socket_t) -1;
+
+        next = &c[i];
+
+#if (NGX_THREADS)
+        c[i].lock = 0;
+#endif
+    } while (i);
+
+    cycle->free_connections = next;
+    cycle->free_connection_n = ecf->connections;
+
     /* for each listening socket */
 
-    s = cycle->listening.elts;
+    ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
 
-        fd = s[i].fd;
+        c = ngx_get_connection(ls[i].fd, cycle->log);
 
-#if (NGX_WIN32)
-        /*
-         * Winsock assignes a socket number divisible by 4
-         * so to find a connection we divide a socket number by 4.
-         */
+        if (c == NULL) {
+            return NGX_ERROR;
+        }
 
-        fd /= 4;
-#endif
-
-        c = &cycle->connections[fd];
-        rev = &cycle->read_events[fd];
-        wev = &cycle->write_events[fd];
+        rev = c->read;
+        wev = c->write;
 
         ngx_memzero(c, sizeof(ngx_connection_t));
+
+        c->read = rev;
+        c->write = wev;
+        c->fd = ls[i].fd;
+        c->log = &ls[i].log;
+
+        c->listening = &ls[i];
+        ls[i].connection = c;
+
+        c->ctx = ls[i].ctx;
+        c->servers = ls[i].servers;
+
         ngx_memzero(rev, sizeof(ngx_event_t));
         ngx_memzero(wev, sizeof(ngx_event_t));
 
-        c->fd = s[i].fd;
-        c->listening = &s[i];
-
-        c->ctx = s[i].ctx;
-        c->servers = s[i].servers;
-        c->log = s[i].log;
-        c->read = rev;
-
-        /* required by iocp in "c->write->active = 1" */
-        c->write = wev;
-
         /* required by poll */
         wev->index = NGX_INVALID_INDEX;
 
@@ -542,24 +603,26 @@ ngx_event_process_init(ngx_cycle_t *cycl
         rev->accept = 1;
 
 #if (NGX_HAVE_DEFERRED_ACCEPT)
-        rev->deferred_accept = s[i].deferred_accept;
+        rev->deferred_accept = ls[i].deferred_accept;
 #endif
 
         if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
-            if (s[i].remain) {
+            if (ls[i].previous) {
 
                 /*
                  * delete the old accept events that were bound to
                  * the old cycle read events array
                  */
 
-                if (ngx_del_event(&cycle->old_cycle->read_events[fd],
-                                 NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR)
+                old = ls[i].previous->connection;
+
+                if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT)
+                    == NGX_ERROR)
                 {
                     return NGX_ERROR;
                 }
 
-                cycle->old_cycle->connections[fd].fd = (ngx_socket_t) -1;
+                old->fd = (ngx_socket_t) -1;
             }
         }
 
@@ -572,9 +635,11 @@ ngx_event_process_init(ngx_cycle_t *cycl
                 return NGX_ERROR;
             }
 
+            ls[i].log.handler = ngx_acceptex_log_error;
+
             iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);
-            if (ngx_event_post_acceptex(&s[i], iocpcf->post_acceptex)
-                                                                  == NGX_ERROR)
+            if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex)
+                == NGX_ERROR)
             {
                 return NGX_ERROR;
             }
@@ -607,6 +672,7 @@ ngx_event_process_init(ngx_cycle_t *cycl
         }
 
 #endif
+
     }
 
     return NGX_OK;
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -218,63 +218,69 @@ extern ngx_event_actions_t   ngx_event_a
 
 
 /*
- * The event filter requires to read/write the whole data -
+ * The event filter requires to read/write the whole data:
  * select, poll, /dev/poll, kqueue, epoll.
  */
 #define NGX_USE_LEVEL_EVENT      0x00000001
 
 /*
  * The event filter is deleted after a notification without an additional
- * syscall - select, poll, kqueue, epoll, Solaris 10's event ports.
+ * syscall: select, poll, kqueue, epoll, Solaris 10's event ports.
  */
 #define NGX_USE_ONESHOT_EVENT    0x00000002
 
 /*
- * The event filter notifies only the changes and an initial level -
+ * The event filter notifies only the changes and an initial level:
  * kqueue, epoll.
  */
 #define NGX_USE_CLEAR_EVENT      0x00000004
 
 /*
- * The event filter has kqueue features - the eof flag, errno,
+ * The event filter has kqueue features: the eof flag, errno,
  * available data, etc.
  */
-#define NGX_USE_KQUEUE_EVENT    0x00000008
+#define NGX_USE_KQUEUE_EVENT     0x00000008
 
 /*
- * The event filter supports low water mark - kqueue's NOTE_LOWAT.
+ * The event filter supports low water mark: kqueue's NOTE_LOWAT.
  * kqueue in FreeBSD 4.1-4.2 has no NOTE_LOWAT so we need a separate flag.
  */
-#define NGX_USE_LOWAT_EVENT     0x00000010
+#define NGX_USE_LOWAT_EVENT      0x00000010
 
 /*
- * The event filter requires to do i/o operation until EAGAIN -
+ * The event filter requires to do i/o operation until EAGAIN:
  * epoll, rt signals.
  */
-#define NGX_USE_GREEDY_EVENT    0x00000020
+#define NGX_USE_GREEDY_EVENT     0x00000020
 
 /*
- * The event filter is epoll,
+ * The event filter is epoll.
  */
 #define NGX_USE_EPOLL_EVENT      0x00000040
 
 /*
- * No need to add or delete the event filters - rt signals.
+ * No need to add or delete the event filters: rt signals.
  */
 #define NGX_USE_RTSIG_EVENT      0x00000080
 
 /*
- * No need to add or delete the event filters - overlapped, aio_read,
+ * No need to add or delete the event filters: overlapped, aio_read,
  * aioread, io_submit.
  */
 #define NGX_USE_AIO_EVENT        0x00000100
 
 /*
- * Need to add socket or handle only once - i/o completion port.
+ * Need to add socket or handle only once: i/o completion port.
  * It also requires NGX_HAVE_AIO and NGX_USE_AIO_EVENT to be set.
  */
 #define NGX_USE_IOCP_EVENT       0x00000200
 
+/*
+ * The event filter has no opaque data and requires file descriptors table:
+ * poll, /dev/poll, rt signals.
+ */
+#define NGX_USE_FD_EVENT         0x00000400
+
 
 
 /*
@@ -391,13 +397,14 @@ extern ngx_event_actions_t   ngx_event_a
 #define ngx_del_timer        ngx_event_del_timer
 
 
+extern ngx_os_io_t  ngx_io;
+
 #define ngx_recv             ngx_io.recv
 #define ngx_recv_chain       ngx_io.recv_chain
 #define ngx_send             ngx_io.send
 #define ngx_send_chain       ngx_io.send_chain
 
 
-
 #define NGX_EVENT_MODULE      0x544E5645  /* "EVNT" */
 #define NGX_EVENT_CONF        0x02000000
 
@@ -471,6 +478,7 @@ void ngx_event_accept(ngx_event_t *ev);
 ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle);
 ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle);
 ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
+u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
 
 
 ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags);
@@ -479,7 +487,8 @@ ngx_int_t ngx_handle_write_event(ngx_eve
 
 #if (NGX_WIN32)
 void ngx_event_acceptex(ngx_event_t *ev);
-int ngx_event_post_acceptex(ngx_listening_t *ls, int n);
+ngx_int_t ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n);
+u_char *ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len);
 #endif
 
 
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -9,26 +9,26 @@
 #include <ngx_event.h>
 
 
-static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log);
-static u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
+/* the buffer size is enough to hold "struct sockaddr_un" */
+#define NGX_SOCKLEN  512
+
+
+static void ngx_close_accepted_connection(ngx_connection_t *c);
 
 
 void
 ngx_event_accept(ngx_event_t *ev)
 {
-    ngx_uint_t         instance;
-#if 0
-    ngx_uint_t         accepted;
-#endif
-    socklen_t          len;
-    struct sockaddr   *sa;
+    socklen_t          sl;
     ngx_err_t          err;
     ngx_log_t         *log;
-    ngx_pool_t        *pool;
+    ngx_uint_t         instance;
     ngx_socket_t       s;
     ngx_event_t       *rev, *wev;
-    ngx_connection_t  *c, *ls;
+    ngx_listening_t   *ls;
+    ngx_connection_t  *c, *lc;
     ngx_event_conf_t  *ecf;
+    char               sa[NGX_SOCKLEN];
 
     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
 
@@ -39,77 +39,28 @@ ngx_event_accept(ngx_event_t *ev)
         ev->available = ecf->multi_accept;
     }
 
-    ls = ev->data;
+    lc = ev->data;
+    ls = lc->listening;
+    ev->ready = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
-                   "accept on %V, ready: %d",
-                   &ls->listening->addr_text, ev->available);
-
-    ev->ready = 0;
-    pool = NULL;
-#if 0
-    accepted = 0;
-#endif
+                   "accept on %V, ready: %d", &ls->addr_text, ev->available);
 
     do {
-
-        if (pool == NULL) {
-
-            /*
-             * Create the pool before accept() to avoid the copying of
-             * the sockaddr.  Although accept() can fail it is uncommon
-             * case and besides the pool can be got from the free pool list.
-             */
-
-            pool = ngx_create_pool(ls->listening->pool_size, ev->log);
-            if (pool == NULL) {
-                return;
-            }
-        }
+        sl = NGX_SOCKLEN;
 
-        sa = ngx_palloc(pool, ls->listening->socklen);
-        if (sa == NULL) {
-            ngx_destroy_pool(pool);
-            return;
-        }
-
-        log = ngx_palloc(pool, sizeof(ngx_log_t));
-        if (log == NULL) {
-            ngx_destroy_pool(pool);
-            return;
-        }
-
-        ngx_memcpy(log, ls->log, sizeof(ngx_log_t));
-        pool->log = log;
-
-        log->data = &ls->listening->addr_text;
-        log->handler = ngx_accept_log_error;
-
-        len = ls->listening->socklen;
-
-        s = accept(ls->fd, sa, &len);
+        s = accept(lc->fd, (struct sockaddr *) sa, &sl);
 
         if (s == -1) {
             err = ngx_socket_errno;
 
             if (err == NGX_EAGAIN) {
-#if 0
-                if (!(ngx_event_flags & NGX_USE_RTSIG_EVENT))
-                {
-                    ngx_log_error(NGX_LOG_NOTICE, log, err,
-                                  "EAGAIN after %d accepted connection(s)",
-                                  accepted);
-                }
-#endif
-
-                ngx_destroy_pool(pool);
                 return;
             }
 
             ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_CRIT:
                                                       NGX_LOG_ALERT,
-                          ev->log, err,
-                          "accept() on %V failed", &ls->listening->addr_text);
+                          ev->log, err, "accept() failed");
 
             if (err == NGX_ECONNABORTED) {
                 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -117,12 +68,10 @@ ngx_event_accept(ngx_event_t *ev)
                 }
 
                 if (ev->available) {
-                    /* reuse the previously allocated pool */
                     continue;
                 }
             }
 
-            ngx_destroy_pool(pool);
             return;
         }
 
@@ -131,34 +80,58 @@ ngx_event_accept(ngx_event_t *ev)
         ngx_atomic_inc(ngx_stat_active);
 #endif
 
-        ngx_accept_disabled = (ngx_uint_t) s + NGX_ACCEPT_THRESHOLD
-                                                            - ecf->connections;
+        ngx_accept_disabled = NGX_ACCEPT_THRESHOLD
+                              - ngx_cycle->free_connection_n;
+
+        c = ngx_get_connection(s, ev->log);
 
-        /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
+        if (c == NULL) {
+            if (ngx_close_socket(s) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+                              ngx_close_socket_n " failed");
+            }
 
-        if ((ngx_uint_t) s >= ecf->connections) {
+            return;
+        }
+
+        rev = c->read;
+        wev = c->write;
+
+        ngx_memzero(c, sizeof(ngx_connection_t));
 
-            ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
-                          "accept() on %V returned socket #%d while "
-                          "only %d connections was configured, "
-                          "closing the connection",
-                          &ls->listening->addr_text, s, ecf->connections);
+        c->read = rev;
+        c->write = wev;
+        c->fd = s;
+        c->log = ev->log;
+
+        c->pool = ngx_create_pool(ls->pool_size, ev->log);
+        if (c->pool == NULL) {
+            ngx_close_accepted_connection(c);
+            return;
+        }
 
-            ngx_close_accepted_socket(s, log);
-            ngx_destroy_pool(pool);
+        c->sockaddr = ngx_palloc(c->pool, sl);
+        if (c->sockaddr == NULL) {
+            ngx_close_accepted_connection(c);
+            return;
+        }
+
+        ngx_memcpy(c->sockaddr, sa, sl);
+
+        log = ngx_palloc(c->pool, sizeof(ngx_log_t));
+        if (log == NULL) {
+            ngx_close_accepted_connection(c);
             return;
         }
 
         /* set a blocking mode for aio and non-blocking mode for others */
 
         if (ngx_inherited_nonblocking) {
-            if ((ngx_event_flags & NGX_USE_AIO_EVENT)) {
+            if (ngx_event_flags & NGX_USE_AIO_EVENT) {
                 if (ngx_blocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                   ngx_blocking_n " failed");
-
-                    ngx_close_accepted_socket(s, log);
-                    ngx_destroy_pool(pool);
+                    ngx_close_accepted_connection(c);
                     return;
                 }
             }
@@ -166,61 +139,35 @@ ngx_event_accept(ngx_event_t *ev)
         } else {
             if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
                 if (ngx_nonblocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                   ngx_nonblocking_n " failed");
-
-                    ngx_close_accepted_socket(s, log);
-                    ngx_destroy_pool(pool);
+                    ngx_close_accepted_connection(c);
                     return;
                 }
             }
         }
 
-#if (NGX_WIN32)
-        /*
-         * Winsock assignes a socket number divisible by 4
-         * so to find a connection we divide a socket number by 4.
-         */
+        *log = ls->log;
+
+        c->recv = ngx_recv;
+        c->send = ngx_send;
+        c->send_chain = ngx_send_chain;
 
-        if (s % 4) {
-            ngx_log_error(NGX_LOG_EMERG, ev->log, 0,
-                          "accept() on %V returned socket #%d, "
-                          "not divisible by 4",
-                          &ls->listening->addr_text, s);
-            exit(1);
-        }
+        c->log = log;
+        c->pool->log = log;
 
-        c = &ngx_cycle->connections[s / 4];
-        rev = &ngx_cycle->read_events[s / 4];
-        wev = &ngx_cycle->write_events[s / 4];
-#else
-        c = &ngx_cycle->connections[s];
-        rev = &ngx_cycle->read_events[s];
-        wev = &ngx_cycle->write_events[s];
-#endif
+        c->listening = ls;
+        c->socklen = sl;
+
+        c->unexpected_eof = 1;
+
+        c->ctx = lc->ctx;
+        c->servers = lc->servers;
 
         instance = rev->instance;
 
-#if (NGX_THREADS)
-
-        if (*(&c->lock)) {
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
-                           "spinlock in accept, fd:%d", s);
-            ngx_spinlock(&c->lock, 1000);
-            ngx_unlock(&c->lock);
-        }
-
-#endif
-
         ngx_memzero(rev, sizeof(ngx_event_t));
         ngx_memzero(wev, sizeof(ngx_event_t));
-        ngx_memzero(c, sizeof(ngx_connection_t));
-
-        c->pool = pool;
-
-        c->listening = ls->listening;
-        c->sockaddr = sa;
-        c->socklen = len;
 
         rev->instance = !instance;
         wev->instance = !instance;
@@ -231,12 +178,6 @@ ngx_event_accept(ngx_event_t *ev)
         rev->data = c;
         wev->data = c;
 
-        c->read = rev;
-        c->write = wev;
-
-        c->fd = s;
-        c->unexpected_eof = 1;
-
         wev->write = 1;
         wev->ready = 1;
 
@@ -252,14 +193,6 @@ ngx_event_accept(ngx_event_t *ev)
 #endif
         }
 
-        c->ctx = ls->ctx;
-        c->servers = ls->servers;
-
-        c->recv = ngx_recv;
-        c->send = ngx_send;
-        c->send_chain = ngx_send_chain;
-
-        c->log = log;
         rev->log = log;
         wev->log = log;
 
@@ -285,24 +218,21 @@ ngx_event_accept(ngx_event_t *ev)
         wev->own_lock = &c->lock;
 #endif
 
-        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
                        "accept: fd:%d c:%d", s, c->number);
 
-        if (c->listening->addr_ntop) {
-            c->addr_text.data = ngx_palloc(c->pool,
-                                           c->listening->addr_text_max_len);
+        if (ls->addr_ntop) {
+            c->addr_text.data = ngx_palloc(c->pool, ls->addr_text_max_len);
             if (c->addr_text.data == NULL) {
-                ngx_close_accepted_socket(s, log);
-                ngx_destroy_pool(pool);
+                ngx_close_accepted_connection(c);
                 return;
             }
     
-            c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr,
+            c->addr_text.len = ngx_sock_ntop(ls->family, c->sockaddr,
                                              c->addr_text.data,
-                                             c->listening->addr_text_max_len);
+                                             ls->addr_text_max_len);
             if (c->addr_text.len == 0) {
-                ngx_close_accepted_socket(s, log);
-                ngx_destroy_pool(pool);
+                ngx_close_accepted_connection(c);
                 return;
             }
         }
@@ -328,27 +258,20 @@ ngx_event_accept(ngx_event_t *ev)
 
         if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
             if (ngx_add_conn(c) == NGX_ERROR) {
-                ngx_close_accepted_socket(s, log);
-                ngx_destroy_pool(pool);
+                ngx_close_accepted_connection(c);
                 return;
             }
         }
 
-        pool = NULL;
-
         log->data = NULL;
         log->handler = NULL;
 
-        ls->listening->handler(c);
+        ls->handler(c);
 
         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
             ev->available--;
         }
 
-#if 0
-        accepted++;
-#endif
-
     } while (ev->available);
 }
 
@@ -389,27 +312,22 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cy
 ngx_int_t
 ngx_enable_accept_events(ngx_cycle_t *cycle)
 {
-    ngx_uint_t        i;
-    ngx_listening_t  *s;
+    ngx_uint_t         i;
+    ngx_listening_t   *ls;
+    ngx_connection_t  *c;
 
-    s = cycle->listening.elts;
+    ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
 
-        /*
-         * we do not need to handle the Winsock sockets here (divide a socket
-         * number by 4) because this function would never called
-         * in the Winsock environment
-         */
+        c = ls[i].connection;
 
         if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
-            if (ngx_add_conn(&cycle->connections[s[i].fd]) == NGX_ERROR) {
+            if (ngx_add_conn(c) == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
         } else {
-            if (ngx_add_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT, 0)
-                                                                  == NGX_ERROR)
-            {
+            if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
                 return NGX_ERROR;
             }
         }
@@ -422,36 +340,27 @@ ngx_enable_accept_events(ngx_cycle_t *cy
 ngx_int_t
 ngx_disable_accept_events(ngx_cycle_t *cycle)
 {
-    ngx_uint_t        i;
-    ngx_listening_t  *s;
+    ngx_uint_t         i;
+    ngx_listening_t   *ls;
+    ngx_connection_t  *c;
 
-    s = cycle->listening.elts;
+    ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
 
-        /*
-         * we do not need to handle the Winsock sockets here (divide a socket
-         * number by 4) because this function would never called
-         * in the Winsock environment
-         */
+        c = ls[i].connection;
+
+        if (!c->read->active) {
+            continue;
+        }
 
         if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
-            if (!cycle->connections[s[i].fd].read->active) {
-                continue;
-            }
-
-            if (ngx_del_conn(&cycle->connections[s[i].fd], NGX_DISABLE_EVENT)
-                                                                  == NGX_ERROR)
-            {
+            if (ngx_del_conn(c, NGX_DISABLE_EVENT) == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
         } else {
-            if (!cycle->read_events[s[i].fd].active) {
-                continue;
-            }
-
-            if (ngx_del_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT,
-                                               NGX_DISABLE_EVENT) == NGX_ERROR)
+            if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
+                == NGX_ERROR)
             {
                 return NGX_ERROR;
             }
@@ -463,21 +372,33 @@ ngx_disable_accept_events(ngx_cycle_t *c
 
 
 static void
-ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log)
+ngx_close_accepted_connection(ngx_connection_t *c)
 {
-    if (ngx_close_socket(s) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+    ngx_socket_t  fd;
+
+    ngx_free_connection(c);
+
+    fd = c->fd;
+    c->fd = (ngx_socket_t) -1;
+
+    if (ngx_close_socket(fd) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
                       ngx_close_socket_n " failed");
     }
 
+    if (c->pool) {
+        ngx_destroy_pool(c->pool);
+    }
+
 #if (NGX_STAT_STUB)
     ngx_atomic_dec(ngx_stat_active);
 #endif
 }
 
 
-static u_char *
+u_char *
 ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len)
 {
-    return ngx_snprintf(buf, len, " while accept() on %V", log->data);
+    return ngx_snprintf(buf, len, " while accepting new connection on %V",
+                        log->data);
 }
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -10,22 +10,18 @@
 #include <ngx_event_connect.h>
 
 
-#define NGX_RESOLVER_BUFSIZE  8192
-
-
 ngx_int_t
 ngx_event_connect_peer(ngx_peer_connection_t *pc)
 {
-    int                  rc;
-    ngx_uint_t           instance, level;
-    u_int                event;
-    time_t               now;
-    ngx_err_t            err;
-    ngx_peer_t          *peer;
-    ngx_socket_t         s;
-    ngx_event_t         *rev, *wev;
-    ngx_connection_t    *c;
-    ngx_event_conf_t    *ecf;
+    int                rc;
+    ngx_uint_t         instance, level, i;
+    u_int              event;
+    time_t             now;
+    ngx_err_t          err;
+    ngx_peer_t        *peer;
+    ngx_socket_t       s;
+    ngx_event_t       *rev, *wev;
+    ngx_connection_t  *c;
 
     now = ngx_time();
 
@@ -47,6 +43,7 @@ ngx_event_connect_peer(ngx_peer_connecti
 
         pc->connection = c;
         pc->cached = 1;
+
         return NGX_OK;
     }
 
@@ -102,9 +99,16 @@ ngx_event_connect_peer(ngx_peer_connecti
             pc->tries--;
 
             if (pc->tries == 0) {
+
+                /* all peers failed, mark them as live for quick recovery */
+
+                for (i = 0; i < pc->peers->number; i++) {
+                    pc->peers->peer[i].fails = 0;
+                }
+
                 /* ngx_unlock_mutex(pc->peers->mutex); */
 
-                return NGX_ERROR;
+                return NGX_BUSY;
             }
         }
     }
@@ -124,27 +128,26 @@ ngx_event_connect_peer(ngx_peer_connecti
     }
 
 
-    ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
-
-    /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
-
-    if ((ngx_uint_t) s >= ecf->connections) {
+    c = ngx_get_connection(s, pc->log);
 
-        ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
-                      "socket() returned socket #%d while only %d "
-                      "connections was configured, closing the socket",
-                      s, ecf->connections);
-
+    if (c == NULL) {
         if (ngx_close_socket(s) == -1) {
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           ngx_close_socket_n "failed");
         }
 
-        /* TODO: sleep for some time */
-
         return NGX_ERROR;
     }
 
+    rev = c->read;
+    wev = c->write;
+
+    ngx_memzero(c, sizeof(ngx_connection_t));
+
+    c->read = rev;
+    c->write = wev;
+    c->fd = s;
+    c->log = pc->log;
 
     if (pc->rcvbuf) {
         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
@@ -152,6 +155,8 @@ ngx_event_connect_peer(ngx_peer_connecti
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           "setsockopt(SO_RCVBUF) failed");
 
+            ngx_free_connection(c);
+
             if (ngx_close_socket(s) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                               ngx_close_socket_n " failed");
@@ -165,6 +170,8 @@ ngx_event_connect_peer(ngx_peer_connecti
         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                       ngx_nonblocking_n " failed");
 
+        ngx_free_connection(c);
+
         if (ngx_close_socket(s) == -1) {
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           ngx_close_socket_n " failed");
@@ -173,46 +180,19 @@ ngx_event_connect_peer(ngx_peer_connecti
         return NGX_ERROR;
     }
 
-#if (NGX_WIN32)
+    c->recv = ngx_recv;
+    c->send = ngx_send;
+    c->send_chain = ngx_send_chain;
 
-    /*
-     * Winsock assignes a socket number divisible by 4
-     * so to find a connection we divide a socket number by 4.
-     */
+    c->log_error = pc->log_error;
 
-    if (s % 4) {
-        ngx_log_error(NGX_LOG_EMERG, pc->log, 0,
-                      ngx_socket_n
-                      " created socket %d, not divisible by 4", s);
-        exit(1);
+    if (peer->sockaddr->sa_family != AF_INET) {
+        c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
+        c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
     }
 
-    c = &ngx_cycle->connections[s / 4];
-    rev = &ngx_cycle->read_events[s / 4];
-    wev = &ngx_cycle->write_events[s / 4];
-
-#else
-
-    c = &ngx_cycle->connections[s];
-    rev = &ngx_cycle->read_events[s];
-    wev = &ngx_cycle->write_events[s];
-
-#endif
-
     instance = rev->instance;
 
-#if (NGX_THREADS)
-
-    if (*(&c->lock)) {
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
-                       "spinlock in connect, fd:%d", s);
-        ngx_spinlock(&c->lock, 1000);
-        ngx_unlock(&c->lock);
-    }
-
-#endif
-
-    ngx_memzero(c, sizeof(ngx_connection_t));
     ngx_memzero(rev, sizeof(ngx_event_t));
     ngx_memzero(wev, sizeof(ngx_event_t));
 
@@ -225,27 +205,11 @@ ngx_event_connect_peer(ngx_peer_connecti
     rev->data = c;
     wev->data = c;
 
-    c->read = rev;
-    c->write = wev;
     wev->write = 1;
 
-    c->recv = ngx_recv;
-    c->send = ngx_send;
-    c->send_chain = ngx_send_chain;
-
-    c->log = pc->log;
     rev->log = pc->log;
     wev->log = pc->log;
 
-    c->fd = s;
-
-    c->log_error = pc->log_error;
-
-    if (peer->sockaddr->sa_family != AF_INET) {
-        c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
-        c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
-    }
-
     pc->connection = c;
 
     /*
@@ -272,8 +236,8 @@ ngx_event_connect_peer(ngx_peer_connecti
         }
     } 
 
-    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0,
-                   "connect to %V, #%d", &peer->name, c->number);
+    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
+                   "connect to %V, fd:%d #%d", &peer->name, s, c->number);
 
     rc = connect(s, peer->sockaddr, peer->socklen);
 
@@ -293,7 +257,7 @@ ngx_event_connect_peer(ngx_peer_connecti
             ngx_log_error(level, c->log, err, "connect() to %V failed",
                           &peer->name);
 
-            return NGX_CONNECT_ERROR;
+            return NGX_DECLINED;
         }
     }
 
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -13,9 +13,6 @@
 #include <ngx_event.h>
 
 
-#define NGX_CONNECT_ERROR   -10
-
-
 typedef struct {
     struct sockaddr    *sockaddr;
     socklen_t           socklen;
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -81,7 +81,7 @@ ngx_ssl_init(ngx_log_t *log)
 
 
 ngx_int_t
-ngx_ssl_create_session(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c,
+ngx_ssl_create_connection(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c,
     ngx_uint_t flags)
 {   
     ngx_ssl_t  *ssl;
@@ -91,28 +91,28 @@ ngx_ssl_create_session(ngx_ssl_ctx_t *ss
         return NGX_ERROR;
     }
 
-    ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
-    if (ssl->buf == NULL) {
-        return NGX_ERROR;
+    if (flags & NGX_SSL_BUFFER) {
+        ssl->buffer = 1;
+
+        ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
+        if (ssl->buf == NULL) {
+            return NGX_ERROR;
+        }
     }
 
-    if (flags & NGX_SSL_BUFFER) {
-        ssl->buffer = 1;
-    }
+    ssl->connection = SSL_new(ssl_ctx);
 
-    ssl->ssl = SSL_new(ssl_ctx);
-
-    if (ssl->ssl == NULL) {
+    if (ssl->connection == NULL) {
         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");
         return NGX_ERROR;
     }
 
-    if (SSL_set_fd(ssl->ssl, c->fd) == 0) {
+    if (SSL_set_fd(ssl->connection, c->fd) == 0) {
         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");
         return NGX_ERROR;
     }
 
-    SSL_set_accept_state(ssl->ssl);
+    SSL_set_accept_state(ssl->connection);
 
     c->ssl = ssl;
 
@@ -138,7 +138,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
     for ( ;; ) {
 
-        n = SSL_read(c->ssl->ssl, buf, size);
+        n = SSL_read(c->ssl->connection, buf, size);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); 
 
@@ -148,13 +148,14 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
 #if (NGX_DEBUG)
 
-            if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) {
+            if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection))
+            {
                 char         buf[129], *s, *d;
                 SSL_CIPHER  *cipher;
 
                 c->ssl->handshaked = 1;
 
-                cipher = SSL_get_current_cipher(c->ssl->ssl);
+                cipher = SSL_get_current_cipher(c->ssl->connection);
 
                 if (cipher) {
                     SSL_CIPHER_description(cipher, &buf[1], 128);
@@ -179,6 +180,12 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
                     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                    "SSL cipher: \"%s\"", &buf[1]); 
+
+                    if (SSL_session_reused(c->ssl->connection)) {
+                        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                                       "SSL reused session");
+                    }
+
                 } else {
                     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                    "SSL no shared ciphers"); 
@@ -214,9 +221,10 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 static ngx_int_t
 ngx_ssl_handle_recv(ngx_connection_t *c, int n)
 {
-    int         sslerr;
-    ngx_err_t   err;
-    char       *handshake;
+    int          sslerr;
+    char        *handshake;
+    ngx_err_t    err;
+    ngx_uint_t   level;
 
     if (n > 0) {
 
@@ -242,14 +250,14 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
         return NGX_OK;
     }
 
-    if (!SSL_is_init_finished(c->ssl->ssl)) {
+    if (!SSL_is_init_finished(c->ssl->connection)) {
         handshake = " in SSL handshake";
 
     } else {
         handshake = "";
     }
 
-    sslerr = SSL_get_error(c->ssl->ssl, n);
+    sslerr = SSL_get_error(c->ssl->connection, n);
 
     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
 
@@ -264,7 +272,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
 
         ngx_log_error(NGX_LOG_INFO, c->log, err,
                       "client does SSL %shandshake",
-                      SSL_is_init_finished(c->ssl->ssl) ? "re" : "");
+                      SSL_is_init_finished(c->ssl->connection) ? "re" : "");
 
         c->write->ready = 0;
 
@@ -294,8 +302,34 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
         return NGX_ERROR;
     }
 
-    ngx_ssl_error(NGX_LOG_ALERT, c->log, err,
-                  "SSL_read() failed%s", handshake);
+    level = NGX_LOG_CRIT;
+
+    if (sslerr == SSL_ERROR_SYSCALL) {
+
+        if (err == NGX_ECONNRESET
+            || err == NGX_EPIPE
+            || err == NGX_ENOTCONN
+            || err == NGX_ECONNREFUSED
+            || err == NGX_EHOSTUNREACH)
+        {
+            switch (c->log_error) {
+
+            case NGX_ERROR_IGNORE_ECONNRESET:
+            case NGX_ERROR_INFO:
+                level = NGX_LOG_INFO;
+                break;
+
+            case NGX_ERROR_ERR:
+                level = NGX_LOG_ERR;
+                break;
+
+            default:
+                break;
+            }
+        }
+    }
+
+    ngx_ssl_error(level, c->log, err, "SSL_read() failed%s", handshake);
 
     return NGX_ERROR;
 }
@@ -448,12 +482,13 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
 ssize_t
 ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
 {
-    int        n, sslerr;
-    ngx_err_t  err;
+    int         n, sslerr;
+    ngx_err_t   err;
+    ngx_uint_t  level;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
 
-    n = SSL_write(c->ssl->ssl, data, size);
+    n = SSL_write(c->ssl->connection, data, size);
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
 
@@ -461,13 +496,13 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
 
 #if (NGX_DEBUG)
 
-        if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) {
+        if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) {
             char         buf[129], *s, *d;
             SSL_CIPHER  *cipher;
 
             c->ssl->handshaked = 1;
 
-            cipher = SSL_get_current_cipher(c->ssl->ssl);
+            cipher = SSL_get_current_cipher(c->ssl->connection);
 
             if (cipher) {
                 SSL_CIPHER_description(cipher, &buf[1], 128);
@@ -492,6 +527,12 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
 
                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                "SSL cipher: \"%s\"", &buf[1]); 
+
+                if (SSL_session_reused(c->ssl->connection)) {
+                    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                                   "SSL reused session");
+                }
+
             } else {
                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                "SSL no shared ciphers"); 
@@ -521,7 +562,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
         return n;
     }
 
-    sslerr = SSL_get_error(c->ssl->ssl, n);
+    sslerr = SSL_get_error(c->ssl->connection, n);
 
     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
 
@@ -536,7 +577,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
 
         ngx_log_error(NGX_LOG_INFO, c->log, err,
                       "client does SSL %shandshake",
-                      SSL_is_init_finished(c->ssl->ssl) ? "re" : "");
+                      SSL_is_init_finished(c->ssl->connection) ? "re" : "");
 
         c->read->ready = 0;
 
@@ -560,7 +601,34 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
     c->ssl->no_rcv_shut = 1;
     c->ssl->no_send_shut = 1;
 
-    ngx_ssl_error(NGX_LOG_ALERT, c->log, err, "SSL_write() failed");
+    level = NGX_LOG_CRIT;
+
+    if (sslerr == SSL_ERROR_SYSCALL) {
+
+        if (err == NGX_ECONNRESET
+            || err == NGX_EPIPE
+            || err == NGX_ENOTCONN
+            || err == NGX_ECONNREFUSED
+            || err == NGX_EHOSTUNREACH)
+        {
+            switch (c->log_error) {
+
+            case NGX_ERROR_IGNORE_ECONNRESET:
+            case NGX_ERROR_INFO:
+                level = NGX_LOG_INFO;
+                break;
+
+            case NGX_ERROR_ERR:
+                level = NGX_LOG_ERR;
+                break;
+
+            default:
+                break;
+            }
+        }
+    }
+
+    ngx_ssl_error(level, c->log, err, "SSL_write() failed");
 
     return NGX_ERROR;
 }
@@ -602,7 +670,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
         }
 
         if (mode) {
-            SSL_set_shutdown(c->ssl->ssl, mode);
+            SSL_set_shutdown(c->ssl->connection, mode);
             c->ssl->shutdown_set = 1;
         }
     }
@@ -613,13 +681,14 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 #endif
 
     for ( ;; ) {
-        n = SSL_shutdown(c->ssl->ssl);
+        n = SSL_shutdown(c->ssl->connection);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
 
         if (n == 1 || (n == 0 && c->read->timedout)) {
-            SSL_free(c->ssl->ssl);
+            SSL_free(c->ssl->connection);
             c->ssl = NULL;
+
             return NGX_OK;
         }
 
@@ -632,7 +701,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
     }
 
     if (!again) {
-        sslerr = SSL_get_error(c->ssl->ssl, n);
+        sslerr = SSL_get_error(c->ssl->connection, n);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "SSL_get_error: %d", sslerr);
@@ -660,6 +729,9 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
     ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed");
 
+    SSL_free(c->ssl->connection);
+    c->ssl = NULL;
+
     return NGX_ERROR;
 }
 
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -23,7 +23,7 @@
 
 
 typedef struct {
-    SSL                   *ssl;
+    SSL                   *connection;
     ngx_int_t              last;
     ngx_buf_t             *buf;
     ngx_event_handler_pt   saved_read_handler;
@@ -49,8 +49,8 @@ typedef SSL_CTX  ngx_ssl_ctx_t;
 
 
 ngx_int_t ngx_ssl_init(ngx_log_t *log);
-ngx_int_t ngx_ssl_create_session(ngx_ssl_ctx_t *ctx, ngx_connection_t *c,
-                                 ngx_uint_t flags);
+ngx_int_t ngx_ssl_create_connection(ngx_ssl_ctx_t *ctx, ngx_connection_t *c,
+    ngx_uint_t flags);
 
 #define ngx_ssl_handshake(c)     NGX_OK
 
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -203,7 +203,10 @@ ngx_http_autoindex_handler(ngx_http_requ
     if (ngx_open_dir(&dname, &dir) == NGX_ERROR) {
         err = ngx_errno;
 
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+        if (err == NGX_ENOENT
+            || err == NGX_ENOTDIR
+            || err == NGX_ENAMETOOLONG)
+        {
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_NOT_FOUND;
 
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -82,7 +82,10 @@ ngx_http_headers_filter(ngx_http_request
     ngx_table_elt_t          *expires, *cc, **ccp;
     ngx_http_headers_conf_t  *conf;
 
-    if (r->headers_out.status != NGX_HTTP_OK || r->main) {
+    if ((r->headers_out.status != NGX_HTTP_OK
+         && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
+        || r->main)
+    {
         return ngx_http_next_header_filter(r);
     }
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -160,7 +160,7 @@ static ngx_command_t  ngx_http_proxy_com
       NULL },
 
     { ngx_string("proxy_pass_unparsed_uri"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri),
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -83,6 +83,9 @@ ngx_module_t  ngx_http_ssl_module = {
 };
 
 
+static u_char ngx_http_session_id_ctx[] = "HTTP";
+
+
 static void *
 ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
 {
@@ -147,12 +150,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     }
 
 
-#if 0
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3);
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_SINGLE_DH_USE);
-#endif
-
     if (conf->ciphers.len) {
         if (SSL_CTX_set_cipher_list(conf->ssl_ctx,
                                    (const char *) conf->ciphers.data) == 0)
@@ -182,7 +179,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         return NGX_CONF_ERROR;
     }
 
-    SSL_CTX_set_verify(conf->ssl_ctx, SSL_VERIFY_NONE, NULL);
+    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
+
+    SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+    SSL_CTX_set_read_ahead(conf->ssl_ctx, 1);
+
+    SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER);
+
+    SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_http_session_id_ctx,
+                                   sizeof(ngx_http_session_id_ctx) - 1);
 
     return NGX_CONF_OK;
 }
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -203,7 +203,10 @@ ngx_http_static_handler(ngx_http_request
     if (fd == NGX_INVALID_FILE) {
         err = ngx_errno;
 
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+        if (err == NGX_ENOENT
+            || err == NGX_ENOTDIR
+            || err == NGX_ENAMETOOLONG)
+        {
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_NOT_FOUND;
 
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -646,7 +646,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
             ls->post_accept_timeout = cscf->client_header_timeout;
 
             clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
-            ls->log = clcf->err_log;
+
+            ls->log = *clcf->err_log;
+            ls->log.data = &ls->addr_text;
+            ls->log.handler = ngx_accept_log_error;
 
 #if (NGX_WIN32)
             iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -284,6 +284,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("satisfy_any"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, satisfy_any),
+      NULL },
+
     { ngx_string("internal"),
       NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
       ngx_http_core_internal,
@@ -401,50 +408,43 @@ ngx_http_handler(ngx_http_request_t *r)
 
     r->connection->unexpected_eof = 0;
 
-    switch (r->headers_in.connection_type) {
-    case 0:
-        if (r->http_version > NGX_HTTP_VERSION_10) {
+    if (r->err_ctx == NULL) {
+        switch (r->headers_in.connection_type) {
+        case 0:
+            if (r->http_version > NGX_HTTP_VERSION_10) {
+                r->keepalive = 1;
+            } else {
+                r->keepalive = 0;
+            }
+            break;
+
+        case NGX_HTTP_CONNECTION_CLOSE:
+            r->keepalive = 0;
+            break;
+
+        case NGX_HTTP_CONNECTION_KEEP_ALIVE:
             r->keepalive = 1;
-        } else {
+            break;
+        }
+
+        if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) {
+
+            /*
+             * MSIE may wait for some time if the response for the POST request
+             * is sent over the keepalive connection
+             */
+
             r->keepalive = 0;
         }
-        break;
-
-    case NGX_HTTP_CONNECTION_CLOSE:
-        r->keepalive = 0;
-        break;
-
-    case NGX_HTTP_CONNECTION_KEEP_ALIVE:
-        r->keepalive = 1;
-        break;
+
+        if (r->headers_in.content_length_n > 0) {
+            r->lingering_close = 1;
+
+        } else {
+            r->lingering_close = 0;
+        }
     }
 
-    if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) {
-
-        /*
-         * MSIE may wait for some time if the response for the POST request
-         * is sent over the keepalive connection
-         */
-
-        r->keepalive = 0;
-    }
-
-#if 0
-    /* TEST STUB */ r->http_version = NGX_HTTP_VERSION_10;
-    /* TEST STUB */ r->keepalive = 0;
-#endif
-
-    if (r->headers_in.content_length_n > 0) {
-        r->lingering_close = 1;
-
-    } else {
-        r->lingering_close = 0;
-    }
-
-#if 0
-    /* TEST STUB */ r->lingering_close = 1;
-#endif
-
     r->write_event_handler = ngx_http_core_run_phases;
 
     r->valid_unparsed_uri = 1;
@@ -498,6 +498,10 @@ ngx_http_core_run_phases(ngx_http_reques
             r->phase = NGX_HTTP_FIND_CONFIG_PHASE;
         }
 
+        if (r->phase == NGX_HTTP_ACCESS_PHASE && r->main) {
+            continue;
+        }
+
         if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) {
             r->write_event_handler = ngx_http_request_empty_handler;
             ngx_http_finalize_request(r, r->content_handler(r));
@@ -515,7 +519,7 @@ ngx_http_core_run_phases(ngx_http_reques
 
                 /*
                  * we should never use r here because 
-                 * it could point to already freed data
+                 * it may point to already freed data
                  */
 
                 return;
@@ -525,6 +529,30 @@ ngx_http_core_run_phases(ngx_http_reques
                 continue;
             }
 
+            if (r->phase == NGX_HTTP_ACCESS_PHASE) {
+                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+                if (clcf->satisfy_any) {
+
+                    if (rc == NGX_OK) {
+                        r->access_code = 0;
+
+                        if (r->headers_out.www_authenticate) {
+                            r->headers_out.www_authenticate->hash = 0;
+                        }
+
+                        break;
+                    }
+
+                    if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED)
+                    {
+                        r->access_code = rc;
+
+                        continue;
+                    }
+                }
+            }
+
             if (rc >= NGX_HTTP_SPECIAL_RESPONSE
                 || rc == NGX_HTTP_NO_CONTENT
                 || rc == NGX_ERROR)
@@ -545,6 +573,12 @@ ngx_http_core_run_phases(ngx_http_reques
             if (rc == NGX_OK && cmcf->phases[r->phase].type == NGX_OK) {
                 break;
             }
+
+        }
+
+        if (r->phase == NGX_HTTP_ACCESS_PHASE && r->access_code) {
+            ngx_http_finalize_request(r, r->access_code);
+            return;
         }
     }
 
@@ -1102,6 +1136,7 @@ ngx_http_subrequest(ngx_http_request_t *
 
     sr->internal = 1;
 
+    sr->discard_body = r->discard_body;
     sr->main_filter_need_in_memory = r->main_filter_need_in_memory;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1793,6 +1828,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->client_max_body_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
+    lcf->satisfy_any = NGX_CONF_UNSET;
     lcf->internal = NGX_CONF_UNSET;
     lcf->sendfile = NGX_CONF_UNSET;
     lcf->tcp_nopush = NGX_CONF_UNSET;
@@ -1895,6 +1931,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_msec_value(conf->client_body_timeout,
                               prev->client_body_timeout, 60000);
 
+    ngx_conf_merge_value(conf->satisfy_any, prev->satisfy_any, 0);
     ngx_conf_merge_value(conf->internal, prev->internal, 0);
     ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
     ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -217,6 +217,7 @@ struct ngx_http_core_loc_conf_s {
 
     time_t        keepalive_header;        /* keepalive_timeout */
 
+    ngx_flag_t    satisfy_any;             /* satisfy_any */
     ngx_flag_t    internal;                /* internal */
     ngx_flag_t    sendfile;                /* sendfile */
     ngx_flag_t    tcp_nopush;              /* tcp_nopush */
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -359,7 +359,7 @@ void ngx_http_init_request(ngx_event_t *
     if (sscf->enable) {
 
         if (c->ssl == NULL) {
-            if (ngx_ssl_create_session(sscf->ssl_ctx, c, NGX_SSL_BUFFER)
+            if (ngx_ssl_create_connection(sscf->ssl_ctx, c, NGX_SSL_BUFFER)
                 == NGX_ERROR)
             {
                 ngx_http_close_connection(c);
@@ -1732,10 +1732,6 @@ ngx_http_postponed_handler(ngx_http_requ
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http postponed output filter: %d", rc);
 
-        if (rc == NGX_AGAIN) {
-            return rc;
-        }
-
         /*
          * we treat NGX_ERROR as NGX_OK, because we need to complete
          * all postponed requests
@@ -1744,6 +1740,11 @@ ngx_http_postponed_handler(ngx_http_requ
         pr = r->postponed;
 
         if (pr == NULL) {
+
+            if (rc == NGX_AGAIN) {
+                return NGX_AGAIN;
+            }
+
             return NGX_OK;
         }
     }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -307,6 +307,7 @@ struct ngx_http_request_s {
     ngx_uint_t                        phase;
     ngx_int_t                         phase_handler;
     ngx_http_handler_pt               content_handler;
+    ngx_uint_t                        access_code;
 
     ngx_http_variable_value_t       **variables;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -459,7 +459,11 @@ ngx_http_upstream_connect(ngx_http_reque
 
     u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name;
 
-    if (rc == NGX_CONNECT_ERROR) {
+    if (rc == NGX_BUSY) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
+    }
+
+    if (rc == NGX_BUSY || rc == NGX_DECLINED) {
         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
         return;
     }
--- a/src/imap/ngx_imap.h
+++ b/src/imap/ngx_imap.h
@@ -101,6 +101,8 @@ typedef struct {
     unsigned                quit:1;
     unsigned                protocol:1;
     unsigned                quoted:1;
+    unsigned                backslash:1;
+    unsigned                no_sync_literal:1;
 
     ngx_str_t               login;
     ngx_str_t               passwd;
--- a/src/imap/ngx_imap_auth_http_module.c
+++ b/src/imap/ngx_imap_auth_http_module.c
@@ -150,7 +150,8 @@ ngx_imap_auth_http_init(ngx_imap_session
 
     rc = ngx_event_connect_peer(&ctx->peer);
 
-    if (rc == NGX_ERROR || rc == NGX_CONNECT_ERROR) {
+    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+        ngx_close_connection(ctx->peer.connection);
         ngx_imap_session_internal_server_error(s);
         return;
     }
@@ -448,6 +449,7 @@ ngx_imap_auth_http_process_headers(ngx_i
 
                 p = ngx_pcalloc(s->connection->pool, size);
                 if (p == NULL) {
+                    ngx_close_connection(ctx->peer.connection);
                     ngx_imap_session_internal_server_error(s);
                     return;
                 }
@@ -641,8 +643,9 @@ ngx_imap_auth_http_process_headers(ngx_i
 static void
 ngx_imap_auth_sleep_handler(ngx_event_t *rev)
 {
-    ngx_connection_t    *c;
-    ngx_imap_session_t  *s;
+    ngx_connection_t          *c;
+    ngx_imap_session_t        *s;
+    ngx_imap_core_srv_conf_t  *cscf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap auth sleep handler");
 
@@ -662,6 +665,18 @@ ngx_imap_auth_sleep_handler(ngx_event_t 
             s->connection->read->handler = ngx_imap_auth_state;
         }
 
+        c->log->action = "in auth state";
+
+        ngx_imap_send(s->connection->write);
+
+        if (c->closed) {
+            return;
+        }
+
+        cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
+
+        ngx_add_timer(rev, cscf->timeout);
+
         if (rev->ready) {
             s->connection->read->handler(rev);
             return;
@@ -671,8 +686,6 @@ ngx_imap_auth_sleep_handler(ngx_event_t 
             ngx_imap_close_connection(s->connection);
         }
 
-        ngx_imap_send(s->connection->write);
-
         return;
     }
 
--- a/src/imap/ngx_imap_core_module.c
+++ b/src/imap/ngx_imap_core_module.c
@@ -418,7 +418,9 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx
     ls->ctx = cf->ctx;
 
     /* STUB */
-    ls->log = cf->cycle->new_log;
+    ls->log = *cf->cycle->new_log;
+    ls->log.data = &ls->addr_text;
+    ls->log.handler = ngx_accept_log_error;
     /**/
 
     return NGX_CONF_OK;
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -33,6 +33,7 @@ static ngx_str_t  internal_server_errors
 static u_char  pop3_ok[] = "+OK" CRLF;
 static u_char  pop3_invalid_command[] = "-ERR invalid command" CRLF;
 
+static u_char  imap_star[] = "* ";
 static u_char  imap_ok[] = "OK completed" CRLF;
 static u_char  imap_next[] = "+ OK" CRLF;
 static u_char  imap_bye[] = "* BYE" CRLF;
@@ -42,26 +43,48 @@ static u_char  imap_invalid_command[] = 
 void
 ngx_imap_init_connection(ngx_connection_t *c)
 {
-    ngx_imap_log_ctx_t  *ctx;
+    ngx_imap_log_ctx_t   *lctx;
+#if (NGX_IMAP_SSL)
+    ngx_imap_conf_ctx_t  *ctx;
+    ngx_imap_ssl_conf_t  *sslcf;
+#endif
 
     ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection");
 
-    ctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t));
-    if (ctx == NULL) {
+    lctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t));
+    if (lctx == NULL) {
         ngx_imap_close_connection(c);
         return;
     } 
 
-    ctx->client = &c->addr_text;
-    ctx->session = NULL;
+    lctx->client = &c->addr_text;
+    lctx->session = NULL;
 
     c->log->connection = c->number;
     c->log->handler = ngx_imap_log_error;
-    c->log->data = ctx;
+    c->log->data = lctx;
     c->log->action = "sending client greeting line";
 
     c->log_error = NGX_ERROR_INFO;
 
+#if (NGX_IMAP_SSL)
+
+    ctx = c->ctx;
+    sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module);
+
+    if (sslcf->enable) {
+        if (ngx_ssl_create_connection(sslcf->ssl_ctx, c, 0) == NGX_ERROR) {
+            ngx_imap_close_connection(c);
+            return;
+        }
+
+        c->recv = ngx_ssl_recv;
+        c->send = ngx_ssl_write;
+        c->send_chain = ngx_ssl_send_chain;
+    }
+
+#endif
+
     ngx_imap_init_session(c->read);
 }
 
@@ -76,27 +99,15 @@ ngx_imap_init_session(ngx_event_t *rev)
     ngx_imap_core_srv_conf_t  *cscf;
 #if (NGX_IMAP_SSL)
     ngx_int_t                  rc;
-    ngx_imap_ssl_conf_t       *sslcf;
 #endif
 
     c = rev->data;
-
     ctx = c->ctx;
-
     cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
 
 #if (NGX_IMAP_SSL)
 
-    sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module);
-
-    if (sslcf->enable) {
-
-        if (ngx_ssl_create_session(sslcf->ssl_ctx, c, NGX_SSL_BUFFER)
-            == NGX_ERROR)
-        {
-            ngx_imap_close_connection(c);
-            return;
-        }
+    if (c->ssl) {
 
         rc = ngx_ssl_handshake(c);
 
@@ -116,9 +127,6 @@ ngx_imap_init_session(ngx_event_t *rev)
             return;
         }
 
-        c->recv = ngx_ssl_recv;
-        c->send = ngx_ssl_write;
-        c->send_chain = ngx_ssl_send_chain;
     }
 
 #endif
@@ -275,11 +283,11 @@ ngx_imap_init_protocol(ngx_event_t *rev)
 void
 ngx_imap_auth_state(ngx_event_t *rev)
 {
-    u_char                    *text, *last, *p;
+    u_char                    *text, *last, *p, *dst, *src, *end;
     ssize_t                    text_len, last_len;
     ngx_str_t                 *arg;
     ngx_int_t                  rc;
-    ngx_uint_t                 tag;
+    ngx_uint_t                 tag, i;
     ngx_connection_t          *c;
     ngx_imap_session_t        *s;
     ngx_imap_core_srv_conf_t  *cscf;
@@ -324,6 +332,27 @@ ngx_imap_auth_state(ngx_event_t *rev)
         ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i",
                        s->command);
 
+        if (s->backslash) {
+
+            arg = s->args.elts;
+
+            for (i = 0; i < s->args.nelts; i++) {
+                dst = arg[i].data;
+                end = dst + arg[i].len;
+
+                for (src = dst; src < end; dst++) {
+                    *dst = *src;
+                    if (*src++ == '\\') {
+                        *dst = *src++;
+                    }
+                }
+
+                arg[i].len = dst - arg[i].data;
+            }
+
+            s->backslash = 0;
+        }
+
         switch (s->command) {
 
         case NGX_IMAP_LOGIN:
@@ -405,6 +434,11 @@ ngx_imap_auth_state(ngx_event_t *rev)
     }
 
     if (tag) {
+        if (s->tag.len == 0) {
+            s->tag.len = sizeof(imap_star) - 1;
+            s->tag.data = (u_char *) imap_star;
+        }
+
         if (s->tagged_line.len < s->tag.len + text_len + last_len) {
             s->tagged_line.len = s->tag.len + text_len + last_len;
             s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len);
@@ -693,6 +727,8 @@ ngx_imap_close_connection(ngx_connection
 
 #endif
 
+    c->closed = 1;
+
     pool = c->pool;
 
     ngx_close_connection(c);
--- a/src/imap/ngx_imap_parse.c
+++ b/src/imap/ngx_imap_parse.c
@@ -20,7 +20,9 @@ ngx_int_t ngx_imap_parse_command(ngx_ima
         sw_command,
         sw_spaces_before_argument,
         sw_argument,
+        sw_backslash,
         sw_literal,
+        sw_no_sync_literal_argument,
         sw_start_literal_argument,
         sw_literal_argument,
         sw_end_literal_argument,
@@ -225,6 +227,22 @@ ngx_int_t ngx_imap_parse_command(ngx_ima
                     goto done;
                 }
                 break;
+            case '\\':
+                if (s->quoted) {
+                    s->backslash = 1;
+                    state = sw_backslash;
+                }
+                break;
+            }
+            break;
+
+        case sw_backslash:
+            switch (ch) {
+            case CR:
+            case LF:
+                goto invalid;
+            default:
+                state = sw_argument;
             }
             break;
 
@@ -237,6 +255,18 @@ ngx_int_t ngx_imap_parse_command(ngx_ima
                 state = sw_start_literal_argument;
                 break;
             }
+            if (ch == '+') {
+                state = sw_no_sync_literal_argument;
+                break;
+            }
+            goto invalid;
+
+        case sw_no_sync_literal_argument:
+            if (ch == '}') {
+                s->no_sync_literal = 1;
+                state = sw_start_literal_argument;
+                break;
+            }
             goto invalid;
 
         case sw_start_literal_argument:
@@ -246,10 +276,17 @@ ngx_int_t ngx_imap_parse_command(ngx_ima
             case LF:
                 s->buffer->pos = p + 1;
                 s->arg_start = p + 1;
-                s->state = sw_literal_argument;
-                return NGX_IMAP_NEXT;
+                if (s->no_sync_literal == 0) {
+                    s->state = sw_literal_argument;
+                    return NGX_IMAP_NEXT;
+                }
+                state = sw_literal_argument;
+                s->no_sync_literal = 0;
+                break;
+            default:
+                goto invalid;
             }
-            goto invalid;
+            break;
 
         case sw_literal_argument:
             if (s->literal_len && --s->literal_len) {
@@ -312,9 +349,11 @@ done:
         }
         arg->len = s->arg_end - s->arg_start;
         arg->data = s->arg_start;
+
         s->arg_start = NULL;
         s->cmd_start = NULL;
         s->quoted = 0;
+        s->no_sync_literal = 0;
         s->literal_len = 0;
     }
 
@@ -326,6 +365,7 @@ invalid:
 
     s->state = sw_start;
     s->quoted = 0;
+    s->no_sync_literal = 0;
     s->literal_len = 0;
 
     return NGX_IMAP_PARSE_INVALID_COMMAND;
@@ -432,7 +472,14 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
 
         case sw_argument:
             switch (ch) {
-            case ' ':
+
+         /* 
+          * the space should be considered part of the at username
+          * or password, but not of argument in other commands
+          *
+          * case ' ':
+          */
+
             case CR:
             case LF:
                 arg = ngx_array_push(&s->args);
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -111,8 +111,8 @@ ngx_imap_proxy_init(ngx_imap_session_t *
 
     rc = ngx_event_connect_peer(&p->upstream);
 
-    if (rc == NGX_ERROR || rc == NGX_CONNECT_ERROR) {
-        ngx_imap_session_internal_server_error(s);
+    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+        ngx_imap_proxy_internal_server_error(s);
         return;
     }
 
--- a/src/imap/ngx_imap_ssl_module.c
+++ b/src/imap/ngx_imap_ssl_module.c
@@ -76,6 +76,9 @@ ngx_module_t  ngx_imap_ssl_module = {
 };
 
 
+static u_char ngx_imap_session_id_ctx[] = "IMAP";
+
+
 static void *
 ngx_imap_ssl_create_conf(ngx_conf_t *cf)
 {           
@@ -176,7 +179,16 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, 
         return NGX_CONF_ERROR;
     }
 
-    SSL_CTX_set_verify(conf->ssl_ctx, SSL_VERIFY_NONE, NULL);
+    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
+
+    SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+    SSL_CTX_set_read_ahead(conf->ssl_ctx, 1);
+
+    SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER);
+
+    SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_imap_session_id_ctx,
+                                   sizeof(ngx_imap_session_id_ctx) - 1);
 
     return NGX_CONF_OK;
 }
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -9,8 +9,9 @@
 #include <ngx_channel.h>
 
 
-ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
-                            ngx_log_t *log) 
+ngx_int_t
+ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+    ngx_log_t *log) 
 {
     ssize_t             n;
     ngx_err_t           err;
@@ -77,8 +78,8 @@ ngx_int_t ngx_write_channel(ngx_socket_t
 }
 
 
-ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
-                           ngx_log_t *log)
+ngx_int_t
+ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
 {   
     ssize_t             n;
     ngx_err_t           err;
@@ -178,31 +179,40 @@ ngx_int_t ngx_read_channel(ngx_socket_t 
 }
 
 
-ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd,
-                                ngx_int_t event, ngx_event_handler_pt handler)
+ngx_int_t
+ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event,
+    ngx_event_handler_pt handler)
 {
     ngx_event_t       *ev, *rev, *wev;
     ngx_connection_t  *c;
 
-    c = &cycle->connections[fd];
-    rev = &cycle->read_events[fd];
-    wev = &cycle->write_events[fd];
+    c = ngx_get_connection(fd, cycle->log);
+
+    if (c == NULL) {
+        return NGX_ERROR;
+    }
+
+    rev = c->read;
+    wev = c->write;
 
     ngx_memzero(c, sizeof(ngx_connection_t));
+
+    c->read = rev;
+    c->write = wev;
+    c->fd = fd;
+    c->log = cycle->log;
+
+    c->pool = cycle->pool;
+
     ngx_memzero(rev, sizeof(ngx_event_t));
     ngx_memzero(wev, sizeof(ngx_event_t));
 
-    c->fd = fd;
-    c->pool = cycle->pool;
-
-    c->read = rev;
-    c->write = wev;
-
-    c->log = cycle->log;
     rev->log = cycle->log;
     wev->log = cycle->log;
+
     rev->index = NGX_INVALID_INDEX;
     wev->index = NGX_INVALID_INDEX;
+
     rev->data = c;
     wev->data = c;
 
@@ -219,11 +229,13 @@ ngx_int_t ngx_add_channel_event(ngx_cycl
 
     if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
         if (ngx_add_conn(c) == NGX_ERROR) {
+            ngx_free_connection(c);
             return NGX_ERROR;
         }
     
     } else { 
         if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
+            ngx_free_connection(c);
             return NGX_ERROR;
         }
     }
@@ -232,7 +244,8 @@ ngx_int_t ngx_add_channel_event(ngx_cycl
 }
 
 
-void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
+void
+ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
 {
     if (close(fd[0]) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
--- a/src/os/unix/ngx_channel.h
+++ b/src/os/unix/ngx_channel.h
@@ -22,11 +22,11 @@ typedef struct {
 
 
 ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
-                            ngx_log_t *log);
+    ngx_log_t *log);
 ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
-                           ngx_log_t *log);
+    ngx_log_t *log);
 ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd,
-                                ngx_int_t event, ngx_event_handler_pt handler);
+    ngx_int_t event, ngx_event_handler_pt handler);
 void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log);
 
 
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -33,6 +33,7 @@ typedef int               ngx_err_t;
 #define NGX_ENOTCONN      ENOTCONN
 #define NGX_ETIMEDOUT     ETIMEDOUT
 #define NGX_ECONNREFUSED  ECONNREFUSED
+#define NGX_ENAMETOOLONG  ENAMETOOLONG
 #define NGX_EHOSTUNREACH  EHOSTUNREACH
 #define NGX_ENOSYS        ENOSYS
 #define NGX_ECANCELED     ECANCELED
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -94,7 +94,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                           "no more than %d processes can be spawned",
                           NGX_MAX_PROCESSES);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
     }
 
@@ -107,7 +107,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
         {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                           "socketpair() failed while spawning \"%s\"", name);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
@@ -120,7 +120,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
                           ngx_nonblocking_n " failed while spawning \"%s\"",
                           name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
@@ -128,7 +128,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
                           ngx_nonblocking_n " failed while spawning \"%s\"",
                           name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         on = 1;
@@ -136,14 +136,14 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                           "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                           "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
@@ -151,7 +151,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                            name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
@@ -159,7 +159,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                            name);
             ngx_close_channel(ngx_processes[s].channel, cycle->log);
-            return NGX_ERROR;
+            return NGX_INVALID_PID;
         }
 
         ngx_channel = ngx_processes[s].channel[1];
@@ -180,7 +180,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                       "fork() failed while spawning \"%s\"", name);
         ngx_close_channel(ngx_processes[s].channel, cycle->log);
-        return NGX_ERROR;
+        return NGX_INVALID_PID;
 
     case 0:
         ngx_pid = ngx_getpid();
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -13,6 +13,8 @@
 
 typedef pid_t       ngx_pid_t;
 
+#define NGX_INVALID_PID  -1
+
 typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data);
 
 typedef struct {
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -513,9 +513,10 @@ ngx_signal_worker_processes(ngx_cycle_t 
 static ngx_uint_t
 ngx_reap_childs(ngx_cycle_t *cycle)
 {
-    ngx_int_t      i, n;
-    ngx_uint_t     live;
-    ngx_channel_t  ch;
+    ngx_int_t         i, n;
+    ngx_uint_t        live;
+    ngx_channel_t     ch;
+    ngx_core_conf_t  *ccf;
 
     ch.command = NGX_CMD_CLOSE_CHANNEL;
     ch.fd = -1;
@@ -575,7 +576,7 @@ ngx_reap_childs(ngx_cycle_t *cycle)
                 if (ngx_spawn_process(cycle, ngx_processes[i].proc,
                                       ngx_processes[i].data,
                                       ngx_processes[i].name, i)
-                                                                  == NGX_ERROR)
+                    == NGX_INVALID_PID)
                 {
                     ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                                   "can not respawn %s", ngx_processes[i].name);
@@ -615,6 +616,20 @@ ngx_reap_childs(ngx_cycle_t *cycle)
             }
 
             if (ngx_processes[i].pid == ngx_new_binary) {
+
+                ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
+                                                       ngx_core_module);
+
+                if (ngx_rename_file((char *) ccf->oldpid.data,
+                                    (char *) ccf->pid.data)
+                    != NGX_OK)
+                {
+                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                                  ngx_rename_file_n " %s back to %s failed "
+                                  "after the new binary process \"%s\" exited",
+                                  ccf->oldpid.data, ccf->pid.data, ngx_argv[0]);
+                }
+
                 ngx_new_binary = 0;
                 if (ngx_noaccepting) {
                     ngx_restart = 1;
@@ -795,6 +810,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc
     sigset_t           set;
     ngx_int_t          n;
     ngx_uint_t         i;
+    struct rlimit      rlmt;
     struct timeval     tv;
     ngx_core_conf_t   *ccf;
     ngx_listening_t   *ls;
@@ -818,6 +834,30 @@ ngx_worker_process_init(ngx_cycle_t *cyc
             }
         }
 
+        if (ccf->rlimit_nofile != NGX_CONF_UNSET) {
+            rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;
+            rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile;
+
+            if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                              "setrlimit(RLIMIT_NOFILE, %i) failed",
+                              ccf->rlimit_nofile);
+            }
+        }
+
+#ifdef RLIMIT_SIGPENDING
+        if (ccf->rlimit_sigpending != NGX_CONF_UNSET) {
+            rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending;
+            rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending;
+
+            if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                              "setrlimit(RLIMIT_SIGPENDING, %i) failed",
+                              ccf->rlimit_sigpending);
+            }
+        }
+#endif
+
         if (setgid(ccf->group) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           "setgid(%d) failed", ccf->group);
@@ -874,7 +914,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc
      */ 
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
-        ls[i].remain = 0;
+        ls[i].previous = NULL;
     }
 
     for (i = 0; ngx_modules[i]; i++) {
@@ -928,6 +968,7 @@ static void
 ngx_channel_handler(ngx_event_t *ev)
 {
     ngx_int_t          n;
+    ngx_socket_t       fd;
     ngx_channel_t      ch;
     ngx_connection_t  *c;
 
@@ -945,12 +986,17 @@ ngx_channel_handler(ngx_event_t *ev)
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
 
     if (n == NGX_ERROR) {
-        if (close(c->fd) == -1) {
+
+        ngx_free_connection(c);
+
+        fd = c->fd;
+        c->fd = (ngx_socket_t) -1;
+
+        if (close(fd) == -1) {
             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
                           "close() channel failed");
         }
 
-        c->fd = -1;
         return;
     }
 
@@ -1144,7 +1190,7 @@ ngx_garbage_collector_cycle(ngx_cycle_t 
 
     ngx_worker_process_init(cycle, 0);
 
-    ev = &cycle->read_events[ngx_channel];
+    ev = &cycle->read_events0[ngx_channel];
 
     ngx_accept_mutex = NULL;