changeset 552:c04fa65fe604 NGINX_0_8_22

nginx 0.8.22 *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" directives. *) Feature: the "access" and the "deny" directives support IPv6. *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in request headers. *) Feature: the "unix:" parameter of the "set_real_ip_from" directive. *) Bugfix: nginx did not delete unix domain socket after configuration testing. *) Bugfix: nginx deleted unix domain socket while online upgrade. *) Bugfix: the "!-x" operator did not work. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process, if limit_rate was used in HTTPS server. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process while $limit_rate logging. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process, if there was no "listen" directive in "server" block; the bug had appeared in 0.8.21.
author Igor Sysoev <http://sysoev.ru>
date Tue, 03 Nov 2009 00:00:00 +0300
parents c88014f74832
children 8da5668048b4
files CHANGES CHANGES.ru auto/install auto/os/linux src/core/nginx.h src/core/ngx_connection.c src/core/ngx_connection.h src/core/ngx_inet.c src/core/ngx_inet.h src/core/ngx_resolver.c src/core/ngx_resolver.h src/core/ngx_string.c 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/http/modules/ngx_http_access_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_realip_module.c src/http/modules/perl/nginx.pm src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_upstream_round_robin.h src/http/ngx_http_variables.c src/mail/ngx_mail.h src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_proxy_module.c src/os/unix/ngx_files.h src/os/unix/ngx_freebsd_rfork_thread.h src/os/unix/ngx_setproctitle.h src/os/unix/ngx_thread.h src/os/unix/ngx_user.h
diffstat 38 files changed, 837 insertions(+), 303 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,37 @@
 
+Changes with nginx 0.8.22                                        03 Nov 2009
+
+    *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" 
+       directives.
+
+    *) Feature: the "access" and the "deny" directives support IPv6.
+
+    *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in 
+       request headers.
+
+    *) Feature: the "unix:" parameter of the "set_real_ip_from" directive.
+
+    *) Bugfix: nginx did not delete unix domain socket after configuration 
+       testing.
+
+    *) Bugfix: nginx deleted unix domain socket while online upgrade.
+
+    *) Bugfix: the "!-x" operator did not work.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if 
+       limit_rate was used in HTTPS server.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process while 
+       $limit_rate logging.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault might occur in a worker process, if 
+       there was no "listen" directive in "server" block; the bug had 
+       appeared in 0.8.21.
+
+
 Changes with nginx 0.8.21                                        26 Oct 2009
 
     *) Feature: now the "-V" switch shows TLS SNI support.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,37 @@
 
+Изменения в nginx 0.8.22                                          03.11.2009
+
+    *) Добавление: директивы proxy_bind, fastcgi_bind и memcached_bind.
+
+    *) Добавление: директивы access и deny поддерживают IPv6.
+
+    *) Добавление: директива set_real_ip_from поддерживает IPv6 адреса в 
+       заголовках запроса.
+
+    *) Добавление: параметр "unix:" в директиве set_real_ip_from.
+
+    *) Исправление: nginx не удалял unix domain сокет после тестирования 
+       конфигурации.
+
+    *) Исправление: nginx удалял unix domain сокет во время обновления без 
+       перерыва.
+
+    *) Исправление: оператор "!-x" не работал.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault при 
+       использовании limit_rate в HTTPS сервере.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: при записи в лог переменной $limit_rate в рабочем 
+       процессе происходил segmentation fault.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault, 
+       если внутри блока server не было директивы listen; ошибка появилась 
+       в 0.8.21.
+
+
 Изменения в nginx 0.8.21                                          26.10.2009
 
     *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI.
--- a/auto/install
+++ b/auto/install
@@ -144,19 +144,4 @@ upgrade:
 	test -f $NGX_PID_PATH.oldbin
 
 	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
-
-upgrade1:
-	# upgrade 0.1.x to 0.2+
-
-	$NGX_SBIN_PATH -t
-
-	cp $NGX_PID_PATH $NGX_PID_PATH.oldbin
-
-	kill -USR2 \`cat $NGX_PID_PATH\`
-	sleep 1
-	test -f $NGX_PID_PATH.oldbin
-
-	cp $NGX_PID_PATH $NGX_PID_PATH.newbin
-
-	kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
 END
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -35,6 +35,12 @@ then
 fi
 
 
+# posix_fadvise64() had been implemented in 2.5.60
+
+if [ $version -lt 132412 ]; then
+    have=NGX_HAVE_POSIX_FADVISE . auto/nohave
+fi
+
 # epoll, EPOLLET version
 
 ngx_feature="epoll"
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8021
-#define NGINX_VERSION      "0.8.21"
+#define nginx_version         8022
+#define NGINX_VERSION      "0.8.22"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -365,6 +365,18 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 continue;
             }
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+            if (ngx_test_config && ls[i].sockaddr->sa_family == AF_UNIX) {
+                u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+                if (ngx_delete_file(name) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                                  ngx_delete_file_n " %s failed", name);
+                }
+            }
+#endif
+
             if (listen(s, ls[i].backlog) == -1) {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                               "listen() to %V, backlog %d failed",
@@ -615,7 +627,8 @@ ngx_close_listening_sockets(ngx_cycle_t 
 #if (NGX_HAVE_UNIX_DOMAIN)
 
         if (ls[i].sockaddr->sa_family == AF_UNIX
-            && ngx_process != NGX_PROCESS_WORKER)
+            && ngx_process != NGX_PROCESS_WORKER
+            && ngx_new_binary == 0)
         {
             u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
 
@@ -881,7 +894,6 @@ ngx_connection_local_sockaddr(ngx_connec
             return NGX_ERROR;
         }
 
-        c->local_socklen = len;
         ngx_memcpy(c->local_sockaddr, &sa, len);
     }
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -129,7 +129,6 @@ struct ngx_connection_s {
 #endif
 
     struct sockaddr    *local_sockaddr;
-    socklen_t           local_socklen;
 
     ngx_buf_t          *buffer;
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -8,9 +8,6 @@
 #include <ngx_core.h>
 
 
-#if (NGX_HAVE_INET6)
-static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
-#endif
 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
 static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
 static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
@@ -59,6 +56,126 @@ ngx_inet_addr(u_char *text, size_t len)
 }
 
 
+#if (NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
+{
+    u_char      c, *zero, *digit, *s, *d;
+    size_t      len4;
+    ngx_uint_t  n, nibbles, word;
+
+    if (len == 0) {
+        return NGX_ERROR;
+    }
+
+    zero = NULL;
+    digit = NULL;
+    len4 = 0;
+    nibbles = 0;
+    word = 0;
+    n = 8;
+
+    if (p[0] == ':') {
+        p++;
+        len--;
+    }
+
+    for (/* void */; len; len--) {
+        c = *p++;
+
+        if (c == ':') {
+            if (nibbles) {
+                digit = p;
+                len4 = len;
+                *addr++ = (u_char) (word >> 8);
+                *addr++ = (u_char) (word & 0xff);
+
+                if (--n) {
+                    nibbles = 0;
+                    word = 0;
+                    continue;
+                }
+
+            } else {
+                if (zero == NULL) {
+                    digit = p;
+                    len4 = len;
+                    zero = addr;
+                    continue;
+                }
+            }
+
+            return NGX_ERROR;
+        }
+
+        if (c == '.' && nibbles) {
+            if (n < 2) {
+                return NGX_ERROR;
+            }
+
+            word = ngx_inet_addr(digit, len4 - 1);
+            if (word == INADDR_NONE) {
+                return NGX_ERROR;
+            }
+
+            word = ntohl(word);
+            *addr++ = (u_char) ((word >> 24) & 0xff);
+            *addr++ = (u_char) ((word >> 16) & 0xff);
+            n--;
+            break;
+        }
+
+        if (++nibbles > 4) {
+            return NGX_ERROR;
+        }
+
+        if (c >= '0' && c <= '9') {
+            word = word * 16 + (c - '0');
+            continue;
+        }
+
+        c |= 0x20;
+
+        if (c >= 'a' && c <= 'f') {
+            word = word * 16 + (c - 'a') + 10;
+            continue;
+        }
+
+        return NGX_ERROR;
+    }
+
+    if (nibbles == 0 && zero == NULL) {
+        return NGX_ERROR;
+    }
+
+    *addr++ = (u_char) (word >> 8);
+    *addr++ = (u_char) (word & 0xff);
+
+    if (--n) {
+        if (zero) {
+            n *= 2;
+            s = addr - 1;
+            d = s + n;
+            while (s >= zero) {
+                *d-- = *s--;
+            }
+            ngx_memzero(zero, n);
+            return NGX_OK;
+        }
+
+    } else {
+        if (zero == NULL) {
+            return NGX_OK;
+        }
+    }
+
+    return NGX_ERROR;
+}
+
+#endif
+
+
 size_t
 ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
 {
@@ -101,7 +218,7 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
             text[n++] = '[';
         }
 
-        n = ngx_inet6_ntop((u_char *) &sin6->sin6_addr, &text[n], len);
+        n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
 
         if (port) {
             n = ngx_sprintf(&text[1 + n], "]:%d",
@@ -158,7 +275,7 @@ ngx_inet_ntop(int family, void *addr, u_
 
 #if (NGX_HAVE_INET6)
 
-static size_t
+size_t
 ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
 {
     u_char      *dst;
@@ -237,31 +354,47 @@ ngx_inet6_ntop(u_char *p, u_char *text, 
 #endif
 
 
-/* AF_INET only */
-
 ngx_int_t
 ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
 {
-    u_char     *addr, *mask, *last;
-    ngx_int_t   shift;
+    u_char      *addr, *mask, *last;
+    size_t       len;
+    ngx_int_t    shift;
+#if (NGX_HAVE_INET6)
+    ngx_int_t    rc;
+    ngx_uint_t   s, i;
+#endif
 
     addr = text->data;
     last = addr + text->len;
 
     mask = ngx_strlchr(addr, last, '/');
+    len = (mask ? mask : last) - addr;
 
-    cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
+    cidr->u.in.addr = ngx_inet_addr(addr, len);
+
+    if (cidr->u.in.addr != INADDR_NONE) {
+        cidr->family = AF_INET;
+
+        if (mask == NULL) {
+            cidr->u.in.mask = 0xffffffff;
+            return NGX_OK;
+        }
 
-    if (cidr->u.in.addr == INADDR_NONE) {
+#if (NGX_HAVE_INET6)
+    } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) {
+        cidr->family = AF_INET6;
+
+        if (mask == NULL) {
+            ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16);
+            return NGX_OK;
+        }
+
+#endif
+    } else {
         return NGX_ERROR;
     }
 
-    if (mask == NULL) {
-        cidr->family = AF_INET;
-        cidr->u.in.mask = 0xffffffff;
-        return NGX_OK;
-    }
-
     mask++;
 
     shift = ngx_atoi(mask, last - mask);
@@ -269,30 +402,108 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t 
         return NGX_ERROR;
     }
 
-    cidr->family = AF_INET;
+    switch (cidr->family) {
 
-    if (shift == 0) {
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        addr = cidr->u.in6.addr.s6_addr;
+        mask = cidr->u.in6.mask.s6_addr;
+        rc = NGX_OK;
+
+        for (i = 0; i < 16; i++) {
+
+            s = (shift > 8) ? 8 : shift;
+            shift -= s;
+
+            mask[i] = (u_char) (0 - (1 << (8 - s)));
 
-        /* the x86 compilers use the shl instruction that shifts by modulo 32 */
+            if (addr[i] != (addr[i] & mask[i])) {
+                rc = NGX_DONE;
+                addr[i] &= mask[i];
+            }
+        }
+
+        return rc;
+#endif
 
-        cidr->u.in.mask = 0;
+    default: /* AF_INET */
+
+        if (shift) {
+            cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
 
-        if (cidr->u.in.addr == 0) {
+        } else {
+            /* x86 compilers use a shl instruction that shifts by modulo 32 */
+            cidr->u.in.mask = 0;
+        }
+
+        if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
             return NGX_OK;
         }
 
+        cidr->u.in.addr &= cidr->u.in.mask;
+
         return NGX_DONE;
     }
+}
+
+
+ngx_int_t
+ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
+{
+    in_addr_t             inaddr;
+    ngx_uint_t            family;
+    struct sockaddr_in   *sin;
+#if (NGX_HAVE_INET6)
+    struct in6_addr       inaddr6;
+    struct sockaddr_in6  *sin6;
+
+    /*
+     * prevent MSVC8 waring:
+     *    potentially uninitialized local variable 'inaddr6' used
+     */
+    ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
+#endif
+
+    inaddr = ngx_inet_addr(text, len);
+
+    if (inaddr != INADDR_NONE) {
+        family = AF_INET;
+        len = sizeof(struct sockaddr_in);
+
+#if (NGX_HAVE_INET6)
+    } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
+        family = AF_INET6;
+        len = sizeof(struct sockaddr_in6);
+
+#endif
+    } else {
+        return NGX_DECLINED;
+    }
 
-    cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
-
-    if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
-        return NGX_OK;
+    addr->sockaddr = ngx_pcalloc(pool, len);
+    if (addr->sockaddr == NULL) {
+        return NGX_ERROR;
     }
 
-    cidr->u.in.addr &= cidr->u.in.mask;
+    addr->sockaddr->sa_family = (u_char) family;
+    addr->socklen = len;
+
+    switch (family) {
 
-    return NGX_DONE;
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) addr->sockaddr;
+        ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+        break;
+#endif
+
+    default: /* AF_INET */
+        sin = (struct sockaddr_in *) addr->sockaddr;
+        sin->sin_addr.s_addr = inaddr;
+        break;
+    }
+
+    return NGX_OK;
 }
 
 
@@ -365,7 +576,7 @@ ngx_parse_unix_domain_url(ngx_pool_t *po
     saun->sun_family = AF_UNIX;
     (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
 
-    u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
+    u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
     if (u->addrs == NULL) {
         return NGX_ERROR;
     }
@@ -523,20 +734,21 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
         return NGX_OK;
     }
 
-    if (len++) {
-
-        p = ngx_alloc(len, pool->log);
-        if (p == NULL) {
-            return NGX_ERROR;
-        }
-
-        (void) ngx_cpystrn(p, host, len);
-
-        sin->sin_addr.s_addr = inet_addr((const char *) p);
+    if (len) {
+        sin->sin_addr.s_addr = ngx_inet_addr(host, len);
 
         if (sin->sin_addr.s_addr == INADDR_NONE) {
+            p = ngx_alloc(++len, pool->log);
+            if (p == NULL) {
+                return NGX_ERROR;
+            }
+
+            (void) ngx_cpystrn(p, host, len);
+
             h = gethostbyname((const char *) p);
 
+            ngx_free(p);
+
             if (h == NULL || h->h_addr_list[0] == NULL) {
                 ngx_free(p);
                 u->err = "host not found";
@@ -550,8 +762,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx
             u->wildcard = 1;
         }
 
-        ngx_free(p);
-
     } else {
         sin->sin_addr.s_addr = INADDR_ANY;
         u->wildcard = 1;
@@ -578,7 +788,6 @@ static ngx_int_t
 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
 {
 #if (NGX_HAVE_INET6)
-    int                   rc;
     u_char               *p, *host, *port, *last, *uri;
     size_t                len;
     ngx_int_t             n;
@@ -650,35 +859,10 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng
         return NGX_ERROR;
     }
 
-    u->host.len = len++;
+    u->host.len = len;
     u->host.data = host;
 
-    p = ngx_alloc(len, pool->log);
-    if (p == NULL) {
-        return NGX_ERROR;
-    }
-
-    (void) ngx_cpystrn(p, host, len);
-
-#if (NGX_WIN32)
-
-    rc = WSAStringToAddress((char *) p, AF_INET6, NULL,
-                            (SOCKADDR *) sin6, &u->socklen);
-    rc = !rc;
-
-    if (u->port) {
-        sin6->sin6_port = htons(u->port);
-    }
-
-#else
-
-    rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr);
-
-#endif
-
-    ngx_free(p);
-
-    if (rc == 0) {
+    if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
         u->err = "invalid IPv6 address";
         return NGX_ERROR;
     }
@@ -721,20 +905,20 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
     struct hostent      *h;
     struct sockaddr_in  *sin;
 
-    host = ngx_alloc(u->host.len + 1, pool->log);
-    if (host == NULL) {
-        return NGX_ERROR;
-    }
-
-    (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
-
     /* AF_INET only */
 
     port = htons(u->port);
 
-    in_addr = inet_addr((char *) host);
+    in_addr = ngx_inet_addr(u->host.data, u->host.len);
 
     if (in_addr == INADDR_NONE) {
+        host = ngx_alloc(u->host.len + 1, pool->log);
+        if (host == NULL) {
+            return NGX_ERROR;
+        }
+
+        (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
         h = gethostbyname((char *) host);
 
         ngx_free(host);
@@ -753,7 +937,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
 
         /* MP: ngx_shared_palloc() */
 
-        u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t));
+        u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
         if (u->addrs == NULL) {
             return NGX_ERROR;
         }
@@ -789,11 +973,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, 
 
     } else {
 
-        ngx_free(host);
-
         /* MP: ngx_shared_palloc() */
 
-        u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
+        u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
         if (u->addrs == NULL) {
             return NGX_ERROR;
         }
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -70,7 +70,7 @@ typedef struct {
     struct sockaddr          *sockaddr;
     socklen_t                 socklen;
     ngx_str_t                 name;
-} ngx_peer_addr_t;
+} ngx_addr_t;
 
 
 typedef struct {
@@ -94,7 +94,7 @@ typedef struct {
     socklen_t                 socklen;
     u_char                    sockaddr[NGX_SOCKADDRLEN];
 
-    ngx_peer_addr_t          *addrs;
+    ngx_addr_t               *addrs;
     ngx_uint_t                naddrs;
 
     char                     *err;
@@ -102,13 +102,18 @@ typedef struct {
 
 
 in_addr_t ngx_inet_addr(u_char *text, size_t len);
+#if (NGX_HAVE_INET6)
+ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr);
+size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
+#endif
 size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len,
     ngx_uint_t port);
 size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
 ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
+ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
+    size_t len);
 ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
 ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u);
 
 
-
 #endif /* _NGX_INET_H_INCLUDED_ */
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -92,7 +92,7 @@ static void *ngx_resolver_dup(ngx_resolv
 /* STUB: ngx_peer_addr_t * */
 
 ngx_resolver_t *
-ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr)
+ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr)
 {
     ngx_resolver_t        *r;
     ngx_pool_cleanup_t    *cln;
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -135,7 +135,7 @@ struct ngx_resolver_ctx_s {
 };
 
 
-ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr);
+ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr);
 ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
     ngx_resolver_ctx_t *temp);
 ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -15,10 +15,11 @@ static u_char *ngx_sprintf_num(u_char *b
 void
 ngx_strlow(u_char *dst, u_char *src, size_t n)
 {
-    while (n--) {
+    while (n) {
         *dst = ngx_tolower(*src);
         dst++;
         src++;
+        n--;
     }
 }
 
@@ -147,7 +148,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
     int64_t                i64;
     uint64_t               ui64;
     ngx_msec_t             ms;
-    ngx_uint_t             width, sign, hex, max_width, frac_width, i;
+    ngx_uint_t             width, sign, hex, max_width, frac_width, n;
     ngx_str_t             *v;
     ngx_variable_value_t  *vv;
 
@@ -377,7 +378,7 @@ ngx_vslprintf(u_char *buf, u_char *last,
 
                     scale = 1.0;
 
-                    for (i = 0; i < frac_width; i++) {
+                    for (n = frac_width; n; n--) {
                         scale *= 10.0;
                     }
 
@@ -1255,7 +1256,7 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr
 uintptr_t
 ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
 {
-    ngx_uint_t      i, n;
+    ngx_uint_t      n;
     uint32_t       *escape;
     static u_char   hex[] = "0123456789abcdef";
 
@@ -1373,17 +1374,18 @@ ngx_escape_uri(u_char *dst, u_char *src,
 
         n = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                 n++;
             }
             src++;
+            size--;
         }
 
         return (uintptr_t) n;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
             *dst++ = '%';
             *dst++ = hex[*src >> 4];
@@ -1393,6 +1395,7 @@ ngx_escape_uri(u_char *dst, u_char *src,
         } else {
             *dst++ = *src++;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
@@ -1533,13 +1536,13 @@ uintptr_t
 ngx_escape_html(u_char *dst, u_char *src, size_t size)
 {
     u_char      ch;
-    ngx_uint_t  i, len;
+    ngx_uint_t  len;
 
     if (dst == NULL) {
 
         len = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             switch (*src++) {
 
             case '<':
@@ -1557,12 +1560,13 @@ ngx_escape_html(u_char *dst, u_char *src
             default:
                 break;
             }
+            size--;
         }
 
         return (uintptr_t) len;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         ch = *src++;
 
         switch (ch) {
@@ -1584,6 +1588,7 @@ ngx_escape_html(u_char *dst, u_char *src
             *dst++ = ch;
             break;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -152,7 +152,6 @@ ngx_event_accept(ngx_event_t *ev)
         c->socklen = socklen;
         c->listening = ls;
         c->local_sockaddr = ls->sockaddr;
-        c->local_socklen = ls->socklen;
 
         c->unexpected_eof = 1;
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -54,15 +54,7 @@ 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");
-            }
-
-            return NGX_ERROR;
+            goto failed;
         }
     }
 
@@ -70,14 +62,16 @@ 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);
+        goto failed;
+    }
 
-        if (ngx_close_socket(s) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
-                          ngx_close_socket_n " failed");
+    if (pc->local) {
+        if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
+                          "bind(%V) failed", &pc->local->name);
+
+            goto failed;
         }
-
-        return NGX_ERROR;
     }
 
     c->recv = ngx_recv;
@@ -127,7 +121,7 @@ ngx_event_connect_peer(ngx_peer_connecti
 
     if (ngx_add_conn) {
         if (ngx_add_conn(c) == NGX_ERROR) {
-            return NGX_ERROR;
+            goto failed;
         }
     }
 
@@ -199,7 +193,7 @@ ngx_event_connect_peer(ngx_peer_connecti
         if (ngx_blocking(s) == -1) {
             ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                           ngx_blocking_n " failed");
-            return NGX_ERROR;
+            goto failed;
         }
 
         /*
@@ -229,7 +223,7 @@ ngx_event_connect_peer(ngx_peer_connecti
     }
 
     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
-        return NGX_ERROR;
+        goto failed;
     }
 
     if (rc == -1) {
@@ -237,7 +231,7 @@ ngx_event_connect_peer(ngx_peer_connecti
         /* NGX_EINPROGRESS */
 
         if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
-            return NGX_ERROR;
+            goto failed;
         }
 
         return NGX_AGAIN;
@@ -248,6 +242,17 @@ ngx_event_connect_peer(ngx_peer_connecti
     wev->ready = 1;
 
     return NGX_OK;
+
+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");
+    }
+
+    return NGX_ERROR;
 }
 
 
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -55,6 +55,8 @@ struct ngx_peer_connection_s {
     ngx_atomic_t                    *lock;
 #endif
 
+    ngx_addr_t                      *local;
+
     int                              rcvbuf;
 
     ngx_log_t                       *log;
@@ -70,5 +72,4 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
 ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data);
 
 
-
 #endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -946,7 +946,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
 
     for ( ;; ) {
 
-        while (in && buf->last < buf->end) {
+        while (in && buf->last < buf->end && send < limit) {
             if (in->buf->last_buf || in->buf->flush) {
                 flush = 1;
             }
@@ -973,8 +973,8 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
             ngx_memcpy(buf->last, in->buf->pos, size);
 
             buf->last += size;
-
             in->buf->pos += size;
+            send += size;
 
             if (in->buf->pos == in->buf->last) {
                 in = in->next;
@@ -999,7 +999,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
         }
 
         buf->pos += n;
-        send += n;
         c->sent += n;
 
         if (n < size) {
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -10,18 +10,37 @@
 
 
 typedef struct {
-    in_addr_t     mask;
-    in_addr_t     addr;
-    ngx_uint_t    deny;      /* unsigned  deny:1; */
+    in_addr_t         mask;
+    in_addr_t         addr;
+    ngx_uint_t        deny;      /* unsigned  deny:1; */
 } ngx_http_access_rule_t;
 
+#if (NGX_HAVE_INET6)
 
 typedef struct {
-    ngx_array_t  *rules;     /* array of ngx_http_access_rule_t */
+    struct in6_addr   addr;
+    struct in6_addr   mask;
+    ngx_uint_t        deny;      /* unsigned  deny:1; */
+} ngx_http_access_rule6_t;
+
+#endif
+
+typedef struct {
+    ngx_array_t      *rules;     /* array of ngx_http_access_rule_t */
+#if (NGX_HAVE_INET6)
+    ngx_array_t      *rules6;    /* array of ngx_http_access_rule6_t */
+#endif
 } ngx_http_access_loc_conf_t;
 
 
 static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r,
+    ngx_http_access_loc_conf_t *alcf, in_addr_t addr);
+#if (NGX_HAVE_INET6)
+static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r,
+    ngx_http_access_loc_conf_t *alcf, u_char *p);
+#endif
+static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
 static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
@@ -87,46 +106,59 @@ ngx_module_t  ngx_http_access_module = {
 static ngx_int_t
 ngx_http_access_handler(ngx_http_request_t *r)
 {
-    ngx_uint_t                   i;
     struct sockaddr_in          *sin;
-    ngx_http_access_rule_t      *rule;
-    ngx_http_core_loc_conf_t    *clcf;
     ngx_http_access_loc_conf_t  *alcf;
 
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
 
-    if (alcf->rules == NULL) {
-        return NGX_DECLINED;
+#if (NGX_HAVE_INET6)
+
+    if (alcf->rules6 && r->connection->sockaddr->sa_family == AF_INET6) {
+        u_char               *p;
+        in_addr_t             addr;
+        struct sockaddr_in6  *sin6;
+
+        sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
+        p = sin6->sin6_addr.s6_addr;
+
+        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+            addr = p[12] << 24;
+            addr += p[13] << 16;
+            addr += p[14] << 8;
+            addr += p[15];
+            return ngx_http_access_inet(r, alcf, htonl(addr));
+        }
+
+        return ngx_http_access_inet6(r, alcf, p);
     }
 
-    /* AF_INET only */
+#endif
 
-    if (r->connection->sockaddr->sa_family != AF_INET) {
-        return NGX_DECLINED;
+    if (alcf->rules && r->connection->sockaddr->sa_family == AF_INET) {
+        sin = (struct sockaddr_in *) r->connection->sockaddr;
+        return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr);
     }
 
-    sin = (struct sockaddr_in *) r->connection->sockaddr;
+    return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
+    in_addr_t addr)
+{
+    ngx_uint_t               i;
+    ngx_http_access_rule_t  *rule;
 
     rule = alcf->rules->elts;
     for (i = 0; i < alcf->rules->nelts; i++) {
 
         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "access: %08XD %08XD %08XD",
-                       sin->sin_addr.s_addr, rule[i].mask, rule[i].addr);
-
-        if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
-            if (rule[i].deny) {
-                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+                       addr, rule[i].mask, rule[i].addr);
 
-                if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
-                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                                  "access forbidden by rule");
-                }
-
-                return NGX_HTTP_FORBIDDEN;
-            }
-
-            return NGX_OK;
+        if ((addr & rule[i].mask) == rule[i].addr) {
+            return ngx_http_access_found(r, rule[i].deny);
         }
     }
 
@@ -134,62 +166,159 @@ ngx_http_access_handler(ngx_http_request
 }
 
 
+#if (NGX_HAVE_INET6)
+
+static ngx_int_t
+ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
+    u_char *p)
+{
+    ngx_uint_t                n;
+    ngx_uint_t                i;
+    ngx_http_access_rule6_t  *rule6;
+
+    rule6 = alcf->rules6->elts;
+    for (i = 0; i < alcf->rules6->nelts; i++) {
+
+#if (NGX_DEBUG)
+        {
+        size_t  cl, ml, al;
+        u_char  ct[NGX_INET6_ADDRSTRLEN];
+        u_char  mt[NGX_INET6_ADDRSTRLEN];
+        u_char  at[NGX_INET6_ADDRSTRLEN];
+
+        cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN);
+        ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN);
+        al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "access: %*s %*s %*s", cl, ct, ml, mt, al, at);
+        }
+#endif
+
+        for (n = 0; n < 16; n++) {
+            if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) {
+                goto next;
+            }
+        }
+
+        return ngx_http_access_found(r, rule6[i].deny);
+
+    next:
+        continue;
+    }
+
+    return NGX_DECLINED;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
+{
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (deny) {
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+        if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "access forbidden by rule");
+        }
+
+        return NGX_HTTP_FORBIDDEN;
+    }
+
+    return NGX_OK;
+}
+
+
 static char *
 ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_access_loc_conf_t *alcf = conf;
 
-    ngx_int_t                rc;
-    ngx_str_t               *value;
-    ngx_cidr_t               cidr;
-    ngx_http_access_rule_t  *rule;
+    ngx_int_t                 rc;
+    ngx_uint_t                all;
+    ngx_str_t                *value;
+    ngx_cidr_t                cidr;
+    ngx_http_access_rule_t   *rule;
+#if (NGX_HAVE_INET6)
+    ngx_http_access_rule6_t  *rule6;
+#endif
 
-    if (alcf->rules == NULL) {
-        alcf->rules = ngx_array_create(cf->pool, 4,
-                                       sizeof(ngx_http_access_rule_t));
-        if (alcf->rules == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    rule = ngx_array_push(alcf->rules);
-    if (rule == NULL) {
-        return NGX_CONF_ERROR;
-    }
+    ngx_memzero(&cidr, sizeof(ngx_cidr_t));
 
     value = cf->args->elts;
 
-    rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+    all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0);
+
+    if (!all) {
+
+        rc = ngx_ptocidr(&value[1], &cidr);
 
-    if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
-        rule->mask = 0;
-        rule->addr = 0;
+        if (rc == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                         "invalid parameter \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
 
-        return NGX_CONF_OK;
+        if (rc == NGX_DONE) {
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                         "low address bits of %V are meaningless", &value[1]);
+        }
     }
 
-    rc = ngx_ptocidr(&value[1], &cidr);
+    switch (cidr.family) {
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+    case 0: /* all */
 
-    if (rc == NGX_ERROR) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
-                           &value[1]);
-        return NGX_CONF_ERROR;
-    }
+        if (alcf->rules6 == NULL) {
+            alcf->rules6 = ngx_array_create(cf->pool, 4,
+                                            sizeof(ngx_http_access_rule6_t));
+            if (alcf->rules6 == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        rule6 = ngx_array_push(alcf->rules6);
+        if (rule6 == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        rule6->mask = cidr.u.in6.mask;
+        rule6->addr = cidr.u.in6.addr;
+        rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
 
-    if (cidr.family != AF_INET) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "\"allow\" supports IPv4 only");
-        return NGX_CONF_ERROR;
-    }
+        if (!all) {
+            break;
+        }
+
+        /* "all" passes through */
+#endif
+
+    default: /* AF_INET */
 
-    if (rc == NGX_DONE) {
-        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                           "low address bits of %V are meaningless", &value[1]);
+        if (alcf->rules == NULL) {
+            alcf->rules = ngx_array_create(cf->pool, 4,
+                                           sizeof(ngx_http_access_rule_t));
+            if (alcf->rules == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        rule = ngx_array_push(alcf->rules);
+        if (rule == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        rule->mask = cidr.u.in.mask;
+        rule->addr = cidr.u.in.addr;
+        rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
     }
 
-    rule->mask = cidr.u.in.mask;
-    rule->addr = cidr.u.in.addr;
-
     return NGX_CONF_OK;
 }
 
@@ -218,6 +347,12 @@ ngx_http_access_merge_loc_conf(ngx_conf_
         conf->rules = prev->rules;
     }
 
+#if (NGX_HAVE_INET6)
+    if (conf->rules6 == NULL) {
+        conf->rules6 = prev->rules6;
+    }
+#endif
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -240,6 +240,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
       NULL },
 
+    { ngx_string("fastcgi_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upsteam_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("fastcgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -650,7 +650,7 @@ ngx_http_log_variable(ngx_http_request_t
 static uintptr_t
 ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
 {
-    ngx_uint_t      i, n;
+    ngx_uint_t      n;
     static u_char   hex[] = "0123456789ABCDEF";
 
     static uint32_t   escape[] = {
@@ -678,17 +678,18 @@ ngx_http_log_escape(u_char *dst, u_char 
 
         n = 0;
 
-        for (i = 0; i < size; i++) {
+        while (size) {
             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                 n++;
             }
             src++;
+            size--;
         }
 
         return (uintptr_t) n;
     }
 
-    for (i = 0; i < size; i++) {
+    while (size) {
         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
             *dst++ = '\\';
             *dst++ = 'x';
@@ -699,6 +700,7 @@ ngx_http_log_escape(u_char *dst, u_char 
         } else {
             *dst++ = *src++;
         }
+        size--;
     }
 
     return (uintptr_t) dst;
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -63,6 +63,13 @@ static ngx_command_t  ngx_http_memcached
       0,
       NULL },
 
+    { ngx_string("memcached_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upsteam_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("memcached_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -229,6 +229,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
       NULL },
 
+    { ngx_string("proxy_bind"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_upsteam_bind_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -25,17 +25,23 @@ typedef struct {
     ngx_uint_t         type;
     ngx_uint_t         hash;
     ngx_str_t          header;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_uint_t         unixsock; /* unsigned  unixsock:1; */
+#endif
 } ngx_http_realip_loc_conf_t;
 
 
 typedef struct {
     ngx_connection_t  *connection;
-    in_addr_t          addr;
+    struct sockaddr   *sockaddr;
+    socklen_t          socklen;
     ngx_str_t          addr_text;
 } ngx_http_realip_ctx_t;
 
 
 static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip,
+    size_t len);
 static void ngx_http_realip_cleanup(void *data);
 static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -103,13 +109,11 @@ ngx_http_realip_handler(ngx_http_request
 {
     u_char                      *ip, *p;
     size_t                       len;
-    in_addr_t                    addr;
     ngx_uint_t                   i, hash;
     ngx_list_part_t             *part;
     ngx_table_elt_t             *header;
     struct sockaddr_in          *sin;
     ngx_connection_t            *c;
-    ngx_pool_cleanup_t          *cln;
     ngx_http_realip_ctx_t       *ctx;
     ngx_http_realip_from_t      *from;
     ngx_http_realip_loc_conf_t  *rlcf;
@@ -120,11 +124,6 @@ ngx_http_realip_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
 
     if (rlcf->from == NULL) {
@@ -207,52 +206,83 @@ found:
 
     /* AF_INET only */
 
-    if (r->connection->sockaddr->sa_family != AF_INET) {
-        return NGX_DECLINED;
+    if (c->sockaddr->sa_family == AF_INET) {
+        sin = (struct sockaddr_in *) c->sockaddr;
+
+        from = rlcf->from->elts;
+        for (i = 0; i < rlcf->from->nelts; i++) {
+
+            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                           "realip: %08XD %08XD %08XD",
+                           sin->sin_addr.s_addr, from[i].mask, from[i].addr);
+
+            if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
+                return ngx_http_realip_set_addr(r, ip, len);
+            }
+        }
+    }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    if (c->sockaddr->sa_family == AF_UNIX && rlcf->unixsock) {
+        return ngx_http_realip_set_addr(r, ip, len);
     }
 
-    sin = (struct sockaddr_in *) c->sockaddr;
+#endif
 
-    from = rlcf->from->elts;
-    for (i = 0; i < rlcf->from->nelts; i++) {
+    return NGX_DECLINED;
+}
 
-        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                       "realip: %08XD %08XD %08XD",
-                       sin->sin_addr.s_addr, from[i].mask, from[i].addr);
 
-        if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
-
-            ctx = cln->data;
-
-            ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
+static ngx_int_t
+ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, size_t len)
+{
+    u_char                 *p;
+    ngx_int_t               rc;
+    ngx_addr_t              addr;
+    ngx_connection_t       *c;
+    ngx_pool_cleanup_t     *cln;
+    ngx_http_realip_ctx_t  *ctx;
 
-            addr = inet_addr((char *) ip);
+    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
+    if (cln == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-            if (addr == INADDR_NONE) {
-                return NGX_DECLINED;
-            }
+    ctx = cln->data;
+    ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
+
+    c = r->connection;
+
+    rc = ngx_parse_addr(c->pool, &addr, ip, len);
 
-            p = ngx_pnalloc(c->pool, len);
-            if (p == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+    switch (rc) {
+    case NGX_DECLINED:
+        return NGX_DECLINED;
+    case NGX_ERROR:
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    default: /* NGX_OK */
+        break;
+    }
 
-            ngx_memcpy(p, ip, len);
-
-            cln->handler = ngx_http_realip_cleanup;
+    p = ngx_pnalloc(c->pool, len);
+    if (p == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-            ctx->connection = c;
-            ctx->addr = sin->sin_addr.s_addr;
-            ctx->addr_text = c->addr_text;
+    ngx_memcpy(p, ip, len);
 
-            sin->sin_addr.s_addr = addr;
+    cln->handler = ngx_http_realip_cleanup;
 
-            c->addr_text.len = len;
-            c->addr_text.data = p;
+    ctx->connection = c;
+    ctx->sockaddr = c->sockaddr;
+    ctx->socklen = c->socklen;
+    ctx->addr_text = c->addr_text;
 
-            return NGX_DECLINED;
-        }
-    }
+    c->sockaddr = addr.sockaddr;
+    c->socklen = addr.socklen;
+    c->addr_text.len = len;
+    c->addr_text.data = p;
 
     return NGX_DECLINED;
 }
@@ -263,14 +293,12 @@ ngx_http_realip_cleanup(void *data)
 {
     ngx_http_realip_ctx_t *ctx = data;
 
-    ngx_connection_t    *c;
-    struct sockaddr_in  *sin;
+    ngx_connection_t  *c;
 
     c = ctx->connection;
 
-    sin = (struct sockaddr_in *) c->sockaddr;
-    sin->sin_addr.s_addr = ctx->addr;
-
+    c->sockaddr = ctx->sockaddr;
+    c->socklen = ctx->socklen;
     c->addr_text = ctx->addr_text;
 }
 
@@ -285,6 +313,17 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
     ngx_cidr_t               cidr;
     ngx_http_realip_from_t  *from;
 
+    value = cf->args->elts;
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    if (ngx_strcmp(value[1].data, "unix:") == 0) {
+         rlcf->unixsock = 1;
+         return NGX_CONF_OK;
+    }
+
+#endif
+
     if (rlcf->from == NULL) {
         rlcf->from = ngx_array_create(cf->pool, 2,
                                       sizeof(ngx_http_realip_from_t));
@@ -298,8 +337,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    value = cf->args->elts;
-
     rc = ngx_ptocidr(&value[1], &cidr);
 
     if (rc == NGX_ERROR) {
@@ -310,7 +347,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx
 
     if (cidr.family != AF_INET) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "\"realip_from\" supports IPv4 only");
+                           "\"set_real_ip_from\" supports IPv4 only");
         return NGX_CONF_ERROR;
     }
 
@@ -369,6 +406,7 @@ ngx_http_realip_create_loc_conf(ngx_conf
      *     conf->from = NULL;
      *     conf->hash = 0;
      *     conf->header = { 0, NULL };
+     *     conf->unixsock = 0;
      */
 
     conf->type = NGX_CONF_UNSET_UINT;
@@ -385,6 +423,9 @@ ngx_http_realip_merge_loc_conf(ngx_conf_
 
     if (conf->from == NULL) {
         conf->from = prev->from;
+#if (NGX_HAVE_UNIX_DOMAIN)
+        conf->unixsock = prev->unixsock;
+#endif
     }
 
     ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.21';
+our $VERSION = '0.8.22';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1348,10 +1348,14 @@ static ngx_int_t
 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_array_t *ports)
 {
-    ngx_uint_t               p, a;
+    ngx_uint_t             p, a;
     ngx_http_conf_port_t  *port;
     ngx_http_conf_addr_t  *addr;
 
+    if (ports == NULL) {
+        return NGX_OK;
+    }
+
     port = ports->elts;
     for (p = 0; p < ports->nelts; p++) {
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2838,6 +2838,33 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
 
     /* TODO: it does not merge, it inits only */
 
+    ngx_conf_merge_size_value(conf->connection_pool_size,
+                              prev->connection_pool_size, 256);
+    ngx_conf_merge_size_value(conf->request_pool_size,
+                              prev->request_pool_size, 4096);
+    ngx_conf_merge_msec_value(conf->client_header_timeout,
+                              prev->client_header_timeout, 60000);
+    ngx_conf_merge_size_value(conf->client_header_buffer_size,
+                              prev->client_header_buffer_size, 1024);
+    ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
+                              prev->large_client_header_buffers,
+                              4, ngx_pagesize);
+
+    if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the \"large_client_header_buffers\" size must be "
+                           "equal to or bigger than \"connection_pool_size\"");
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_conf_merge_value(conf->ignore_invalid_headers,
+                              prev->ignore_invalid_headers, 1);
+
+    ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1);
+
+    ngx_conf_merge_value(conf->underscores_in_headers,
+                              prev->underscores_in_headers, 0);
+
     if (!conf->listen) {
         ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
 
@@ -2882,33 +2909,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
         sn->name.data = conf->server_name.data;
     }
 
-    ngx_conf_merge_size_value(conf->connection_pool_size,
-                              prev->connection_pool_size, 256);
-    ngx_conf_merge_size_value(conf->request_pool_size,
-                              prev->request_pool_size, 4096);
-    ngx_conf_merge_msec_value(conf->client_header_timeout,
-                              prev->client_header_timeout, 60000);
-    ngx_conf_merge_size_value(conf->client_header_buffer_size,
-                              prev->client_header_buffer_size, 1024);
-    ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
-                              prev->large_client_header_buffers,
-                              4, ngx_pagesize);
-
-    if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the \"large_client_header_buffers\" size must be "
-                           "equal to or bigger than \"connection_pool_size\"");
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_conf_merge_value(conf->ignore_invalid_headers,
-                              prev->ignore_invalid_headers, 1);
-
-    ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1);
-
-    ngx_conf_merge_value(conf->underscores_in_headers,
-                              prev->underscores_in_headers, 0);
-
     return NGX_CONF_OK;
 }
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -954,9 +954,17 @@ ngx_http_process_request_headers(ngx_eve
                 }
 
                 if (rv == NGX_DECLINED) {
-                    len = r->header_in->end - r->header_name_start;
                     p = r->header_name_start;
 
+                    if (p == NULL) {
+                        ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                                      "client sent too large request");
+                        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+                        return;
+                    }
+
+                    len = r->header_in->end - p;
+
                     if (len > NGX_MAX_ERROR_STR - 300) {
                         len = NGX_MAX_ERROR_STR - 300;
                         p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -479,6 +479,8 @@ ngx_http_upstream_init_request(ngx_http_
         return;
     }
 
+    u->peer.local = u->conf->local;
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     u->output.alignment = clcf->directio_alignment;
@@ -4196,6 +4198,41 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
 }
 
 
+char *
+ngx_http_upsteam_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf)
+{
+    char  *p = conf;
+
+    ngx_int_t     rc;
+    ngx_str_t    *value;
+    ngx_addr_t  **paddr;
+
+    paddr = (ngx_addr_t **) (p + cmd->offset);
+
+    *paddr = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
+    if (*paddr == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    rc = ngx_parse_addr(cf->pool, *paddr, value[1].data, value[1].len);
+
+    switch (rc) {
+    case NGX_OK:
+        (*paddr)->name = value[1];
+        return NGX_CONF_OK;
+
+    case NGX_DECLINED:
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid address \"%V\"", &value[1]);
+    default:
+        return NGX_CONF_ERROR;
+    }
+}
+
+
 ngx_int_t
 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -80,7 +80,7 @@ typedef struct {
 
 
 typedef struct {
-    ngx_peer_addr_t                 *addrs;
+    ngx_addr_t                      *addrs;
     ngx_uint_t                       naddrs;
     ngx_uint_t                       weight;
     ngx_uint_t                       max_fails;
@@ -152,6 +152,8 @@ typedef struct {
     ngx_array_t                     *hide_headers;
     ngx_array_t                     *pass_headers;
 
+    ngx_addr_t                      *local;
+
 #if (NGX_HTTP_CACHE)
     ngx_shm_zone_t                  *cache;
 
@@ -321,6 +323,8 @@ ngx_int_t ngx_http_upstream_create(ngx_h
 void ngx_http_upstream_init(ngx_http_request_t *r);
 ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
     ngx_url_t *u, ngx_uint_t flags);
+char *ngx_http_upsteam_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
@@ -334,5 +338,4 @@ extern ngx_module_t        ngx_http_upst
 extern ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[];
 
 
-
 #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -81,5 +81,4 @@ void ngx_http_upstream_save_round_robin_
 #endif
 
 
-
 #endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -14,6 +14,8 @@ static ngx_int_t ngx_http_variable_reque
     ngx_http_variable_value_t *v, uintptr_t data);
 static void ngx_http_variable_request_set(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
@@ -238,7 +240,7 @@ static ngx_http_variable_t  ngx_http_cor
       offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
 
     { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
-      ngx_http_variable_request,
+      ngx_http_variable_request_get_size,
       offsetof(ngx_http_request_t, limit_rate),
       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
@@ -568,6 +570,28 @@ ngx_http_variable_request_set(ngx_http_r
 }
 
 
+static ngx_int_t
+ngx_http_variable_request_get_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    size_t  *sp;
+
+    sp = (size_t *) ((char *) r + data);
+
+    v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
+    if (v->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    return NGX_OK;
+}
+
+
 static void
 ngx_http_variable_request_set_size(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
@@ -887,7 +911,7 @@ ngx_http_variable_binary_remote_addr(ngx
         v->valid = 1;
         v->no_cacheable = 0;
         v->not_found = 0;
-        v->data = (u_char *) &sin6->sin6_addr;
+        v->data = sin6->sin6_addr.s6_addr;
 
         break;
 #endif
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -394,7 +394,7 @@ char *ngx_mail_capabilities(ngx_conf_t *
 
 
 /* STUB */
-void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer);
+void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer);
 void ngx_mail_auth_http_init(ngx_mail_session_t *s);
 /**/
 
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -12,7 +12,7 @@
 
 
 typedef struct {
-    ngx_peer_addr_t                *peer;
+    ngx_addr_t                     *peer;
 
     ngx_msec_t                      timeout;
 
@@ -457,7 +457,7 @@ ngx_mail_auth_http_process_headers(ngx_m
     time_t               timer;
     size_t               len, size;
     ngx_int_t            rc, port, n;
-    ngx_peer_addr_t     *peer;
+    ngx_addr_t          *peer;
     struct sockaddr_in  *sin;
 
     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
@@ -764,7 +764,7 @@ ngx_mail_auth_http_process_headers(ngx_m
                 return;
             }
 
-            peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
+            peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t));
             if (peer == NULL) {
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
@@ -795,8 +795,7 @@ ngx_mail_auth_http_process_headers(ngx_m
 
             sin->sin_port = htons((in_port_t) port);
 
-            ctx->addr.data[ctx->addr.len] = '\0';
-            sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
+            sin->sin_addr.s_addr = ngx_inet_addr(ctx->addr.data, ctx->addr.len);
             if (sin->sin_addr.s_addr == INADDR_NONE) {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V sent invalid server "
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -108,7 +108,7 @@ static u_char  smtp_auth_ok[] = "235 2.0
 
 
 void
-ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer)
+ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)
 {
     int                        keepalive;
     ngx_int_t                  rc;
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -141,7 +141,7 @@ ngx_int_t ngx_set_file_time(u_char *name
 #define ngx_is_dir(sb)           (S_ISDIR((sb)->st_mode))
 #define ngx_is_file(sb)          (S_ISREG((sb)->st_mode))
 #define ngx_is_link(sb)          (S_ISLNK((sb)->st_mode))
-#define ngx_is_exec(sb)          ((sb)->st_mode & S_IXUSR)
+#define ngx_is_exec(sb)          (((sb)->st_mode & S_IXUSR) == S_IXUSR)
 #define ngx_file_access(sb)      ((sb)->st_mode & 0777)
 #define ngx_file_size(sb)        (sb)->st_size
 #define ngx_file_mtime(sb)       (sb)->st_mtime
--- a/src/os/unix/ngx_freebsd_rfork_thread.h
+++ b/src/os/unix/ngx_freebsd_rfork_thread.h
@@ -118,5 +118,4 @@ void ngx_mutex_unlock(ngx_mutex_t *m);
 typedef int (*ngx_rfork_thread_func_pt)(void *arg);
 
 
-
 #endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */
--- a/src/os/unix/ngx_setproctitle.h
+++ b/src/os/unix/ngx_setproctitle.h
@@ -13,7 +13,7 @@
 /* FreeBSD, NetBSD, OpenBSD */
 
 #define ngx_init_setproctitle(log)
-#define ngx_setproctitle           setproctitle
+#define ngx_setproctitle(title)    setproctitle("%s", title)
 
 
 #else /* !NGX_HAVE_SETPROCTITLE */
--- a/src/os/unix/ngx_thread.h
+++ b/src/os/unix/ngx_thread.h
@@ -124,5 +124,4 @@ ngx_int_t ngx_cond_signal(ngx_cond_t *cv
 #endif
 
 
-
 #endif /* _NGX_THREAD_H_INCLUDED_ */
--- a/src/os/unix/ngx_user.h
+++ b/src/os/unix/ngx_user.h
@@ -20,5 +20,4 @@ ngx_int_t ngx_crypt(ngx_pool_t *pool, u_
     u_char **encrypted);
 
 
-
 #endif /* _NGX_USER_H_INCLUDED_ */