aboutsummaryrefslogtreecommitdiff
path: root/src/http/modules
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2006-12-04 16:46:13 +0000
committerIgor Sysoev <igor@sysoev.ru>2006-12-04 16:46:13 +0000
commit3d2fd18a3935a7f1b68f14aa95990eef8841acad (patch)
tree9b0bc5932393105bf4f89f403d042494762b8ea2 /src/http/modules
parenta53f7293c8b8e2dcc3168ce96903afe5c55dd763 (diff)
downloadnginx-3d2fd18a3935a7f1b68f14aa95990eef8841acad.tar.gz
nginx-3d2fd18a3935a7f1b68f14aa95990eef8841acad.zip
upstream choice modules
Diffstat (limited to 'src/http/modules')
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c81
-rw-r--r--src/http/modules/ngx_http_memcached_module.c81
-rw-r--r--src/http/modules/ngx_http_proxy_module.c79
-rw-r--r--src/http/modules/ngx_http_upstream_ip_hash_module.c228
4 files changed, 355 insertions, 114 deletions
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index f22de517a..ab214770e 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -13,9 +13,6 @@
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_http_upstream_srv_conf_t *upstream_peers;
- ngx_peers_t *peers0;
-
ngx_str_t index;
ngx_array_t *flushes;
@@ -121,6 +118,11 @@ static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
void *data);
+static char *ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = {
{ 1, /* version */
@@ -310,16 +312,16 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
{ ngx_string("fastcgi_upstream_max_fails"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_num_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_fails),
+ ngx_http_fastcgi_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("fastcgi_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_fastcgi_loc_conf_t, upstream.fail_timeout),
+ ngx_http_fastcgi_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("fastcgi_param"),
@@ -411,8 +413,6 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = flcf->upstream_peers->peers;
- u->peer.tries = flcf->upstream_peers->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -1547,9 +1547,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
@@ -1573,7 +1570,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
uintptr_t *code;
ngx_str_t *header;
ngx_uint_t i, j;
- ngx_peer_t *peer;
ngx_array_t hide_headers;
ngx_keyval_t *src;
ngx_hash_key_t *hk;
@@ -1707,25 +1703,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->upstream_peers) {
- peer = conf->upstream_peers->peers->peer;
- for (i = 0; i < conf->upstream_peers->peers->number; i++) {
- ngx_conf_init_uint_value(peer[i].weight, 1);
- peer[i].current_weight = peer[i].weight;
- ngx_conf_init_uint_value(peer[i].max_fails,
- conf->upstream.max_fails);
- ngx_conf_init_value(peer[i].fail_timeout,
- conf->upstream.fail_timeout);
- }
-
- }
-
ngx_conf_merge_path_value(conf->upstream.temp_path,
prev->upstream.temp_path,
NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
@@ -1844,8 +1821,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
peers:
- if (conf->upstream_peers == NULL) {
- conf->upstream_peers = prev->upstream_peers;
+ if (conf->upstream.upstream == NULL) {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->upstream.schema = prev->upstream.schema;
}
@@ -2033,10 +2010,10 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
- u.upstream = 1;
+ u.no_resolve = 1;
- lcf->upstream_peers = ngx_http_upstream_add(cf, &u);
- if (lcf->upstream_peers == NULL) {
+ lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (lcf->upstream.upstream == NULL) {
return NGX_CONF_ERROR;
}
@@ -2084,3 +2061,29 @@ ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"fastcgi_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"fastcgi_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
index 63bda6498..bd8b83716 100644
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -12,7 +12,6 @@
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_peers_t *peers;
} ngx_http_memcached_loc_conf_t;
@@ -39,6 +38,11 @@ static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf,
static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = {
{ ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -96,16 +100,16 @@ static ngx_command_t ngx_http_memcached_commands[] = {
{ ngx_string("memcached_upstream_max_fails"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_num_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_memcached_loc_conf_t, upstream.max_fails),
+ ngx_http_memcached_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("memcached_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_memcached_loc_conf_t, upstream.fail_timeout),
+ ngx_http_memcached_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
ngx_null_command
@@ -178,8 +182,6 @@ ngx_http_memcached_handler(ngx_http_request_t *r)
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = mlcf->peers;
- u->peer.tries = mlcf->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -511,13 +513,8 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
- /* "fastcgi_cyclic_temp_file" is disabled */
- conf->upstream.cyclic_temp_file = 0;
-
/* the hardcoded values */
+ conf->upstream.cyclic_temp_file = 0;
conf->upstream.buffering = 0;
conf->upstream.ignore_client_abort = 0;
conf->upstream.send_lowat = 0;
@@ -540,8 +537,6 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_memcached_loc_conf_t *prev = parent;
ngx_http_memcached_loc_conf_t *conf = child;
- ngx_uint_t i;
-
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
@@ -566,20 +561,6 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->peers && conf->peers->number > 1) {
- for (i = 0; i < conf->peers->number; i++) {
- conf->peers->peer[i].weight = 1;
- conf->peers->peer[i].max_fails = conf->upstream.max_fails;
- conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout;
- }
- }
-
return NGX_CONF_OK;
}
@@ -602,16 +583,14 @@ ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
- u.uri_part = 1;
+ u.no_resolve = 1;
+ /* u.uri_part = 1; may be used as namespace */
- if (ngx_parse_url(cf, &u) != NGX_OK) {
- if (u.err) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "%s in \"%V\"", u.err, &u.url);
- }
+ lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (lcf->upstream.upstream == NULL) {
+ return NGX_CONF_ERROR;
}
- lcf->peers = u.peers;
lcf->upstream.schema.len = sizeof("memcached://") - 1;
lcf->upstream.schema.data = (u_char *) "memcached://";
@@ -627,3 +606,29 @@ ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"memcached_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"memcached_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index f17f0a752..2095f6a32 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -35,8 +35,6 @@ struct ngx_http_proxy_redirect_s {
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_http_upstream_srv_conf_t *upstream_peers;
-
ngx_array_t *flushes;
ngx_array_t *body_set_len;
ngx_array_t *body_set;
@@ -107,6 +105,11 @@ static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
+static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_conf_post_t ngx_http_proxy_lowat_post =
{ ngx_http_proxy_lowat_check };
@@ -297,16 +300,16 @@ static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_upstream_max_fails"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_num_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.max_fails),
+ ngx_http_proxy_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("proxy_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.fail_timeout),
+ ngx_http_proxy_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("proxy_pass_header"),
@@ -419,8 +422,6 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = plcf->upstream_peers->peers;
- u->peer.tries = plcf->upstream_peers->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -1498,9 +1499,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
@@ -1527,7 +1525,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
uintptr_t *code;
ngx_str_t *header;
ngx_uint_t i, j;
- ngx_peer_t *peer;
ngx_array_t hide_headers;
ngx_keyval_t *src, *s, *h;
ngx_hash_key_t *hk;
@@ -1660,24 +1657,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->upstream_peers) {
- peer = conf->upstream_peers->peers->peer;
- for (i = 0; i < conf->upstream_peers->peers->number; i++) {
- ngx_conf_init_uint_value(peer[i].weight, 1);
- peer[i].current_weight = peer[i].weight;
- ngx_conf_init_uint_value(peer[i].max_fails,
- conf->upstream.max_fails);
- ngx_conf_init_value(peer[i].fail_timeout,
- conf->upstream.fail_timeout);
- }
- }
-
ngx_conf_merge_path_value(conf->upstream.temp_path,
prev->upstream.temp_path,
NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
@@ -1834,8 +1813,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
peers:
- if (conf->upstream_peers == NULL) {
- conf->upstream_peers = prev->upstream_peers;
+ if (conf->upstream.upstream == NULL) {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->host_header = prev->host_header;
conf->port_text = prev->port_text;
@@ -2180,11 +2159,11 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
u.url.len = url->len - add;
u.url.data = url->data + add;
u.default_portn = port;
+ u.no_resolve = 1;
u.uri_part = 1;
- u.upstream = 1;
- plcf->upstream_peers = ngx_http_upstream_add(cf, &u);
- if (plcf->upstream_peers == NULL) {
+ plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (plcf->upstream.upstream == NULL) {
return NGX_CONF_ERROR;
}
@@ -2345,3 +2324,29 @@ ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
new file mode 100644
index 000000000..1de019e05
--- /dev/null
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -0,0 +1,228 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ /* the round robin data must be first */
+ ngx_http_upstream_rr_peer_data_t rrp;
+
+ ngx_uint_t hash;
+
+ /* AF_INET only */
+ u_char addr[3];
+
+ u_char tries;
+
+ ngx_event_get_peer_pt get_rr_peer;
+} ngx_http_upstream_ip_hash_peer_data_t;
+
+
+static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us);
+static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc,
+ void *data);
+static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+
+static ngx_command_t ngx_http_upstream_ip_hash_commands[] = {
+
+ { ngx_string("ip_hash"),
+ NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
+ ngx_http_upstream_ip_hash,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_upstream_ip_hash_module_ctx = {
+ NULL, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ NULL, /* create location configuration */
+ NULL /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_upstream_ip_hash_module = {
+ NGX_MODULE_V1,
+ &ngx_http_upstream_ip_hash_module_ctx, /* module context */
+ ngx_http_upstream_ip_hash_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+ngx_int_t
+ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
+{
+ if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ us->peer.init = ngx_http_upstream_init_ip_hash_peer;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ struct sockaddr_in *sin;
+ ngx_http_upstream_ip_hash_peer_data_t *iphp;
+
+ iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t));
+ if (iphp == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->upstream->peer.data = &iphp->rrp;
+
+ if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;
+
+ /* AF_INET only */
+ sin = (struct sockaddr_in *) r->connection->sockaddr;
+ iphp->addr[0] = (u_char) ((sin->sin_addr.s_addr >> 24) & 0xff);
+ iphp->addr[1] = (u_char) ((sin->sin_addr.s_addr >> 16) & 0xff);
+ iphp->addr[2] = (u_char) ((sin->sin_addr.s_addr >> 8) & 0xff);
+
+ iphp->hash = 89;
+ iphp->tries = 0;
+ iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_ip_hash_peer_data_t *iphp = data;
+
+ time_t now;
+ uintptr_t m;
+ ngx_uint_t i, n, p, hash;
+ ngx_http_upstream_rr_peer_t *peer;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, try: %ui", pc->tries);
+
+ /* TODO: cached */
+
+ if (iphp->tries > 20 || iphp->rrp.peers->number == 1) {
+ return iphp->get_rr_peer(pc, &iphp->rrp);
+ }
+
+ now = ngx_time();
+
+ pc->cached = 0;
+ pc->connection = NULL;
+
+ hash = iphp->hash;
+
+ for ( ;; ) {
+
+ for (i = 0; i < 3; i++) {
+ hash = (hash * 113 + iphp->addr[i]) % 6271;
+ }
+
+ p = hash % iphp->rrp.peers->number;
+
+ n = p / (8 * sizeof(uintptr_t));
+ m = 1 << p % (8 * sizeof(uintptr_t));
+
+ if (!(iphp->rrp.tried[n] & m)) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, hash: %ui %04XA", p, m);
+
+ peer = &iphp->rrp.peers->peer[p];
+
+ /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
+
+ if (!peer->down) {
+
+ if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
+ break;
+ }
+
+ if (now - peer->accessed > peer->fail_timeout) {
+ peer->fails = 0;
+ break;
+ }
+
+ } else {
+ iphp->rrp.tried[n] |= m;
+ }
+
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ pc->tries--;
+ }
+
+ if (++iphp->tries >= 20) {
+ return iphp->get_rr_peer(pc, &iphp->rrp);
+ }
+ }
+
+ pc->sockaddr = peer->sockaddr;
+ pc->socklen = peer->socklen;
+ pc->name = &peer->name;
+#if (NGX_SSL)
+ pc->ssl_session = peer->ssl_session;
+#endif
+
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ iphp->rrp.tried[n] |= m;
+ iphp->hash = hash;
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_upstream_srv_conf_t *uscf;
+
+ uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
+
+ uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
+
+ uscf->flags = NGX_HTTP_UPSTREAM_CREATE
+ |NGX_HTTP_UPSTREAM_MAX_FAILS
+ |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
+ |NGX_HTTP_UPSTREAM_DOWN;
+
+ return NGX_CONF_OK;
+}