nginx-0.3.3-RELEASE import

    *) Change: the "bl" and "af" parameters of the "listen" directive was
       renamed to the "backlog" and "accept_filter".

    *) Feature: the "rcvbuf" and "sndbuf" parameters of the "listen"
       directive.

    *) Change: the "$msec" log parameter does not require now the
       additional the gettimeofday() system call.

    *) Feature: the -t switch now tests the "listen" directives.

    *) Bugfix: if the invalid address was specified in the "listen"
       directive, then after the -HUP signal nginx left an open socket in
       the CLOSED state.

    *) Bugfix: the mime type may be incorrectly set to default value for
       index file with variable in the name; the bug had appeared in 0.3.0.

    *) Feature: the "timer_resolution" directive.

    *) Feature: the millisecond "$upstream_response_time" log parameter.

    *) Bugfix: a temporary file with client request body now is removed
       just after the response header was transferred to a client.

    *) Bugfix: OpenSSL 0.9.6 compatibility.

    *) Bugfix: the SSL certificate and key file paths could not be relative.

    *) Bugfix: the "ssl_prefer_server_ciphers" directive did not work in
       the ngx_imap_ssl_module.

    *) Bugfix: the "ssl_protocols" directive allowed to specify the single
       protocol only.
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 3f36d31..cac3944 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -66,13 +66,12 @@
     ngx_uint_t                 i;
     ngx_listening_t           *ls;
     struct sockaddr_in        *sin;
+    socklen_t                  olen;
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
     ngx_err_t                  err;
-    socklen_t                  aflen;
     struct accept_filter_arg   af;
 #endif
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-    socklen_t                  tlen;
     int                        timeout;
 #endif
 
@@ -126,12 +125,38 @@
 
         ls[i].backlog = -1;
 
+        olen = sizeof(int);
+
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
+                       &olen)
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                          "getsockopt(SO_RCVBUF) %V failed, ignored",
+                          &ls[i].addr_text);
+
+            ls[i].rcvbuf = -1;
+        }
+
+        olen = sizeof(int);
+
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
+                       &olen)
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                          "getsockopt(SO_SNDBUF) %V failed, ignored",
+                          &ls[i].addr_text);
+
+            ls[i].sndbuf = -1;
+        }
+
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
         ngx_memzero(&af, sizeof(struct accept_filter_arg));
-        aflen = sizeof(struct accept_filter_arg);
+        olen = sizeof(struct accept_filter_arg);
 
-        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &aflen)
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
             == -1)
         {
             err = ngx_errno;
@@ -146,7 +171,7 @@
             continue;
         }
 
-        if (aflen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
+        if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
             continue;
         }
 
@@ -162,9 +187,9 @@
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
 
         timeout = 0;
-        tlen = sizeof(int);
+        olen = sizeof(int);
 
-        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &tlen)
+        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
             == -1)
         {
             ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno,
@@ -188,7 +213,8 @@
 ngx_int_t
 ngx_open_listening_sockets(ngx_cycle_t *cycle)
 {
-    ngx_uint_t        tries, failed, reuseaddr, i;
+    int               reuseaddr;
+    ngx_uint_t        i, tries, failed;
     ngx_err_t         err;
     ngx_log_t        *log;
     ngx_socket_t      s;
@@ -201,9 +227,9 @@
 
     log = cycle->log;
 
-    /* TODO: tries configurable */
+    /* TODO: configurable try number */
 
-    for (tries = /* STUB */ 5; tries; tries--) {
+    for (tries = 5 ; tries; tries--) {
         failed = 0;
 
         /* for each listening socket */
@@ -236,25 +262,19 @@
                 return NGX_ERROR;
             }
 
-#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, log, 0,
-                              ngx_socket_n " created socket %d", s);
-                return NGX_ERROR;
-            }
-#endif
-
             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                           (const void *) &reuseaddr, sizeof(int)) == -1) {
+                           (const void *) &reuseaddr, sizeof(int))
+                == -1)
+            {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                               "setsockopt(SO_REUSEADDR) %V failed",
                               &ls[i].addr_text);
+
+                if (ngx_close_socket(s) == -1)
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %V failed",
+                                  &ls[i].addr_text);
+
                 return NGX_ERROR;
             }
 
@@ -265,56 +285,54 @@
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_nonblocking_n " %V failed",
                                   &ls[i].addr_text);
-                    return NGX_ERROR;
-                }
-            }
 
-#if 0
-            if (ls[i].nonblocking) {
-                if (ngx_nonblocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                                  ngx_nonblocking_n " %V failed",
-                                  &ls[i].addr_text);
+                    if (ngx_close_socket(s) == -1)
+                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                      ngx_close_socket_n " %V failed",
+                                      &ls[i].addr_text);
+
                     return NGX_ERROR;
                 }
             }
-#endif
 
             if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
                 err = ngx_socket_errno;
+
+                if (err == NGX_EADDRINUSE && ngx_test_config) {
+                    continue;
+                }
+
                 ngx_log_error(NGX_LOG_EMERG, log, err,
                               "bind() to %V failed", &ls[i].addr_text);
 
-                if (err != NGX_EADDRINUSE)
-                    return NGX_ERROR;
-
                 if (ngx_close_socket(s) == -1)
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_close_socket_n " %V failed",
                                   &ls[i].addr_text);
 
+                if (err != NGX_EADDRINUSE) {
+                    return NGX_ERROR;
+                }
+
                 failed = 1;
+
                 continue;
             }
 
-            if (listen(s, ls[i].backlog) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              "listen() to %V failed", &ls[i].addr_text);
-                return NGX_ERROR;
-            }
-
-            /* TODO: deferred accept */
+            ls[i].listen = 1;
 
             ls[i].fd = s;
         }
 
-        if (!failed)
+        if (!failed) {
             break;
+        }
 
         /* TODO: delay configurable */
 
         ngx_log_error(NGX_LOG_NOTICE, log, 0,
                       "try again to bind() after 500ms");
+
         ngx_msleep(500);
     }
 
@@ -328,6 +346,143 @@
 
 
 void
+ngx_configure_listening_socket(ngx_cycle_t *cycle)
+{
+    ngx_uint_t                 i;
+    ngx_listening_t           *ls;
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+    struct accept_filter_arg   af;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+    int                        timeout;
+#endif
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+
+        if (ls[i].rcvbuf != -1) {
+            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
+                           (const void *) &ls[i].rcvbuf, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(SO_RCVBUF) %V failed, ignored",
+                              &ls[i].addr_text);
+                return;
+            }
+        }
+
+        if (ls[i].sndbuf != -1) {
+            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF,
+                           (const void *) &ls[i].sndbuf, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(SO_SNDBUF) %V failed, ignored",
+                              &ls[i].addr_text);
+                return;
+            }
+        }
+
+        if (ls[i].listen) {
+            if (listen(ls[i].fd, ls[i].backlog) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "changing the listen() backlog to %d "
+                              "for %V failed, ignored",
+                              &ls[i].addr_text, ls[i].backlog);
+            }
+        }
+
+        /*
+         * setting deferred mode should be last operation on socket,
+         * because code may prematurely continue cycle on failure
+         */
+
+#if (NGX_HAVE_DEFERRED_ACCEPT)
+
+#ifdef SO_ACCEPTFILTER
+
+        if (ls->delete_deferred) {
+            if (setsockopt(ls->fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0) == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(SO_ACCEPTFILTER, NULL) "
+                              "for %V failed, ignored",
+                              &ls->addr_text);
+
+                if (ls->accept_filter) {
+                    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                                  "could not change the accept filter "
+                                  "to \"%s\" for %V, ignored",
+                                  ls->accept_filter, &ls->addr_text);
+                }
+
+                continue;
+            }
+
+            ls->deferred_accept = 0;
+        }
+
+        if (ls->add_deferred) {
+            ngx_memzero(&af, sizeof(struct accept_filter_arg));
+            (void) ngx_cpystrn((u_char *) af.af_name,
+                               (u_char *) ls->accept_filter, 16);
+
+            if (setsockopt(ls->fd, SOL_SOCKET, SO_ACCEPTFILTER,
+                           &af, sizeof(struct accept_filter_arg))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(SO_ACCEPTFILTER, \"%s\") "
+                              " for %V failed, ignored",
+                              ls->accept_filter, &ls->addr_text);
+                continue;
+            }
+
+            ls->deferred_accept = 1;
+        }
+
+#endif
+
+#ifdef TCP_DEFER_ACCEPT
+
+        if (ls->add_deferred || ls->delete_deferred) {
+
+            if (ls->add_deferred) {
+                timeout = (int) (ls->post_accept_timeout / 1000);
+
+            } else {
+                timeout = 0;
+            }
+
+            if (setsockopt(ls->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
+                           &timeout, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
+                              "ignored",
+                              timeout, &ls->addr_text);
+
+                continue;
+            }
+        }
+
+        if (ls->add_deferred) { 
+            ls->deferred_accept = 1;
+        }
+
+#endif
+
+#endif /* NGX_HAVE_DEFERRED_ACCEPT */
+    }
+
+    return;
+}
+
+
+void
 ngx_close_listening_sockets(ngx_cycle_t *cycle)
 {
     ngx_uint_t         i;
@@ -361,6 +516,9 @@
 
         c->fd = (ngx_socket_t) -1;
 
+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+                       "close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
+
         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);
@@ -495,28 +653,27 @@
      * before we clean the connection
      */
 
-    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK) {
+    ngx_mutex_lock(ngx_posted_events_mutex);
 
-        if (c->read->prev) {
-            ngx_delete_posted_event(c->read);
-        }
-
-        if (c->write->prev) {
-            ngx_delete_posted_event(c->write);
-        }
-
-        c->read->closed = 1;
-        c->write->closed = 1;
-
-        if (c->single_connection) {
-            ngx_unlock(&c->lock);
-            c->read->locked = 0;
-            c->write->locked = 0;
-        }
-
-        ngx_mutex_unlock(ngx_posted_events_mutex);
+    if (c->read->prev) {
+        ngx_delete_posted_event(c->read);
     }
 
+    if (c->write->prev) {
+        ngx_delete_posted_event(c->write);
+    }
+
+    c->read->closed = 1;
+    c->write->closed = 1;
+
+    if (c->single_connection) {
+        ngx_unlock(&c->lock);
+        c->read->locked = 0;
+        c->write->locked = 0;
+    }
+
+    ngx_mutex_unlock(ngx_posted_events_mutex);
+
 #else
 
     if (c->read->prev) {