1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevtypedef struct {
14e18a033bSKonstantin Ananyev    u_char                     color;
15e18a033bSKonstantin Ananyev    u_char                     len;
16e18a033bSKonstantin Ananyev    u_short                    conn;
17e18a033bSKonstantin Ananyev    u_char                     data[1];
18e18a033bSKonstantin Ananyev} ngx_http_limit_conn_node_t;
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyevtypedef struct {
22e18a033bSKonstantin Ananyev    ngx_shm_zone_t            *shm_zone;
23e18a033bSKonstantin Ananyev    ngx_rbtree_node_t         *node;
24e18a033bSKonstantin Ananyev} ngx_http_limit_conn_cleanup_t;
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyevtypedef struct {
28e18a033bSKonstantin Ananyev    ngx_rbtree_t              *rbtree;
29e18a033bSKonstantin Ananyev    ngx_http_complex_value_t   key;
30e18a033bSKonstantin Ananyev} ngx_http_limit_conn_ctx_t;
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyevtypedef struct {
34e18a033bSKonstantin Ananyev    ngx_shm_zone_t            *shm_zone;
35e18a033bSKonstantin Ananyev    ngx_uint_t                 conn;
36e18a033bSKonstantin Ananyev} ngx_http_limit_conn_limit_t;
37e18a033bSKonstantin Ananyev
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyevtypedef struct {
40e18a033bSKonstantin Ananyev    ngx_array_t                limits;
41e18a033bSKonstantin Ananyev    ngx_uint_t                 log_level;
42e18a033bSKonstantin Ananyev    ngx_uint_t                 status_code;
43e18a033bSKonstantin Ananyev} ngx_http_limit_conn_conf_t;
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyev
46e18a033bSKonstantin Ananyevstatic ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
47e18a033bSKonstantin Ananyev    ngx_str_t *key, uint32_t hash);
48e18a033bSKonstantin Ananyevstatic void ngx_http_limit_conn_cleanup(void *data);
49e18a033bSKonstantin Ananyevstatic ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyevstatic void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
52e18a033bSKonstantin Ananyevstatic char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
53e18a033bSKonstantin Ananyev    void *child);
54e18a033bSKonstantin Ananyevstatic char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
55e18a033bSKonstantin Ananyev    void *conf);
56e18a033bSKonstantin Ananyevstatic char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
57e18a033bSKonstantin Ananyev    void *conf);
58e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
59e18a033bSKonstantin Ananyev
60e18a033bSKonstantin Ananyev
61e18a033bSKonstantin Ananyevstatic ngx_conf_enum_t  ngx_http_limit_conn_log_levels[] = {
62e18a033bSKonstantin Ananyev    { ngx_string("info"), NGX_LOG_INFO },
63e18a033bSKonstantin Ananyev    { ngx_string("notice"), NGX_LOG_NOTICE },
64e18a033bSKonstantin Ananyev    { ngx_string("warn"), NGX_LOG_WARN },
65e18a033bSKonstantin Ananyev    { ngx_string("error"), NGX_LOG_ERR },
66e18a033bSKonstantin Ananyev    { ngx_null_string, 0 }
67e18a033bSKonstantin Ananyev};
68e18a033bSKonstantin Ananyev
69e18a033bSKonstantin Ananyev
70e18a033bSKonstantin Ananyevstatic ngx_conf_num_bounds_t  ngx_http_limit_conn_status_bounds = {
71e18a033bSKonstantin Ananyev    ngx_conf_check_num_bounds, 400, 599
72e18a033bSKonstantin Ananyev};
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_limit_conn_commands[] = {
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyev    { ngx_string("limit_conn_zone"),
78e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
79e18a033bSKonstantin Ananyev      ngx_http_limit_conn_zone,
80e18a033bSKonstantin Ananyev      0,
81e18a033bSKonstantin Ananyev      0,
82e18a033bSKonstantin Ananyev      NULL },
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    { ngx_string("limit_conn"),
85e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
86e18a033bSKonstantin Ananyev      ngx_http_limit_conn,
87e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
88e18a033bSKonstantin Ananyev      0,
89e18a033bSKonstantin Ananyev      NULL },
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev    { ngx_string("limit_conn_log_level"),
92e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
93e18a033bSKonstantin Ananyev      ngx_conf_set_enum_slot,
94e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
95e18a033bSKonstantin Ananyev      offsetof(ngx_http_limit_conn_conf_t, log_level),
96e18a033bSKonstantin Ananyev      &ngx_http_limit_conn_log_levels },
97e18a033bSKonstantin Ananyev
98e18a033bSKonstantin Ananyev    { ngx_string("limit_conn_status"),
99e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
100e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
101e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
102e18a033bSKonstantin Ananyev      offsetof(ngx_http_limit_conn_conf_t, status_code),
103e18a033bSKonstantin Ananyev      &ngx_http_limit_conn_status_bounds },
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev      ngx_null_command
106e18a033bSKonstantin Ananyev};
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_limit_conn_module_ctx = {
110e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
111e18a033bSKonstantin Ananyev    ngx_http_limit_conn_init,              /* postconfiguration */
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
114e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
115e18a033bSKonstantin Ananyev
116e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
117e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
118e18a033bSKonstantin Ananyev
119e18a033bSKonstantin Ananyev    ngx_http_limit_conn_create_conf,       /* create location configuration */
120e18a033bSKonstantin Ananyev    ngx_http_limit_conn_merge_conf         /* merge location configuration */
121e18a033bSKonstantin Ananyev};
122e18a033bSKonstantin Ananyev
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyevngx_module_t  ngx_http_limit_conn_module = {
125e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
126e18a033bSKonstantin Ananyev    &ngx_http_limit_conn_module_ctx,       /* module context */
127e18a033bSKonstantin Ananyev    ngx_http_limit_conn_commands,          /* module directives */
128e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
129e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
130e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
131e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
132e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
133e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
134e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
135e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
136e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
137e18a033bSKonstantin Ananyev};
138e18a033bSKonstantin Ananyev
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyevstatic ngx_int_t
141e18a033bSKonstantin Ananyevngx_http_limit_conn_handler(ngx_http_request_t *r)
142e18a033bSKonstantin Ananyev{
143e18a033bSKonstantin Ananyev    size_t                          n;
144e18a033bSKonstantin Ananyev    uint32_t                        hash;
145e18a033bSKonstantin Ananyev    ngx_str_t                       key;
146e18a033bSKonstantin Ananyev    ngx_uint_t                      i;
147e18a033bSKonstantin Ananyev    ngx_slab_pool_t                *shpool;
148e18a033bSKonstantin Ananyev    ngx_rbtree_node_t              *node;
149e18a033bSKonstantin Ananyev    ngx_pool_cleanup_t             *cln;
150e18a033bSKonstantin Ananyev    ngx_http_limit_conn_ctx_t      *ctx;
151e18a033bSKonstantin Ananyev    ngx_http_limit_conn_node_t     *lc;
152e18a033bSKonstantin Ananyev    ngx_http_limit_conn_conf_t     *lccf;
153e18a033bSKonstantin Ananyev    ngx_http_limit_conn_limit_t    *limits;
154e18a033bSKonstantin Ananyev    ngx_http_limit_conn_cleanup_t  *lccln;
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev    if (r->main->limit_conn_set) {
157e18a033bSKonstantin Ananyev        return NGX_DECLINED;
158e18a033bSKonstantin Ananyev    }
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
161e18a033bSKonstantin Ananyev    limits = lccf->limits.elts;
162e18a033bSKonstantin Ananyev
163e18a033bSKonstantin Ananyev    for (i = 0; i < lccf->limits.nelts; i++) {
164e18a033bSKonstantin Ananyev        ctx = limits[i].shm_zone->data;
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev        if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
167e18a033bSKonstantin Ananyev            return NGX_HTTP_INTERNAL_SERVER_ERROR;
168e18a033bSKonstantin Ananyev        }
169e18a033bSKonstantin Ananyev
170e18a033bSKonstantin Ananyev        if (key.len == 0) {
171e18a033bSKonstantin Ananyev            continue;
172e18a033bSKonstantin Ananyev        }
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev        if (key.len > 255) {
175e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
176e18a033bSKonstantin Ananyev                          "the value of the \"%V\" key "
177e18a033bSKonstantin Ananyev                          "is more than 255 bytes: \"%V\"",
178e18a033bSKonstantin Ananyev                          &ctx->key.value, &key);
179e18a033bSKonstantin Ananyev            continue;
180e18a033bSKonstantin Ananyev        }
181e18a033bSKonstantin Ananyev
182e18a033bSKonstantin Ananyev        r->main->limit_conn_set = 1;
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyev        hash = ngx_crc32_short(key.data, key.len);
185e18a033bSKonstantin Ananyev
186e18a033bSKonstantin Ananyev        shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyev        ngx_shmtx_lock(&shpool->mutex);
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev        node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev        if (node == NULL) {
193e18a033bSKonstantin Ananyev
194e18a033bSKonstantin Ananyev            n = offsetof(ngx_rbtree_node_t, color)
195e18a033bSKonstantin Ananyev                + offsetof(ngx_http_limit_conn_node_t, data)
196e18a033bSKonstantin Ananyev                + key.len;
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev            node = ngx_slab_alloc_locked(shpool, n);
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev            if (node == NULL) {
201e18a033bSKonstantin Ananyev                ngx_shmtx_unlock(&shpool->mutex);
202e18a033bSKonstantin Ananyev                ngx_http_limit_conn_cleanup_all(r->pool);
203e18a033bSKonstantin Ananyev                return lccf->status_code;
204e18a033bSKonstantin Ananyev            }
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev            lc = (ngx_http_limit_conn_node_t *) &node->color;
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev            node->key = hash;
209e18a033bSKonstantin Ananyev            lc->len = (u_char) key.len;
210e18a033bSKonstantin Ananyev            lc->conn = 1;
211e18a033bSKonstantin Ananyev            ngx_memcpy(lc->data, key.data, key.len);
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev            ngx_rbtree_insert(ctx->rbtree, node);
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyev        } else {
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev            lc = (ngx_http_limit_conn_node_t *) &node->color;
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev            if ((ngx_uint_t) lc->conn >= limits[i].conn) {
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev                ngx_shmtx_unlock(&shpool->mutex);
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev                ngx_log_error(lccf->log_level, r->connection->log, 0,
224e18a033bSKonstantin Ananyev                              "limiting connections by zone \"%V\"",
225e18a033bSKonstantin Ananyev                              &limits[i].shm_zone->shm.name);
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev                ngx_http_limit_conn_cleanup_all(r->pool);
228e18a033bSKonstantin Ananyev                return lccf->status_code;
229e18a033bSKonstantin Ananyev            }
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev            lc->conn++;
232e18a033bSKonstantin Ananyev        }
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyev        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
235e18a033bSKonstantin Ananyev                       "limit conn: %08Xi %d", node->key, lc->conn);
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev        ngx_shmtx_unlock(&shpool->mutex);
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev        cln = ngx_pool_cleanup_add(r->pool,
240e18a033bSKonstantin Ananyev                                   sizeof(ngx_http_limit_conn_cleanup_t));
241e18a033bSKonstantin Ananyev        if (cln == NULL) {
242e18a033bSKonstantin Ananyev            return NGX_HTTP_INTERNAL_SERVER_ERROR;
243e18a033bSKonstantin Ananyev        }
244e18a033bSKonstantin Ananyev
245e18a033bSKonstantin Ananyev        cln->handler = ngx_http_limit_conn_cleanup;
246e18a033bSKonstantin Ananyev        lccln = cln->data;
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev        lccln->shm_zone = limits[i].shm_zone;
249e18a033bSKonstantin Ananyev        lccln->node = node;
250e18a033bSKonstantin Ananyev    }
251e18a033bSKonstantin Ananyev
252e18a033bSKonstantin Ananyev    return NGX_DECLINED;
253e18a033bSKonstantin Ananyev}
254e18a033bSKonstantin Ananyev
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyevstatic void
257e18a033bSKonstantin Ananyevngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
258e18a033bSKonstantin Ananyev    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
259e18a033bSKonstantin Ananyev{
260e18a033bSKonstantin Ananyev    ngx_rbtree_node_t           **p;
261e18a033bSKonstantin Ananyev    ngx_http_limit_conn_node_t   *lcn, *lcnt;
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyev    for ( ;; ) {
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev        if (node->key < temp->key) {
266e18a033bSKonstantin Ananyev
267e18a033bSKonstantin Ananyev            p = &temp->left;
268e18a033bSKonstantin Ananyev
269e18a033bSKonstantin Ananyev        } else if (node->key > temp->key) {
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyev            p = &temp->right;
272e18a033bSKonstantin Ananyev
273e18a033bSKonstantin Ananyev        } else { /* node->key == temp->key */
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev            lcn = (ngx_http_limit_conn_node_t *) &node->color;
276e18a033bSKonstantin Ananyev            lcnt = (ngx_http_limit_conn_node_t *) &temp->color;
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev            p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0)
279e18a033bSKonstantin Ananyev                ? &temp->left : &temp->right;
280e18a033bSKonstantin Ananyev        }
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev        if (*p == sentinel) {
283e18a033bSKonstantin Ananyev            break;
284e18a033bSKonstantin Ananyev        }
285e18a033bSKonstantin Ananyev
286e18a033bSKonstantin Ananyev        temp = *p;
287e18a033bSKonstantin Ananyev    }
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev    *p = node;
290e18a033bSKonstantin Ananyev    node->parent = temp;
291e18a033bSKonstantin Ananyev    node->left = sentinel;
292e18a033bSKonstantin Ananyev    node->right = sentinel;
293e18a033bSKonstantin Ananyev    ngx_rbt_red(node);
294e18a033bSKonstantin Ananyev}
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev
297e18a033bSKonstantin Ananyevstatic ngx_rbtree_node_t *
298e18a033bSKonstantin Ananyevngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash)
299e18a033bSKonstantin Ananyev{
300e18a033bSKonstantin Ananyev    ngx_int_t                    rc;
301e18a033bSKonstantin Ananyev    ngx_rbtree_node_t           *node, *sentinel;
302e18a033bSKonstantin Ananyev    ngx_http_limit_conn_node_t  *lcn;
303e18a033bSKonstantin Ananyev
304e18a033bSKonstantin Ananyev    node = rbtree->root;
305e18a033bSKonstantin Ananyev    sentinel = rbtree->sentinel;
306e18a033bSKonstantin Ananyev
307e18a033bSKonstantin Ananyev    while (node != sentinel) {
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev        if (hash < node->key) {
310e18a033bSKonstantin Ananyev            node = node->left;
311e18a033bSKonstantin Ananyev            continue;
312e18a033bSKonstantin Ananyev        }
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev        if (hash > node->key) {
315e18a033bSKonstantin Ananyev            node = node->right;
316e18a033bSKonstantin Ananyev            continue;
317e18a033bSKonstantin Ananyev        }
318e18a033bSKonstantin Ananyev
319e18a033bSKonstantin Ananyev        /* hash == node->key */
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev        lcn = (ngx_http_limit_conn_node_t *) &node->color;
322e18a033bSKonstantin Ananyev
323e18a033bSKonstantin Ananyev        rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len);
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev        if (rc == 0) {
326e18a033bSKonstantin Ananyev            return node;
327e18a033bSKonstantin Ananyev        }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev        node = (rc < 0) ? node->left : node->right;
330e18a033bSKonstantin Ananyev    }
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev    return NULL;
333e18a033bSKonstantin Ananyev}
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyevstatic void
337e18a033bSKonstantin Ananyevngx_http_limit_conn_cleanup(void *data)
338e18a033bSKonstantin Ananyev{
339e18a033bSKonstantin Ananyev    ngx_http_limit_conn_cleanup_t  *lccln = data;
340e18a033bSKonstantin Ananyev
341e18a033bSKonstantin Ananyev    ngx_slab_pool_t             *shpool;
342e18a033bSKonstantin Ananyev    ngx_rbtree_node_t           *node;
343e18a033bSKonstantin Ananyev    ngx_http_limit_conn_ctx_t   *ctx;
344e18a033bSKonstantin Ananyev    ngx_http_limit_conn_node_t  *lc;
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev    ctx = lccln->shm_zone->data;
347e18a033bSKonstantin Ananyev    shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
348e18a033bSKonstantin Ananyev    node = lccln->node;
349e18a033bSKonstantin Ananyev    lc = (ngx_http_limit_conn_node_t *) &node->color;
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev    ngx_shmtx_lock(&shpool->mutex);
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
354e18a033bSKonstantin Ananyev                   "limit conn cleanup: %08Xi %d", node->key, lc->conn);
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev    lc->conn--;
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev    if (lc->conn == 0) {
359e18a033bSKonstantin Ananyev        ngx_rbtree_delete(ctx->rbtree, node);
360e18a033bSKonstantin Ananyev        ngx_slab_free_locked(shpool, node);
361e18a033bSKonstantin Ananyev    }
362e18a033bSKonstantin Ananyev
363e18a033bSKonstantin Ananyev    ngx_shmtx_unlock(&shpool->mutex);
364e18a033bSKonstantin Ananyev}
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev
367e18a033bSKonstantin Ananyevstatic ngx_inline void
368e18a033bSKonstantin Ananyevngx_http_limit_conn_cleanup_all(ngx_pool_t *pool)
369e18a033bSKonstantin Ananyev{
370e18a033bSKonstantin Ananyev    ngx_pool_cleanup_t  *cln;
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    cln = pool->cleanup;
373e18a033bSKonstantin Ananyev
374e18a033bSKonstantin Ananyev    while (cln && cln->handler == ngx_http_limit_conn_cleanup) {
375e18a033bSKonstantin Ananyev        ngx_http_limit_conn_cleanup(cln->data);
376e18a033bSKonstantin Ananyev        cln = cln->next;
377e18a033bSKonstantin Ananyev    }
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev    pool->cleanup = cln;
380e18a033bSKonstantin Ananyev}
381e18a033bSKonstantin Ananyev
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyevstatic ngx_int_t
384e18a033bSKonstantin Ananyevngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
385e18a033bSKonstantin Ananyev{
386e18a033bSKonstantin Ananyev    ngx_http_limit_conn_ctx_t  *octx = data;
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyev    size_t                      len;
389e18a033bSKonstantin Ananyev    ngx_slab_pool_t            *shpool;
390e18a033bSKonstantin Ananyev    ngx_rbtree_node_t          *sentinel;
391e18a033bSKonstantin Ananyev    ngx_http_limit_conn_ctx_t  *ctx;
392e18a033bSKonstantin Ananyev
393e18a033bSKonstantin Ananyev    ctx = shm_zone->data;
394e18a033bSKonstantin Ananyev
395e18a033bSKonstantin Ananyev    if (octx) {
396e18a033bSKonstantin Ananyev        if (ctx->key.value.len != octx->key.value.len
397e18a033bSKonstantin Ananyev            || ngx_strncmp(ctx->key.value.data, octx->key.value.data,
398e18a033bSKonstantin Ananyev                           ctx->key.value.len)
399e18a033bSKonstantin Ananyev               != 0)
400e18a033bSKonstantin Ananyev        {
401e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
402e18a033bSKonstantin Ananyev                          "limit_conn_zone \"%V\" uses the \"%V\" key "
403e18a033bSKonstantin Ananyev                          "while previously it used the \"%V\" key",
404e18a033bSKonstantin Ananyev                          &shm_zone->shm.name, &ctx->key.value,
405e18a033bSKonstantin Ananyev                          &octx->key.value);
406e18a033bSKonstantin Ananyev            return NGX_ERROR;
407e18a033bSKonstantin Ananyev        }
408e18a033bSKonstantin Ananyev
409e18a033bSKonstantin Ananyev        ctx->rbtree = octx->rbtree;
410e18a033bSKonstantin Ananyev
411e18a033bSKonstantin Ananyev        return NGX_OK;
412e18a033bSKonstantin Ananyev    }
413e18a033bSKonstantin Ananyev
414e18a033bSKonstantin Ananyev    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
415