changeset 3271:fcd98af88df3

proxy_bind, fastcgi_bind, and memcached_bind
author Igor Sysoev <igor@sysoev.ru>
date Mon, 02 Nov 2009 15:24:02 +0000
parents 7d1a04259e3f
children 98f49b2bcae8
files src/event/ngx_event_connect.c src/event/ngx_event_connect.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h
diffstat 7 files changed, 78 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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_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/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,31 @@ 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_str_t    *value;
+    ngx_addr_t  **paddr;
+
+    paddr = (ngx_addr_t **) (p + cmd->offset);
+
+    value = cf->args->elts;
+
+    *paddr = ngx_parse_addr(cf->pool, &value[1]);
+    if (*paddr) {
+        return NGX_CONF_OK;
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "invalid address \"%V\"", &value[1]);
+
+    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
@@ -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);