Mercurial > hg > nginx
annotate src/http/modules/ngx_http_limit_zone_module.c @ 4515:8bb695c05870 stable-1.0
Merge of r4498:
Fix of rbtree lookup on hash collisions.
Previous code incorrectly assumed that nodes with identical keys are linked
together. This might not be true after tree rebalance.
Patch by Lanshun Zhou.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 05 Mar 2012 13:17:56 +0000 |
parents | 4919fb357a5d |
children | 50143b8fb95f |
rev | line source |
---|---|
980 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4450
4919fb357a5d
Merge of r4406, r4413: copyrights updated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4440
diff
changeset
|
4 * Copyright (C) Nginx, Inc. |
980 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
981 | 14 u_char color; |
15 u_char len; | |
980 | 16 u_short conn; |
17 u_char data[1]; | |
18 } ngx_http_limit_zone_node_t; | |
19 | |
20 | |
21 typedef struct { | |
22 ngx_shm_zone_t *shm_zone; | |
23 ngx_rbtree_node_t *node; | |
24 } ngx_http_limit_zone_cleanup_t; | |
25 | |
26 | |
27 typedef struct { | |
987 | 28 ngx_rbtree_t *rbtree; |
29 ngx_int_t index; | |
30 ngx_str_t var; | |
31 } ngx_http_limit_zone_ctx_t; | |
32 | |
33 | |
34 typedef struct { | |
980 | 35 ngx_shm_zone_t *shm_zone; |
36 ngx_uint_t conn; | |
3186 | 37 ngx_uint_t log_level; |
980 | 38 } ngx_http_limit_zone_conf_t; |
39 | |
40 | |
41 static void ngx_http_limit_zone_cleanup(void *data); | |
42 | |
43 static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf); | |
44 static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, | |
45 void *child); | |
46 static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, | |
47 void *conf); | |
48 static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, | |
49 void *conf); | |
50 static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf); | |
51 | |
52 | |
3186 | 53 static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { |
54 { ngx_string("info"), NGX_LOG_INFO }, | |
55 { ngx_string("notice"), NGX_LOG_NOTICE }, | |
56 { ngx_string("warn"), NGX_LOG_WARN }, | |
57 { ngx_string("error"), NGX_LOG_ERR }, | |
58 { ngx_null_string, 0 } | |
59 }; | |
60 | |
61 | |
980 | 62 static ngx_command_t ngx_http_limit_zone_commands[] = { |
63 | |
64 { ngx_string("limit_zone"), | |
987 | 65 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
980 | 66 ngx_http_limit_zone, |
67 0, | |
68 0, | |
69 NULL }, | |
70 | |
71 { ngx_string("limit_conn"), | |
987 | 72 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
980 | 73 ngx_http_limit_conn, |
74 NGX_HTTP_LOC_CONF_OFFSET, | |
75 0, | |
76 NULL }, | |
77 | |
3186 | 78 { ngx_string("limit_conn_log_level"), |
79 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
80 ngx_conf_set_enum_slot, | |
81 NGX_HTTP_LOC_CONF_OFFSET, | |
82 offsetof(ngx_http_limit_zone_conf_t, log_level), | |
83 &ngx_http_limit_conn_log_levels }, | |
84 | |
980 | 85 ngx_null_command |
86 }; | |
87 | |
88 | |
89 static ngx_http_module_t ngx_http_limit_zone_module_ctx = { | |
90 NULL, /* preconfiguration */ | |
91 ngx_http_limit_zone_init, /* postconfiguration */ | |
92 | |
93 NULL, /* create main configuration */ | |
94 NULL, /* init main configuration */ | |
95 | |
96 NULL, /* create server configuration */ | |
97 NULL, /* merge server configuration */ | |
98 | |
99 ngx_http_limit_zone_create_conf, /* create location configration */ | |
100 ngx_http_limit_zone_merge_conf /* merge location configration */ | |
101 }; | |
102 | |
103 | |
104 ngx_module_t ngx_http_limit_zone_module = { | |
105 NGX_MODULE_V1, | |
106 &ngx_http_limit_zone_module_ctx, /* module context */ | |
107 ngx_http_limit_zone_commands, /* module directives */ | |
108 NGX_HTTP_MODULE, /* module type */ | |
109 NULL, /* init master */ | |
110 NULL, /* init module */ | |
111 NULL, /* init process */ | |
112 NULL, /* init thread */ | |
113 NULL, /* exit thread */ | |
114 NULL, /* exit process */ | |
115 NULL, /* exit master */ | |
116 NGX_MODULE_V1_PADDING | |
117 }; | |
118 | |
119 | |
120 static ngx_int_t | |
121 ngx_http_limit_zone_handler(ngx_http_request_t *r) | |
122 { | |
123 size_t len, n; | |
124 uint32_t hash; | |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
125 ngx_int_t rc; |
980 | 126 ngx_slab_pool_t *shpool; |
127 ngx_rbtree_node_t *node, *sentinel; | |
128 ngx_pool_cleanup_t *cln; | |
129 ngx_http_variable_value_t *vv; | |
987 | 130 ngx_http_limit_zone_ctx_t *ctx; |
980 | 131 ngx_http_limit_zone_node_t *lz; |
132 ngx_http_limit_zone_conf_t *lzcf; | |
133 ngx_http_limit_zone_cleanup_t *lzcln; | |
134 | |
997
5900ec20604a
do not count connection for subrequest
Igor Sysoev <igor@sysoev.ru>
parents:
993
diff
changeset
|
135 if (r->main->limit_zone_set) { |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
136 return NGX_DECLINED; |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
137 } |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
138 |
980 | 139 lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module); |
140 | |
141 if (lzcf->shm_zone == NULL) { | |
142 return NGX_DECLINED; | |
143 } | |
144 | |
987 | 145 ctx = lzcf->shm_zone->data; |
146 | |
147 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
980 | 148 |
149 if (vv == NULL || vv->not_found) { | |
150 return NGX_DECLINED; | |
151 } | |
152 | |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
153 len = vv->len; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
154 |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
155 if (len == 0) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
156 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
157 } |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
158 |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
159 if (len > 255) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
160 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
161 "the value of the \"%V\" variable " |
1406
03341711f9a2
use %v for ngx_variable_value_t in ngx_sprintf(),
Igor Sysoev <igor@sysoev.ru>
parents:
1036
diff
changeset
|
162 "is more than 255 bytes: \"%v\"", |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
163 &ctx->var, vv); |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
164 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
165 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
166 |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
167 r->main->limit_zone_set = 1; |
980 | 168 |
169 hash = ngx_crc32_short(vv->data, len); | |
170 | |
171 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); | |
172 if (cln == NULL) { | |
173 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
174 } | |
175 | |
176 shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; | |
177 | |
178 ngx_shmtx_lock(&shpool->mutex); | |
179 | |
987 | 180 node = ctx->rbtree->root; |
181 sentinel = ctx->rbtree->sentinel; | |
980 | 182 |
183 while (node != sentinel) { | |
184 | |
185 if (hash < node->key) { | |
186 node = node->left; | |
187 continue; | |
188 } | |
189 | |
190 if (hash > node->key) { | |
191 node = node->right; | |
192 continue; | |
193 } | |
194 | |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
195 /* hash == node->key */ |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
196 |
4515 | 197 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 198 |
4515 | 199 rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len); |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
200 |
4515 | 201 if (rc == 0) { |
202 if ((ngx_uint_t) lz->conn < lzcf->conn) { | |
203 lz->conn++; | |
204 goto done; | |
980 | 205 } |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
206 |
4515 | 207 ngx_shmtx_unlock(&shpool->mutex); |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
208 |
4515 | 209 ngx_log_error(lzcf->log_level, r->connection->log, 0, |
210 "limiting connections by zone \"%V\"", | |
211 &lzcf->shm_zone->shm.name); | |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
212 |
4515 | 213 return NGX_HTTP_SERVICE_UNAVAILABLE; |
214 } | |
215 | |
216 node = (rc < 0) ? node->left : node->right; | |
980 | 217 } |
218 | |
981 | 219 n = offsetof(ngx_rbtree_node_t, color) |
980 | 220 + offsetof(ngx_http_limit_zone_node_t, data) |
221 + len; | |
222 | |
223 node = ngx_slab_alloc_locked(shpool, n); | |
224 if (node == NULL) { | |
225 ngx_shmtx_unlock(&shpool->mutex); | |
226 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
227 } | |
228 | |
981 | 229 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 230 |
231 node->key = hash; | |
981 | 232 lz->len = (u_char) len; |
980 | 233 lz->conn = 1; |
234 ngx_memcpy(lz->data, vv->data, len); | |
235 | |
987 | 236 ngx_rbtree_insert(ctx->rbtree, node); |
980 | 237 |
238 done: | |
239 | |
240 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
241 "limit zone: %08XD %d", node->key, lz->conn); | |
242 | |
243 ngx_shmtx_unlock(&shpool->mutex); | |
244 | |
245 cln->handler = ngx_http_limit_zone_cleanup; | |
246 lzcln = cln->data; | |
247 | |
248 lzcln->shm_zone = lzcf->shm_zone; | |
249 lzcln->node = node; | |
250 | |
251 return NGX_DECLINED; | |
252 } | |
253 | |
254 | |
255 static void | |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
256 ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp, |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
257 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
258 { |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
259 ngx_rbtree_node_t **p; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
260 ngx_http_limit_zone_node_t *lzn, *lznt; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
261 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
262 for ( ;; ) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
263 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
264 if (node->key < temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
265 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
266 p = &temp->left; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
267 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
268 } else if (node->key > temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
269 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
270 p = &temp->right; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
271 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
272 } else { /* node->key == temp->key */ |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
273 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
274 lzn = (ngx_http_limit_zone_node_t *) &node->color; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
275 lznt = (ngx_http_limit_zone_node_t *) &temp->color; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
276 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
277 p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
278 ? &temp->left : &temp->right; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
279 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
280 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
281 if (*p == sentinel) { |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
282 break; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
283 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
284 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
285 temp = *p; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
286 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
287 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
288 *p = node; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
289 node->parent = temp; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
290 node->left = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
291 node->right = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
292 ngx_rbt_red(node); |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
293 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
294 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
295 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
296 static void |
980 | 297 ngx_http_limit_zone_cleanup(void *data) |
298 { | |
299 ngx_http_limit_zone_cleanup_t *lzcln = data; | |
300 | |
301 ngx_slab_pool_t *shpool; | |
302 ngx_rbtree_node_t *node; | |
987 | 303 ngx_http_limit_zone_ctx_t *ctx; |
980 | 304 ngx_http_limit_zone_node_t *lz; |
305 | |
987 | 306 ctx = lzcln->shm_zone->data; |
980 | 307 shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; |
308 node = lzcln->node; | |
981 | 309 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 310 |
311 ngx_shmtx_lock(&shpool->mutex); | |
312 | |
313 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0, | |
314 "limit zone cleanup: %08XD %d", node->key, lz->conn); | |
315 | |
316 lz->conn--; | |
317 | |
318 if (lz->conn == 0) { | |
987 | 319 ngx_rbtree_delete(ctx->rbtree, node); |
980 | 320 ngx_slab_free_locked(shpool, node); |
321 } | |
322 | |
323 ngx_shmtx_unlock(&shpool->mutex); | |
324 } | |
325 | |
326 | |
327 static ngx_int_t | |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
328 ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data) |
980 | 329 { |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
330 ngx_http_limit_zone_ctx_t *octx = data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
331 |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
332 size_t len; |
987 | 333 ngx_slab_pool_t *shpool; |
334 ngx_rbtree_node_t *sentinel; | |
335 ngx_http_limit_zone_ctx_t *ctx; | |
980 | 336 |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
337 ctx = shm_zone->data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
338 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
339 if (octx) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
340 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
341 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
1001 | 342 "limit_zone \"%V\" uses the \"%V\" variable " |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
343 "while previously it used the \"%V\" variable", |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
344 &shm_zone->shm.name, &ctx->var, &octx->var); |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
345 return NGX_ERROR; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
346 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
347 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
348 ctx->rbtree = octx->rbtree; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
349 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
350 return NGX_OK; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
351 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
352 |
980 | 353 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
354 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
355 if (shm_zone->shm.exists) { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
356 ctx->rbtree = shpool->data; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
357 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
358 return NGX_OK; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
359 } |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
360 |
987 | 361 ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); |
362 if (ctx->rbtree == NULL) { | |
980 | 363 return NGX_ERROR; |
364 } | |
365 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
366 shpool->data = ctx->rbtree; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
367 |
980 | 368 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); |
369 if (sentinel == NULL) { | |
370 return NGX_ERROR; | |
371 } | |
372 | |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
373 ngx_rbtree_init(ctx->rbtree, sentinel, |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
374 ngx_http_limit_zone_rbtree_insert_value); |
980 | 375 |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
376 len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len; |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
377 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
378 shpool->log_ctx = ngx_slab_alloc(shpool, len); |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
379 if (shpool->log_ctx == NULL) { |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
380 return NGX_ERROR; |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
381 } |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
382 |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
383 ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", |
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
384 &shm_zone->shm.name); |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
385 |
980 | 386 return NGX_OK; |
387 } | |
388 | |
389 | |
390 static void * | |
391 ngx_http_limit_zone_create_conf(ngx_conf_t *cf) | |
392 { | |
393 ngx_http_limit_zone_conf_t *conf; | |
394 | |
395 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); | |
396 if (conf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2720
diff
changeset
|
397 return NULL; |
980 | 398 } |
399 | |
400 /* | |
401 * set by ngx_pcalloc(): | |
402 * | |
403 * conf->shm_zone = NULL; | |
404 * conf->conn = 0; | |
405 */ | |
406 | |
3186 | 407 conf->log_level = NGX_CONF_UNSET_UINT; |
408 | |
980 | 409 return conf; |
410 } | |
411 | |
412 | |
413 static char * | |
414 ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
415 { | |
416 ngx_http_limit_zone_conf_t *prev = parent; | |
417 ngx_http_limit_zone_conf_t *conf = child; | |
418 | |
419 if (conf->shm_zone == NULL) { | |
4440 | 420 conf->shm_zone = prev->shm_zone; |
421 conf->conn = prev->conn; | |
980 | 422 } |
423 | |
3186 | 424 ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); |
425 | |
980 | 426 return NGX_CONF_OK; |
427 } | |
428 | |
429 | |
430 static char * | |
431 ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
432 { | |
987 | 433 ssize_t n; |
434 ngx_str_t *value; | |
435 ngx_shm_zone_t *shm_zone; | |
436 ngx_http_limit_zone_ctx_t *ctx; | |
980 | 437 |
438 value = cf->args->elts; | |
439 | |
987 | 440 if (value[2].data[0] != '$') { |
441 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
442 "invalid variable name \"%V\"", &value[2]); | |
443 return NGX_CONF_ERROR; | |
444 } | |
445 | |
446 value[2].len--; | |
447 value[2].data++; | |
448 | |
449 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t)); | |
450 if (ctx == NULL) { | |
451 return NGX_CONF_ERROR; | |
452 } | |
453 | |
454 ctx->index = ngx_http_get_variable_index(cf, &value[2]); | |
455 if (ctx->index == NGX_ERROR) { | |
456 return NGX_CONF_ERROR; | |
457 } | |
458 | |
459 ctx->var = value[2]; | |
460 | |
461 n = ngx_parse_size(&value[3]); | |
980 | 462 |
463 if (n == NGX_ERROR) { | |
464 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
987 | 465 "invalid size of limit_zone \"%V\"", &value[3]); |
980 | 466 return NGX_CONF_ERROR; |
467 } | |
468 | |
469 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | |
470 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
471 "limit_zone \"%V\" is too small", &value[1]); | |
472 return NGX_CONF_ERROR; | |
473 } | |
474 | |
475 | |
476 shm_zone = ngx_shared_memory_add(cf, &value[1], n, | |
477 &ngx_http_limit_zone_module); | |
478 if (shm_zone == NULL) { | |
479 return NGX_CONF_ERROR; | |
480 } | |
481 | |
987 | 482 if (shm_zone->data) { |
483 ctx = shm_zone->data; | |
484 | |
485 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
486 "limit_zone \"%V\" is already bound to variable \"%V\"", | |
487 &value[1], &ctx->var); | |
488 return NGX_CONF_ERROR; | |
489 } | |
490 | |
980 | 491 shm_zone->init = ngx_http_limit_zone_init_zone; |
987 | 492 shm_zone->data = ctx; |
980 | 493 |
494 return NGX_CONF_OK; | |
495 } | |
496 | |
497 | |
498 static char * | |
499 ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
500 { | |
501 ngx_http_limit_zone_conf_t *lzcf = conf; | |
502 | |
503 ngx_int_t n; | |
504 ngx_str_t *value; | |
505 | |
2372 | 506 if (lzcf->shm_zone) { |
507 return "is duplicate"; | |
508 } | |
509 | |
980 | 510 value = cf->args->elts; |
511 | |
987 | 512 lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0, |
513 &ngx_http_limit_zone_module); | |
514 if (lzcf->shm_zone == NULL) { | |
980 | 515 return NGX_CONF_ERROR; |
516 } | |
517 | |
987 | 518 n = ngx_atoi(value[2].data, value[2].len); |
519 if (n <= 0) { | |
980 | 520 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
987 | 521 "invalid number of connections \"%V\"", &value[2]); |
980 | 522 return NGX_CONF_ERROR; |
523 } | |
524 | |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
525 if (n > 65535) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
526 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
527 "connection limit must be less 65536"); |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
528 return NGX_CONF_ERROR; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
529 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
530 |
980 | 531 lzcf->conn = n; |
532 | |
533 return NGX_CONF_OK; | |
534 } | |
535 | |
536 | |
537 static ngx_int_t | |
538 ngx_http_limit_zone_init(ngx_conf_t *cf) | |
539 { | |
540 ngx_http_handler_pt *h; | |
541 ngx_http_core_main_conf_t *cmcf; | |
542 | |
543 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
544 | |
545 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); | |
546 if (h == NULL) { | |
547 return NGX_ERROR; | |
548 } | |
549 | |
550 *h = ngx_http_limit_zone_handler; | |
551 | |
552 return NGX_OK; | |
553 } |