Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_limit_zone_module.c @ 987:14e68f471d02
new syntax
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Sun, 07 Jan 2007 18:52:34 +0000 |
parents | dd128232e6ba |
children | 1b9a4d92173f |
comparison
equal
deleted
inserted
replaced
986:68c85f283043 | 987:14e68f471d02 |
---|---|
22 ngx_rbtree_node_t *node; | 22 ngx_rbtree_node_t *node; |
23 } ngx_http_limit_zone_cleanup_t; | 23 } ngx_http_limit_zone_cleanup_t; |
24 | 24 |
25 | 25 |
26 typedef struct { | 26 typedef struct { |
27 ngx_rbtree_t *rbtree; | |
28 ngx_int_t index; | |
29 ngx_str_t var; | |
30 } ngx_http_limit_zone_ctx_t; | |
31 | |
32 | |
33 typedef struct { | |
27 ngx_shm_zone_t *shm_zone; | 34 ngx_shm_zone_t *shm_zone; |
28 ngx_int_t index; | |
29 ngx_uint_t conn; | 35 ngx_uint_t conn; |
30 } ngx_http_limit_zone_conf_t; | 36 } ngx_http_limit_zone_conf_t; |
31 | 37 |
32 | 38 |
33 static void ngx_http_limit_zone_cleanup(void *data); | 39 static void ngx_http_limit_zone_cleanup(void *data); |
43 | 49 |
44 | 50 |
45 static ngx_command_t ngx_http_limit_zone_commands[] = { | 51 static ngx_command_t ngx_http_limit_zone_commands[] = { |
46 | 52 |
47 { ngx_string("limit_zone"), | 53 { ngx_string("limit_zone"), |
48 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, | 54 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
49 ngx_http_limit_zone, | 55 ngx_http_limit_zone, |
50 0, | 56 0, |
51 0, | 57 0, |
52 NULL }, | 58 NULL }, |
53 | 59 |
54 { ngx_string("limit_conn"), | 60 { ngx_string("limit_conn"), |
55 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, | 61 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
56 ngx_http_limit_conn, | 62 ngx_http_limit_conn, |
57 NGX_HTTP_LOC_CONF_OFFSET, | 63 NGX_HTTP_LOC_CONF_OFFSET, |
58 0, | 64 0, |
59 NULL }, | 65 NULL }, |
60 | 66 |
96 static ngx_int_t | 102 static ngx_int_t |
97 ngx_http_limit_zone_handler(ngx_http_request_t *r) | 103 ngx_http_limit_zone_handler(ngx_http_request_t *r) |
98 { | 104 { |
99 size_t len, n; | 105 size_t len, n; |
100 uint32_t hash; | 106 uint32_t hash; |
101 ngx_rbtree_t *rbtree; | |
102 ngx_slab_pool_t *shpool; | 107 ngx_slab_pool_t *shpool; |
103 ngx_rbtree_node_t *node, *sentinel; | 108 ngx_rbtree_node_t *node, *sentinel; |
104 ngx_pool_cleanup_t *cln; | 109 ngx_pool_cleanup_t *cln; |
105 ngx_http_variable_value_t *vv; | 110 ngx_http_variable_value_t *vv; |
111 ngx_http_limit_zone_ctx_t *ctx; | |
106 ngx_http_limit_zone_node_t *lz; | 112 ngx_http_limit_zone_node_t *lz; |
107 ngx_http_limit_zone_conf_t *lzcf; | 113 ngx_http_limit_zone_conf_t *lzcf; |
108 ngx_http_limit_zone_cleanup_t *lzcln; | 114 ngx_http_limit_zone_cleanup_t *lzcln; |
109 | 115 |
110 if (r->limit_zone_set) { | 116 if (r->limit_zone_set) { |
115 | 121 |
116 if (lzcf->shm_zone == NULL) { | 122 if (lzcf->shm_zone == NULL) { |
117 return NGX_DECLINED; | 123 return NGX_DECLINED; |
118 } | 124 } |
119 | 125 |
120 vv = ngx_http_get_indexed_variable(r, lzcf->index); | 126 ctx = lzcf->shm_zone->data; |
127 | |
128 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
121 | 129 |
122 if (vv == NULL || vv->not_found) { | 130 if (vv == NULL || vv->not_found) { |
123 return NGX_DECLINED; | 131 return NGX_DECLINED; |
124 } | 132 } |
125 | 133 |
132 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); | 140 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); |
133 if (cln == NULL) { | 141 if (cln == NULL) { |
134 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 142 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
135 } | 143 } |
136 | 144 |
137 rbtree = lzcf->shm_zone->data; | |
138 shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; | 145 shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; |
139 | 146 |
140 ngx_shmtx_lock(&shpool->mutex); | 147 ngx_shmtx_lock(&shpool->mutex); |
141 | 148 |
142 node = rbtree->root; | 149 node = ctx->rbtree->root; |
143 sentinel = rbtree->sentinel; | 150 sentinel = ctx->rbtree->sentinel; |
144 | 151 |
145 while (node != sentinel) { | 152 while (node != sentinel) { |
146 | 153 |
147 if (hash < node->key) { | 154 if (hash < node->key) { |
148 node = node->left; | 155 node = node->left; |
187 node->key = hash; | 194 node->key = hash; |
188 lz->len = (u_char) len; | 195 lz->len = (u_char) len; |
189 lz->conn = 1; | 196 lz->conn = 1; |
190 ngx_memcpy(lz->data, vv->data, len); | 197 ngx_memcpy(lz->data, vv->data, len); |
191 | 198 |
192 ngx_rbtree_insert(rbtree, node); | 199 ngx_rbtree_insert(ctx->rbtree, node); |
193 | 200 |
194 done: | 201 done: |
195 | 202 |
196 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 203 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
197 "limit zone: %08XD %d", node->key, lz->conn); | 204 "limit zone: %08XD %d", node->key, lz->conn); |
211 static void | 218 static void |
212 ngx_http_limit_zone_cleanup(void *data) | 219 ngx_http_limit_zone_cleanup(void *data) |
213 { | 220 { |
214 ngx_http_limit_zone_cleanup_t *lzcln = data; | 221 ngx_http_limit_zone_cleanup_t *lzcln = data; |
215 | 222 |
216 ngx_rbtree_t *rbtree; | |
217 ngx_slab_pool_t *shpool; | 223 ngx_slab_pool_t *shpool; |
218 ngx_rbtree_node_t *node; | 224 ngx_rbtree_node_t *node; |
225 ngx_http_limit_zone_ctx_t *ctx; | |
219 ngx_http_limit_zone_node_t *lz; | 226 ngx_http_limit_zone_node_t *lz; |
220 | 227 |
221 rbtree = lzcln->shm_zone->data; | 228 ctx = lzcln->shm_zone->data; |
222 shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; | 229 shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; |
223 node = lzcln->node; | 230 node = lzcln->node; |
224 lz = (ngx_http_limit_zone_node_t *) &node->color; | 231 lz = (ngx_http_limit_zone_node_t *) &node->color; |
225 | 232 |
226 ngx_shmtx_lock(&shpool->mutex); | 233 ngx_shmtx_lock(&shpool->mutex); |
229 "limit zone cleanup: %08XD %d", node->key, lz->conn); | 236 "limit zone cleanup: %08XD %d", node->key, lz->conn); |
230 | 237 |
231 lz->conn--; | 238 lz->conn--; |
232 | 239 |
233 if (lz->conn == 0) { | 240 if (lz->conn == 0) { |
234 ngx_rbtree_delete(rbtree, node); | 241 ngx_rbtree_delete(ctx->rbtree, node); |
235 ngx_slab_free_locked(shpool, node); | 242 ngx_slab_free_locked(shpool, node); |
236 } | 243 } |
237 | 244 |
238 ngx_shmtx_unlock(&shpool->mutex); | 245 ngx_shmtx_unlock(&shpool->mutex); |
239 } | 246 } |
240 | 247 |
241 | 248 |
242 static ngx_int_t | 249 static ngx_int_t |
243 ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone) | 250 ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone) |
244 { | 251 { |
245 ngx_rbtree_t *rbtree; | 252 ngx_slab_pool_t *shpool; |
246 ngx_slab_pool_t *shpool; | 253 ngx_rbtree_node_t *sentinel; |
247 ngx_rbtree_node_t *sentinel; | 254 ngx_http_limit_zone_ctx_t *ctx; |
248 | 255 |
249 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | 256 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
250 | 257 ctx = shm_zone->data; |
251 rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); | 258 |
252 if (rbtree == NULL) { | 259 ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); |
260 if (ctx->rbtree == NULL) { | |
253 return NGX_ERROR; | 261 return NGX_ERROR; |
254 } | 262 } |
255 | 263 |
256 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); | 264 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); |
257 if (sentinel == NULL) { | 265 if (sentinel == NULL) { |
258 return NGX_ERROR; | 266 return NGX_ERROR; |
259 } | 267 } |
260 | 268 |
261 ngx_rbtree_sentinel_init(sentinel); | 269 ngx_rbtree_sentinel_init(sentinel); |
262 | 270 |
263 rbtree->root = sentinel; | 271 ctx->rbtree->root = sentinel; |
264 rbtree->sentinel = sentinel; | 272 ctx->rbtree->sentinel = sentinel; |
265 rbtree->insert = ngx_rbtree_insert_value; | 273 ctx->rbtree->insert = ngx_rbtree_insert_value; |
266 | |
267 shm_zone->data = rbtree; | |
268 | 274 |
269 return NGX_OK; | 275 return NGX_OK; |
270 } | 276 } |
271 | 277 |
272 | 278 |
282 | 288 |
283 /* | 289 /* |
284 * set by ngx_pcalloc(): | 290 * set by ngx_pcalloc(): |
285 * | 291 * |
286 * conf->shm_zone = NULL; | 292 * conf->shm_zone = NULL; |
287 * conf->index = 0; | |
288 * conf->conn = 0; | 293 * conf->conn = 0; |
289 */ | 294 */ |
290 | 295 |
291 return conf; | 296 return conf; |
292 } | 297 } |
307 | 312 |
308 | 313 |
309 static char * | 314 static char * |
310 ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 315 ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
311 { | 316 { |
312 ssize_t n; | 317 ssize_t n; |
313 ngx_str_t *value; | 318 ngx_str_t *value; |
314 ngx_shm_zone_t *shm_zone; | 319 ngx_shm_zone_t *shm_zone; |
320 ngx_http_limit_zone_ctx_t *ctx; | |
315 | 321 |
316 value = cf->args->elts; | 322 value = cf->args->elts; |
317 | 323 |
318 n = ngx_parse_size(&value[2]); | 324 if (value[2].data[0] != '$') { |
325 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
326 "invalid variable name \"%V\"", &value[2]); | |
327 return NGX_CONF_ERROR; | |
328 } | |
329 | |
330 value[2].len--; | |
331 value[2].data++; | |
332 | |
333 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t)); | |
334 if (ctx == NULL) { | |
335 return NGX_CONF_ERROR; | |
336 } | |
337 | |
338 ctx->index = ngx_http_get_variable_index(cf, &value[2]); | |
339 if (ctx->index == NGX_ERROR) { | |
340 return NGX_CONF_ERROR; | |
341 } | |
342 | |
343 ctx->var = value[2]; | |
344 | |
345 n = ngx_parse_size(&value[3]); | |
319 | 346 |
320 if (n == NGX_ERROR) { | 347 if (n == NGX_ERROR) { |
321 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 348 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
322 "invalid size of limit_zone \"%V\"", &value[2]); | 349 "invalid size of limit_zone \"%V\"", &value[3]); |
323 return NGX_CONF_ERROR; | 350 return NGX_CONF_ERROR; |
324 } | 351 } |
325 | 352 |
326 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | 353 if (n < (ngx_int_t) (8 * ngx_pagesize)) { |
327 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 354 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
334 &ngx_http_limit_zone_module); | 361 &ngx_http_limit_zone_module); |
335 if (shm_zone == NULL) { | 362 if (shm_zone == NULL) { |
336 return NGX_CONF_ERROR; | 363 return NGX_CONF_ERROR; |
337 } | 364 } |
338 | 365 |
366 if (shm_zone->data) { | |
367 ctx = shm_zone->data; | |
368 | |
369 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
370 "limit_zone \"%V\" is already bound to variable \"%V\"", | |
371 &value[1], &ctx->var); | |
372 return NGX_CONF_ERROR; | |
373 } | |
374 | |
339 shm_zone->init = ngx_http_limit_zone_init_zone; | 375 shm_zone->init = ngx_http_limit_zone_init_zone; |
376 shm_zone->data = ctx; | |
340 | 377 |
341 return NGX_CONF_OK; | 378 return NGX_CONF_OK; |
342 } | 379 } |
343 | 380 |
344 | 381 |
350 ngx_int_t n; | 387 ngx_int_t n; |
351 ngx_str_t *value; | 388 ngx_str_t *value; |
352 | 389 |
353 value = cf->args->elts; | 390 value = cf->args->elts; |
354 | 391 |
355 n = ngx_atoi(value[1].data, value[1].len); | 392 lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0, |
393 &ngx_http_limit_zone_module); | |
394 if (lzcf->shm_zone == NULL) { | |
395 return NGX_CONF_ERROR; | |
396 } | |
397 | |
398 n = ngx_atoi(value[2].data, value[2].len); | |
356 if (n <= 0) { | 399 if (n <= 0) { |
357 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 400 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
358 "invalid number of connections"); | 401 "invalid number of connections \"%V\"", &value[2]); |
359 return NGX_CONF_ERROR; | |
360 } | |
361 | |
362 if (value[2].data[0] != '$') { | |
363 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
364 "invalid variable name \"%V\"", &value[2]); | |
365 return NGX_CONF_ERROR; | |
366 } | |
367 | |
368 value[2].len--; | |
369 value[2].data++; | |
370 | |
371 lzcf->index = ngx_http_get_variable_index(cf, &value[2]); | |
372 if (lzcf->index == NGX_ERROR) { | |
373 return NGX_CONF_ERROR; | |
374 } | |
375 | |
376 lzcf->shm_zone = ngx_shared_memory_add(cf, &value[3], 0, | |
377 &ngx_http_limit_zone_module); | |
378 if (lzcf->shm_zone == NULL) { | |
379 return NGX_CONF_ERROR; | 402 return NGX_CONF_ERROR; |
380 } | 403 } |
381 | 404 |
382 lzcf->conn = n; | 405 lzcf->conn = n; |
383 | 406 |