xref: /unit/src/nxt_router.c (revision 115)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9*115Sigor@sysoev.ru #include <nxt_conf.h>
1088Smax.romanov@nginx.com #include <nxt_application.h>
1120Sigor@sysoev.ru 
1220Sigor@sysoev.ru 
13*115Sigor@sysoev.ru typedef struct {
14*115Sigor@sysoev.ru     nxt_str_t  application_type;
15*115Sigor@sysoev.ru     uint32_t   application_workers;
16*115Sigor@sysoev.ru } nxt_router_listener_conf_t;
17*115Sigor@sysoev.ru 
18*115Sigor@sysoev.ru 
1953Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task,
2053Sigor@sysoev.ru     nxt_router_t *router);
2153Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
2253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
2353Sigor@sysoev.ru 
24*115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
25*115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
2653Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
2753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
2865Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
2965Sigor@sysoev.ru     nxt_sockaddr_t *sa);
3053Sigor@sysoev.ru 
3153Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
3253Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
3353Sigor@sysoev.ru     const nxt_event_interface_t *interface);
34*115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
35*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
36*115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
37*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
38*115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
39*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
40*115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
41*115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_mp_t *mp,
4265Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
4365Sigor@sysoev.ru     nxt_work_handler_t handler);
44*115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_engine_conf_t *recf,
45*115Sigor@sysoev.ru     nxt_queue_t *sockets);
4653Sigor@sysoev.ru 
4753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
4853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
4953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
5053Sigor@sysoev.ru     nxt_event_engine_t *engine);
5153Sigor@sysoev.ru 
5253Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
5353Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
5453Sigor@sysoev.ru 
5553Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
5653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
5753Sigor@sysoev.ru     void *data);
5853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
5953Sigor@sysoev.ru     void *data);
6053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
6153Sigor@sysoev.ru     void *data);
6253Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
6353Sigor@sysoev.ru     void *data);
6453Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
6553Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
6653Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
6753Sigor@sysoev.ru     void *data);
6853Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
6953Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
7053Sigor@sysoev.ru 
7153Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
7253Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
7353Sigor@sysoev.ru     void *data);
7488Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
7588Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
7688Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
7753Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
7853Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
7953Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
8053Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
8162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
8220Sigor@sysoev.ru 
8320Sigor@sysoev.ru 
8420Sigor@sysoev.ru nxt_int_t
8520Sigor@sysoev.ru nxt_router_start(nxt_task_t *task, nxt_runtime_t *rt)
8620Sigor@sysoev.ru {
87*115Sigor@sysoev.ru     nxt_int_t     ret;
88*115Sigor@sysoev.ru     nxt_router_t  *router;
8953Sigor@sysoev.ru 
9088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
9188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
9288Smax.romanov@nginx.com         return ret;
9388Smax.romanov@nginx.com     }
9488Smax.romanov@nginx.com 
9553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
9653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
9753Sigor@sysoev.ru         return NXT_ERROR;
9853Sigor@sysoev.ru     }
9953Sigor@sysoev.ru 
10053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
10153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
10253Sigor@sysoev.ru 
103*115Sigor@sysoev.ru     return NXT_OK;
104*115Sigor@sysoev.ru }
105*115Sigor@sysoev.ru 
106*115Sigor@sysoev.ru 
107*115Sigor@sysoev.ru nxt_int_t
108*115Sigor@sysoev.ru nxt_router_new_conf(nxt_task_t *task, nxt_runtime_t *rt, nxt_router_t *router,
109*115Sigor@sysoev.ru     u_char *start, u_char *end)
110*115Sigor@sysoev.ru {
111*115Sigor@sysoev.ru     nxt_int_t                    ret;
112*115Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
113*115Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
11453Sigor@sysoev.ru 
11553Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task, router);
11653Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
11720Sigor@sysoev.ru         return NXT_ERROR;
11820Sigor@sysoev.ru     }
11920Sigor@sysoev.ru 
120*115Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
12153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
12253Sigor@sysoev.ru         return ret;
12353Sigor@sysoev.ru     }
12453Sigor@sysoev.ru 
12553Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
12653Sigor@sysoev.ru 
12753Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
12853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
12953Sigor@sysoev.ru         return ret;
13053Sigor@sysoev.ru     }
13153Sigor@sysoev.ru 
13253Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
13353Sigor@sysoev.ru 
13453Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
13553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
13653Sigor@sysoev.ru         return ret;
13753Sigor@sysoev.ru     }
13853Sigor@sysoev.ru 
13953Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
14053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
14153Sigor@sysoev.ru         return ret;
14253Sigor@sysoev.ru     }
14353Sigor@sysoev.ru 
14453Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
14553Sigor@sysoev.ru 
14653Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
14753Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
14853Sigor@sysoev.ru 
149*115Sigor@sysoev.ru //    nxt_mp_destroy(tmcf->mem_pool);
150*115Sigor@sysoev.ru 
15153Sigor@sysoev.ru     return NXT_OK;
15253Sigor@sysoev.ru }
15353Sigor@sysoev.ru 
15453Sigor@sysoev.ru 
15553Sigor@sysoev.ru static nxt_router_temp_conf_t *
15653Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task, nxt_router_t *router)
15753Sigor@sysoev.ru {
15865Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
15953Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
16053Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
16153Sigor@sysoev.ru 
16265Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
16353Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
16453Sigor@sysoev.ru         return NULL;
16553Sigor@sysoev.ru     }
16653Sigor@sysoev.ru 
16765Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
16853Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
16953Sigor@sysoev.ru         goto fail;
17053Sigor@sysoev.ru     }
17153Sigor@sysoev.ru 
17253Sigor@sysoev.ru     rtcf->mem_pool = mp;
17353Sigor@sysoev.ru     rtcf->router = router;
17453Sigor@sysoev.ru     rtcf->count = 1;
17553Sigor@sysoev.ru 
17665Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
17753Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
17853Sigor@sysoev.ru         goto fail;
17953Sigor@sysoev.ru     }
18053Sigor@sysoev.ru 
18165Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
18253Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
18353Sigor@sysoev.ru         goto temp_fail;
18453Sigor@sysoev.ru     }
18553Sigor@sysoev.ru 
18653Sigor@sysoev.ru     tmcf->mem_pool = tmp;
18753Sigor@sysoev.ru     tmcf->conf = rtcf;
18853Sigor@sysoev.ru 
18953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
19053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
19153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
19253Sigor@sysoev.ru         goto temp_fail;
19353Sigor@sysoev.ru     }
19453Sigor@sysoev.ru 
19553Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
19653Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
19753Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
19853Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
19953Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
20053Sigor@sysoev.ru 
20153Sigor@sysoev.ru     return tmcf;
20253Sigor@sysoev.ru 
20353Sigor@sysoev.ru temp_fail:
20453Sigor@sysoev.ru 
20565Sigor@sysoev.ru     nxt_mp_destroy(tmp);
20653Sigor@sysoev.ru 
20753Sigor@sysoev.ru fail:
20853Sigor@sysoev.ru 
20965Sigor@sysoev.ru     nxt_mp_destroy(mp);
21053Sigor@sysoev.ru 
21153Sigor@sysoev.ru     return NULL;
21253Sigor@sysoev.ru }
21353Sigor@sysoev.ru 
21453Sigor@sysoev.ru 
215*115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
216*115Sigor@sysoev.ru     {
217*115Sigor@sysoev.ru         nxt_string("threads"),
218*115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
219*115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
220*115Sigor@sysoev.ru     },
221*115Sigor@sysoev.ru 
222*115Sigor@sysoev.ru     {
223*115Sigor@sysoev.ru         nxt_null_string, 0, 0,
224*115Sigor@sysoev.ru     },
225*115Sigor@sysoev.ru };
226*115Sigor@sysoev.ru 
227*115Sigor@sysoev.ru 
228*115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
229*115Sigor@sysoev.ru     {
230*115Sigor@sysoev.ru         nxt_string("_application_type"),
231*115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
232*115Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application_type),
233*115Sigor@sysoev.ru     },
234*115Sigor@sysoev.ru 
235*115Sigor@sysoev.ru     {
236*115Sigor@sysoev.ru         nxt_string("_application_workers"),
237*115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
238*115Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application_workers),
239*115Sigor@sysoev.ru     },
240*115Sigor@sysoev.ru 
241*115Sigor@sysoev.ru     {
242*115Sigor@sysoev.ru         nxt_null_string, 0, 0,
243*115Sigor@sysoev.ru     },
244*115Sigor@sysoev.ru };
245*115Sigor@sysoev.ru 
246*115Sigor@sysoev.ru 
247*115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
248*115Sigor@sysoev.ru     {
249*115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
250*115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
251*115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
252*115Sigor@sysoev.ru     },
253*115Sigor@sysoev.ru 
254*115Sigor@sysoev.ru     {
255*115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
256*115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
257*115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
258*115Sigor@sysoev.ru     },
259*115Sigor@sysoev.ru 
260*115Sigor@sysoev.ru     {
261*115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
262*115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
263*115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
264*115Sigor@sysoev.ru     },
265*115Sigor@sysoev.ru 
266*115Sigor@sysoev.ru     {
267*115Sigor@sysoev.ru         nxt_null_string, 0, 0,
268*115Sigor@sysoev.ru     },
269*115Sigor@sysoev.ru };
270*115Sigor@sysoev.ru 
271*115Sigor@sysoev.ru 
27253Sigor@sysoev.ru static nxt_int_t
273*115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
274*115Sigor@sysoev.ru     u_char *start, u_char *end)
27553Sigor@sysoev.ru {
276*115Sigor@sysoev.ru     nxt_mp_t                    *mp;
277*115Sigor@sysoev.ru     uint32_t                    next;
278*115Sigor@sysoev.ru     nxt_int_t                   ret;
279*115Sigor@sysoev.ru     nxt_str_t                   name;
280*115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
281*115Sigor@sysoev.ru     nxt_conf_value_t            *conf, *listeners, *router, *http, *listener;
282*115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
283*115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
284*115Sigor@sysoev.ru 
285*115Sigor@sysoev.ru     static nxt_str_t  router_path = nxt_string("/router");
286*115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
287*115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
288*115Sigor@sysoev.ru 
289*115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
290*115Sigor@sysoev.ru     if (conf == NULL) {
291*115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
292*115Sigor@sysoev.ru         return NXT_ERROR;
293*115Sigor@sysoev.ru     }
294*115Sigor@sysoev.ru 
295*115Sigor@sysoev.ru     router = nxt_conf_get_path(conf, &router_path);
29653Sigor@sysoev.ru 
297*115Sigor@sysoev.ru     if (router == NULL) {
298*115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"/router\" block");
299*115Sigor@sysoev.ru         return NXT_ERROR;
300*115Sigor@sysoev.ru     }
301*115Sigor@sysoev.ru 
302*115Sigor@sysoev.ru     ret = nxt_conf_map_object(router, nxt_router_conf, tmcf->conf);
303*115Sigor@sysoev.ru     if (ret != NXT_OK) {
304*115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "router map error");
305*115Sigor@sysoev.ru         return NXT_ERROR;
306*115Sigor@sysoev.ru     }
307*115Sigor@sysoev.ru 
308*115Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
309*115Sigor@sysoev.ru 
310*115Sigor@sysoev.ru     if (http == NULL) {
311*115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"/http\" block");
312*115Sigor@sysoev.ru         return NXT_ERROR;
313*115Sigor@sysoev.ru     }
314*115Sigor@sysoev.ru 
315*115Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
316*115Sigor@sysoev.ru 
317*115Sigor@sysoev.ru     if (listeners == NULL) {
318*115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"/listeners\" block");
319*115Sigor@sysoev.ru         return NXT_ERROR;
320*115Sigor@sysoev.ru     }
32153Sigor@sysoev.ru 
32253Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
32353Sigor@sysoev.ru 
324*115Sigor@sysoev.ru     next = 0;
325*115Sigor@sysoev.ru 
326*115Sigor@sysoev.ru     for ( ;; ) {
327*115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
328*115Sigor@sysoev.ru         if (listener == NULL) {
329*115Sigor@sysoev.ru             break;
330*115Sigor@sysoev.ru         }
33153Sigor@sysoev.ru 
332*115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
333*115Sigor@sysoev.ru         if (sa == NULL) {
334*115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
335*115Sigor@sysoev.ru             return NXT_ERROR;
336*115Sigor@sysoev.ru         }
337*115Sigor@sysoev.ru 
338*115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
339*115Sigor@sysoev.ru 
340*115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
341*115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
34253Sigor@sysoev.ru 
343*115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
344*115Sigor@sysoev.ru         if (skcf == NULL) {
345*115Sigor@sysoev.ru             return NXT_ERROR;
346*115Sigor@sysoev.ru         }
34753Sigor@sysoev.ru 
348*115Sigor@sysoev.ru         ret = nxt_conf_map_object(listener, nxt_router_listener_conf, &lscf);
349*115Sigor@sysoev.ru         if (ret != NXT_OK) {
350*115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
351*115Sigor@sysoev.ru             return NXT_ERROR;
352*115Sigor@sysoev.ru         }
35353Sigor@sysoev.ru 
354*115Sigor@sysoev.ru         nxt_debug(task, "router type: %V", &lscf.application_type);
355*115Sigor@sysoev.ru         nxt_debug(task, "router workers: %D", lscf.application_workers);
35653Sigor@sysoev.ru 
357*115Sigor@sysoev.ru         ret = nxt_conf_map_object(http, nxt_router_http_conf, skcf);
358*115Sigor@sysoev.ru         if (ret != NXT_OK) {
359*115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "http map error");
360*115Sigor@sysoev.ru             return NXT_ERROR;
361*115Sigor@sysoev.ru         }
362*115Sigor@sysoev.ru 
363*115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
364*115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
365*115Sigor@sysoev.ru 
366*115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
367*115Sigor@sysoev.ru     }
36853Sigor@sysoev.ru 
36953Sigor@sysoev.ru     return NXT_OK;
37053Sigor@sysoev.ru }
37153Sigor@sysoev.ru 
37253Sigor@sysoev.ru 
37353Sigor@sysoev.ru static nxt_socket_conf_t *
37465Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
37553Sigor@sysoev.ru {
37653Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
37753Sigor@sysoev.ru 
37865Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
37953Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
38053Sigor@sysoev.ru         return NULL;
38153Sigor@sysoev.ru     }
38253Sigor@sysoev.ru 
383*115Sigor@sysoev.ru     conf->sockaddr = sa;
384*115Sigor@sysoev.ru 
38553Sigor@sysoev.ru     conf->listen.sockaddr = sa;
386103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
387103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
38853Sigor@sysoev.ru 
38953Sigor@sysoev.ru     conf->listen.socket = -1;
39053Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
39153Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
39253Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
39353Sigor@sysoev.ru 
39453Sigor@sysoev.ru     return conf;
39553Sigor@sysoev.ru }
39653Sigor@sysoev.ru 
39753Sigor@sysoev.ru 
39853Sigor@sysoev.ru static void
39953Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
40053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
40153Sigor@sysoev.ru {
40253Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
40353Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
40453Sigor@sysoev.ru 
40553Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
40653Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
40753Sigor@sysoev.ru          nqlk = next)
40853Sigor@sysoev.ru     {
40953Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
41053Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
41153Sigor@sysoev.ru 
41253Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
41353Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
41453Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
41553Sigor@sysoev.ru         {
41653Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
41753Sigor@sysoev.ru 
418*115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
419*115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
420*115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
421*115Sigor@sysoev.ru 
42253Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
42353Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
42453Sigor@sysoev.ru 
42553Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
42653Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
42753Sigor@sysoev.ru 
42853Sigor@sysoev.ru                 break;
42953Sigor@sysoev.ru             }
43053Sigor@sysoev.ru         }
43153Sigor@sysoev.ru     }
43253Sigor@sysoev.ru 
43353Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
434*115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
43553Sigor@sysoev.ru }
43653Sigor@sysoev.ru 
43753Sigor@sysoev.ru 
43853Sigor@sysoev.ru static nxt_int_t
43953Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
44053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
44153Sigor@sysoev.ru {
442*115Sigor@sysoev.ru     nxt_int_t            ret;
443*115Sigor@sysoev.ru     nxt_socket_t         s;
444*115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
445*115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
446*115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
44753Sigor@sysoev.ru 
44853Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
44953Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
45053Sigor@sysoev.ru          qlk = nqlk)
45153Sigor@sysoev.ru     {
452*115Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
453*115Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
45453Sigor@sysoev.ru             return NXT_ERROR;
45553Sigor@sysoev.ru         }
45653Sigor@sysoev.ru 
457*115Sigor@sysoev.ru         rtsk->count = 0;
458*115Sigor@sysoev.ru 
459*115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
460*115Sigor@sysoev.ru         skcf->socket = rtsk;
461*115Sigor@sysoev.ru 
462*115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
463*115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
464*115Sigor@sysoev.ru             return NXT_ERROR;
465*115Sigor@sysoev.ru         }
466*115Sigor@sysoev.ru 
467*115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
468*115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
469*115Sigor@sysoev.ru             return NXT_ERROR;
470*115Sigor@sysoev.ru         }
471*115Sigor@sysoev.ru 
472*115Sigor@sysoev.ru         skcf->listen.socket = s;
473*115Sigor@sysoev.ru 
474*115Sigor@sysoev.ru         rtsk->fd = s;
475*115Sigor@sysoev.ru 
47653Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
47753Sigor@sysoev.ru         nxt_queue_remove(qlk);
47853Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
47953Sigor@sysoev.ru     }
48053Sigor@sysoev.ru 
48153Sigor@sysoev.ru     return NXT_OK;
48253Sigor@sysoev.ru }
48353Sigor@sysoev.ru 
48453Sigor@sysoev.ru 
48553Sigor@sysoev.ru static nxt_int_t
48653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
48753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
48853Sigor@sysoev.ru {
48953Sigor@sysoev.ru     nxt_int_t                 ret;
49053Sigor@sysoev.ru     nxt_uint_t                n, threads;
49153Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
49253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
49353Sigor@sysoev.ru 
49453Sigor@sysoev.ru     threads = tmcf->conf->threads;
49553Sigor@sysoev.ru 
49653Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
49753Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
49853Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
49953Sigor@sysoev.ru         return NXT_ERROR;
50053Sigor@sysoev.ru     }
50153Sigor@sysoev.ru 
50253Sigor@sysoev.ru     n = 0;
50353Sigor@sysoev.ru 
50453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
50553Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
50653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
50753Sigor@sysoev.ru     {
50853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
50953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
51053Sigor@sysoev.ru             return NXT_ERROR;
51153Sigor@sysoev.ru         }
51253Sigor@sysoev.ru 
513*115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
51453Sigor@sysoev.ru         // STUB
51553Sigor@sysoev.ru         recf->task = recf->engine->task;
51653Sigor@sysoev.ru 
51753Sigor@sysoev.ru         if (n < threads) {
518*115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
51953Sigor@sysoev.ru 
52053Sigor@sysoev.ru         } else {
521*115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
52253Sigor@sysoev.ru         }
52353Sigor@sysoev.ru 
52453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
52553Sigor@sysoev.ru             return ret;
52653Sigor@sysoev.ru         }
52753Sigor@sysoev.ru 
52853Sigor@sysoev.ru         n++;
52953Sigor@sysoev.ru     }
53053Sigor@sysoev.ru 
53153Sigor@sysoev.ru     tmcf->new_threads = n;
53253Sigor@sysoev.ru 
53353Sigor@sysoev.ru     while (n < threads) {
53453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
53553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
53653Sigor@sysoev.ru             return NXT_ERROR;
53753Sigor@sysoev.ru         }
53853Sigor@sysoev.ru 
53953Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
54053Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
54153Sigor@sysoev.ru             return NXT_ERROR;
54253Sigor@sysoev.ru         }
54353Sigor@sysoev.ru         // STUB
54453Sigor@sysoev.ru         recf->task = recf->engine->task;
54553Sigor@sysoev.ru 
546*115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
54753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
54853Sigor@sysoev.ru             return ret;
54953Sigor@sysoev.ru         }
55053Sigor@sysoev.ru 
551*115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
552*115Sigor@sysoev.ru 
55353Sigor@sysoev.ru         n++;
55453Sigor@sysoev.ru     }
55553Sigor@sysoev.ru 
55653Sigor@sysoev.ru     return NXT_OK;
55753Sigor@sysoev.ru }
55853Sigor@sysoev.ru 
55953Sigor@sysoev.ru 
56053Sigor@sysoev.ru static nxt_int_t
561*115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
562*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
56353Sigor@sysoev.ru {
564*115Sigor@sysoev.ru     nxt_mp_t               *mp;
565*115Sigor@sysoev.ru     nxt_int_t              ret;
566*115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
56753Sigor@sysoev.ru 
56853Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
56953Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
57053Sigor@sysoev.ru         return NXT_ERROR;
57153Sigor@sysoev.ru     }
57253Sigor@sysoev.ru 
573*115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
574*115Sigor@sysoev.ru 
575*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->creating,
576*115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
577*115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
578*115Sigor@sysoev.ru         return ret;
579*115Sigor@sysoev.ru     }
580*115Sigor@sysoev.ru 
581*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->updating,
58253Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
58353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
58453Sigor@sysoev.ru         return ret;
58553Sigor@sysoev.ru     }
58653Sigor@sysoev.ru 
587*115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
588*115Sigor@sysoev.ru 
589*115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
590*115Sigor@sysoev.ru 
591*115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
592*115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
593*115Sigor@sysoev.ru 
594*115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
595*115Sigor@sysoev.ru 
596*115Sigor@sysoev.ru     return ret;
59753Sigor@sysoev.ru }
59853Sigor@sysoev.ru 
59953Sigor@sysoev.ru 
60053Sigor@sysoev.ru static nxt_int_t
601*115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
602*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
60353Sigor@sysoev.ru {
604*115Sigor@sysoev.ru     nxt_mp_t               *mp;
605*115Sigor@sysoev.ru     nxt_int_t              ret;
606*115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
60753Sigor@sysoev.ru 
60853Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
60953Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
61053Sigor@sysoev.ru         return NXT_ERROR;
61153Sigor@sysoev.ru     }
61253Sigor@sysoev.ru 
613*115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
614*115Sigor@sysoev.ru 
615*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->creating,
61653Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
61753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
61853Sigor@sysoev.ru         return ret;
61953Sigor@sysoev.ru     }
62053Sigor@sysoev.ru 
62153Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
62253Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
62353Sigor@sysoev.ru         return NXT_ERROR;
62453Sigor@sysoev.ru     }
62553Sigor@sysoev.ru 
626*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->updating,
62753Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
62853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
62953Sigor@sysoev.ru         return ret;
63053Sigor@sysoev.ru     }
63153Sigor@sysoev.ru 
63253Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
63353Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
63453Sigor@sysoev.ru         return NXT_ERROR;
63553Sigor@sysoev.ru     }
63653Sigor@sysoev.ru 
637*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(recf, &tmcf->deleting);
638*115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
639*115Sigor@sysoev.ru         return ret;
640*115Sigor@sysoev.ru     }
641*115Sigor@sysoev.ru 
642*115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
643*115Sigor@sysoev.ru 
644*115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
645*115Sigor@sysoev.ru 
646*115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
647*115Sigor@sysoev.ru 
648*115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
649*115Sigor@sysoev.ru 
650*115Sigor@sysoev.ru     return ret;
65153Sigor@sysoev.ru }
65253Sigor@sysoev.ru 
65353Sigor@sysoev.ru 
65453Sigor@sysoev.ru static nxt_int_t
655*115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
656*115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
65753Sigor@sysoev.ru {
65853Sigor@sysoev.ru     nxt_int_t  ret;
65953Sigor@sysoev.ru 
66053Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
66153Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
66253Sigor@sysoev.ru         return NXT_ERROR;
66353Sigor@sysoev.ru     }
66453Sigor@sysoev.ru 
665*115Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(recf, &tmcf->updating);
66653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
66753Sigor@sysoev.ru         return ret;
66853Sigor@sysoev.ru     }
66953Sigor@sysoev.ru 
670*115Sigor@sysoev.ru     return nxt_router_engine_joints_delete(recf, &tmcf->deleting);
67153Sigor@sysoev.ru }
67253Sigor@sysoev.ru 
67353Sigor@sysoev.ru 
67453Sigor@sysoev.ru static nxt_int_t
675*115Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_engine_conf_t *recf,
676*115Sigor@sysoev.ru     nxt_queue_t *sockets, nxt_array_t *array,
67753Sigor@sysoev.ru     nxt_work_handler_t handler)
67853Sigor@sysoev.ru {
67953Sigor@sysoev.ru     nxt_work_t               *work;
68053Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
68153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
68253Sigor@sysoev.ru 
68353Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
68453Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
68553Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
68653Sigor@sysoev.ru     {
68753Sigor@sysoev.ru         work = nxt_array_add(array);
68853Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
68953Sigor@sysoev.ru             return NXT_ERROR;
69053Sigor@sysoev.ru         }
69153Sigor@sysoev.ru 
69253Sigor@sysoev.ru         work->next = NULL;
69353Sigor@sysoev.ru         work->handler = handler;
69453Sigor@sysoev.ru         work->task = &recf->task;
69553Sigor@sysoev.ru         work->obj = recf->engine;
69653Sigor@sysoev.ru 
69765Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
69853Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
69953Sigor@sysoev.ru             return NXT_ERROR;
70053Sigor@sysoev.ru         }
70153Sigor@sysoev.ru 
70253Sigor@sysoev.ru         work->data = joint;
70353Sigor@sysoev.ru 
70453Sigor@sysoev.ru         joint->count = 1;
70553Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
70688Smax.romanov@nginx.com         joint->engine = recf->engine;
707*115Sigor@sysoev.ru 
708*115Sigor@sysoev.ru         nxt_queue_insert_tail(&joint->engine->joints, &joint->link);
70953Sigor@sysoev.ru     }
71053Sigor@sysoev.ru 
71120Sigor@sysoev.ru     return NXT_OK;
71220Sigor@sysoev.ru }
71320Sigor@sysoev.ru 
71420Sigor@sysoev.ru 
715*115Sigor@sysoev.ru static void
716*115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
717*115Sigor@sysoev.ru {
718*115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
719*115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
720*115Sigor@sysoev.ru 
721*115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
722*115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
723*115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
724*115Sigor@sysoev.ru     {
725*115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
726*115Sigor@sysoev.ru         skcf->socket->count++;
727*115Sigor@sysoev.ru     }
728*115Sigor@sysoev.ru }
729*115Sigor@sysoev.ru 
730*115Sigor@sysoev.ru 
73120Sigor@sysoev.ru static nxt_int_t
732*115Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_engine_conf_t *recf,
733*115Sigor@sysoev.ru     nxt_queue_t *sockets)
73420Sigor@sysoev.ru {
73553Sigor@sysoev.ru     nxt_work_t        *work;
73653Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
73720Sigor@sysoev.ru 
73853Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
73953Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
74053Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
74153Sigor@sysoev.ru     {
742*115Sigor@sysoev.ru         work = nxt_array_add(recf->deleting);
74353Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
74453Sigor@sysoev.ru             return NXT_ERROR;
74553Sigor@sysoev.ru         }
74620Sigor@sysoev.ru 
74753Sigor@sysoev.ru         work->next = NULL;
74853Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
74953Sigor@sysoev.ru         work->task = &recf->task;
75053Sigor@sysoev.ru         work->obj = recf->engine;
75153Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
75220Sigor@sysoev.ru     }
75320Sigor@sysoev.ru 
75453Sigor@sysoev.ru     return NXT_OK;
75553Sigor@sysoev.ru }
75620Sigor@sysoev.ru 
75720Sigor@sysoev.ru 
75853Sigor@sysoev.ru static nxt_int_t
75953Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
76053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
76153Sigor@sysoev.ru {
76253Sigor@sysoev.ru     nxt_int_t                 ret;
76353Sigor@sysoev.ru     nxt_uint_t                i, threads;
76453Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
76520Sigor@sysoev.ru 
76653Sigor@sysoev.ru     recf = tmcf->engines->elts;
76753Sigor@sysoev.ru     threads = tmcf->conf->threads;
76820Sigor@sysoev.ru 
76953Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
77053Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
77153Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
77253Sigor@sysoev.ru             return ret;
77353Sigor@sysoev.ru         }
77420Sigor@sysoev.ru     }
77520Sigor@sysoev.ru 
77620Sigor@sysoev.ru     return NXT_OK;
77720Sigor@sysoev.ru }
77853Sigor@sysoev.ru 
77953Sigor@sysoev.ru 
78053Sigor@sysoev.ru static nxt_int_t
78153Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
78253Sigor@sysoev.ru     nxt_event_engine_t *engine)
78353Sigor@sysoev.ru {
78488Smax.romanov@nginx.com     nxt_mp_t             *mp;
78553Sigor@sysoev.ru     nxt_int_t            ret;
78688Smax.romanov@nginx.com     nxt_port_t           *port;
78788Smax.romanov@nginx.com     nxt_process_t        *process;
78853Sigor@sysoev.ru     nxt_thread_link_t    *link;
78953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
79053Sigor@sysoev.ru 
79153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
79253Sigor@sysoev.ru 
79353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
79453Sigor@sysoev.ru         return NXT_ERROR;
79553Sigor@sysoev.ru     }
79653Sigor@sysoev.ru 
79753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
79853Sigor@sysoev.ru     link->engine = engine;
79953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
80053Sigor@sysoev.ru     link->work.task = task;
80153Sigor@sysoev.ru     link->work.data = link;
80253Sigor@sysoev.ru 
80353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
80453Sigor@sysoev.ru 
80588Smax.romanov@nginx.com     process = nxt_runtime_process_find(rt, nxt_pid);
80688Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
80788Smax.romanov@nginx.com         return NXT_ERROR;
80888Smax.romanov@nginx.com     }
80988Smax.romanov@nginx.com 
81088Smax.romanov@nginx.com     port = nxt_process_port_new(process);
81188Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
81288Smax.romanov@nginx.com         return NXT_ERROR;
81388Smax.romanov@nginx.com     }
81488Smax.romanov@nginx.com 
81588Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
81688Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
81788Smax.romanov@nginx.com         return ret;
81888Smax.romanov@nginx.com     }
81988Smax.romanov@nginx.com 
82088Smax.romanov@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
82188Smax.romanov@nginx.com     if (nxt_slow_path(mp == NULL)) {
82288Smax.romanov@nginx.com         return NXT_ERROR;
82388Smax.romanov@nginx.com     }
82488Smax.romanov@nginx.com 
82588Smax.romanov@nginx.com     port->mem_pool = mp;
82688Smax.romanov@nginx.com     port->engine = 0;
82788Smax.romanov@nginx.com     port->type = NXT_PROCESS_ROUTER;
82888Smax.romanov@nginx.com 
82988Smax.romanov@nginx.com     engine->port = port;
83088Smax.romanov@nginx.com 
83188Smax.romanov@nginx.com     nxt_runtime_port_add(rt, port);
83288Smax.romanov@nginx.com 
83353Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
83453Sigor@sysoev.ru 
83553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
83653Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
83753Sigor@sysoev.ru     }
83853Sigor@sysoev.ru 
83953Sigor@sysoev.ru     return ret;
84053Sigor@sysoev.ru }
84153Sigor@sysoev.ru 
84253Sigor@sysoev.ru 
84353Sigor@sysoev.ru static void
84453Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
84553Sigor@sysoev.ru {
84653Sigor@sysoev.ru     nxt_uint_t                n;
84753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
84853Sigor@sysoev.ru 
84953Sigor@sysoev.ru     recf = tmcf->engines->elts;
85053Sigor@sysoev.ru 
85153Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
85253Sigor@sysoev.ru         nxt_router_engine_post(recf);
85353Sigor@sysoev.ru         recf++;
85453Sigor@sysoev.ru     }
85553Sigor@sysoev.ru }
85653Sigor@sysoev.ru 
85753Sigor@sysoev.ru 
85853Sigor@sysoev.ru static void
85953Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
86053Sigor@sysoev.ru {
86153Sigor@sysoev.ru     nxt_uint_t  n;
86253Sigor@sysoev.ru     nxt_work_t  *work;
86353Sigor@sysoev.ru 
864*115Sigor@sysoev.ru     if (recf->creating != NULL) {
865*115Sigor@sysoev.ru         work = recf->creating->elts;
866*115Sigor@sysoev.ru 
867*115Sigor@sysoev.ru         for (n = recf->creating->nelts; n != 0; n--) {
868*115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
869*115Sigor@sysoev.ru             work++;
870*115Sigor@sysoev.ru         }
871*115Sigor@sysoev.ru     }
872*115Sigor@sysoev.ru 
873*115Sigor@sysoev.ru     if (recf->updating != NULL) {
874*115Sigor@sysoev.ru         work = recf->updating->elts;
87553Sigor@sysoev.ru 
876*115Sigor@sysoev.ru         for (n = recf->updating->nelts; n != 0; n--) {
877*115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
878*115Sigor@sysoev.ru             work++;
879*115Sigor@sysoev.ru         }
880*115Sigor@sysoev.ru     }
881*115Sigor@sysoev.ru 
882*115Sigor@sysoev.ru     if (recf->deleting != NULL) {
883*115Sigor@sysoev.ru         work = recf->deleting->elts;
884*115Sigor@sysoev.ru 
885*115Sigor@sysoev.ru         for (n = recf->deleting->nelts; n != 0; n--) {
886*115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
887*115Sigor@sysoev.ru             work++;
888*115Sigor@sysoev.ru         }
88953Sigor@sysoev.ru     }
89053Sigor@sysoev.ru }
89153Sigor@sysoev.ru 
89253Sigor@sysoev.ru 
89353Sigor@sysoev.ru static void
89488Smax.romanov@nginx.com nxt_router_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
89588Smax.romanov@nginx.com 
89688Smax.romanov@nginx.com nxt_port_handler_t  nxt_router_process_port_handlers[] = {
89788Smax.romanov@nginx.com     NULL,
89888Smax.romanov@nginx.com     nxt_port_new_port_handler,
89988Smax.romanov@nginx.com     nxt_port_change_log_file_handler,
90088Smax.romanov@nginx.com     nxt_port_mmap_handler,
90188Smax.romanov@nginx.com     nxt_router_data_handler,
90288Smax.romanov@nginx.com };
90388Smax.romanov@nginx.com 
90488Smax.romanov@nginx.com 
90588Smax.romanov@nginx.com static void
90653Sigor@sysoev.ru nxt_router_thread_start(void *data)
90753Sigor@sysoev.ru {
90888Smax.romanov@nginx.com     nxt_task_t          *task;
90953Sigor@sysoev.ru     nxt_thread_t        *thread;
91053Sigor@sysoev.ru     nxt_thread_link_t   *link;
91153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
91253Sigor@sysoev.ru 
91353Sigor@sysoev.ru     link = data;
91453Sigor@sysoev.ru     engine = link->engine;
91588Smax.romanov@nginx.com     task = &engine->task;
91653Sigor@sysoev.ru 
91753Sigor@sysoev.ru     thread = nxt_thread();
91853Sigor@sysoev.ru 
91953Sigor@sysoev.ru     /* STUB */
92053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
92153Sigor@sysoev.ru 
92253Sigor@sysoev.ru     engine->task.thread = thread;
92353Sigor@sysoev.ru     engine->task.log = thread->log;
92453Sigor@sysoev.ru     thread->engine = engine;
92563Sigor@sysoev.ru     thread->task = &engine->task;
92653Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
92753Sigor@sysoev.ru 
92888Smax.romanov@nginx.com     engine->port->socket.task = task;
92988Smax.romanov@nginx.com     nxt_port_create(task, engine->port, nxt_router_process_port_handlers);
93088Smax.romanov@nginx.com 
93163Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
93253Sigor@sysoev.ru 
93353Sigor@sysoev.ru     nxt_event_engine_start(engine);
93453Sigor@sysoev.ru }
93553Sigor@sysoev.ru 
93653Sigor@sysoev.ru 
93753Sigor@sysoev.ru static void
93853Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
93953Sigor@sysoev.ru {
94053Sigor@sysoev.ru     nxt_listen_event_t       *listen;
94153Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
94253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
94353Sigor@sysoev.ru 
94453Sigor@sysoev.ru     joint = data;
94553Sigor@sysoev.ru 
94653Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
94753Sigor@sysoev.ru 
94853Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
94953Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
95053Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
95153Sigor@sysoev.ru         return;
95253Sigor@sysoev.ru     }
95353Sigor@sysoev.ru 
95453Sigor@sysoev.ru     listen->socket.data = joint;
95553Sigor@sysoev.ru }
95653Sigor@sysoev.ru 
95753Sigor@sysoev.ru 
95853Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
95953Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
96053Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
96153Sigor@sysoev.ru {
962*115Sigor@sysoev.ru     nxt_socket_t        fd;
963*115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
96453Sigor@sysoev.ru     nxt_listen_event_t  *listen;
96553Sigor@sysoev.ru 
966*115Sigor@sysoev.ru     fd = skcf->socket->fd;
96753Sigor@sysoev.ru 
968*115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
969*115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
970*115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
97153Sigor@sysoev.ru     {
972*115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
97353Sigor@sysoev.ru 
974*115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
97553Sigor@sysoev.ru             return listen;
97653Sigor@sysoev.ru         }
97753Sigor@sysoev.ru     }
97853Sigor@sysoev.ru 
97953Sigor@sysoev.ru     return NULL;
98053Sigor@sysoev.ru }
98153Sigor@sysoev.ru 
98253Sigor@sysoev.ru 
98353Sigor@sysoev.ru static void
98453Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
98553Sigor@sysoev.ru {
98653Sigor@sysoev.ru     nxt_event_engine_t       *engine;
98753Sigor@sysoev.ru     nxt_listen_event_t       *listen;
98853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
98953Sigor@sysoev.ru 
99053Sigor@sysoev.ru     engine = obj;
99153Sigor@sysoev.ru     joint = data;
99253Sigor@sysoev.ru 
99353Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
99453Sigor@sysoev.ru                                      joint->socket_conf);
99553Sigor@sysoev.ru 
99653Sigor@sysoev.ru     old = listen->socket.data;
99753Sigor@sysoev.ru     listen->socket.data = joint;
99853Sigor@sysoev.ru 
99953Sigor@sysoev.ru     nxt_router_conf_release(task, old);
100053Sigor@sysoev.ru }
100153Sigor@sysoev.ru 
100253Sigor@sysoev.ru 
100353Sigor@sysoev.ru static void
100453Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
100553Sigor@sysoev.ru {
100653Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
100753Sigor@sysoev.ru     nxt_listen_event_t  *listen;
100853Sigor@sysoev.ru     nxt_event_engine_t  *engine;
100953Sigor@sysoev.ru 
101053Sigor@sysoev.ru     engine = obj;
101153Sigor@sysoev.ru     skcf = data;
101253Sigor@sysoev.ru 
101353Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
101453Sigor@sysoev.ru 
101553Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
101653Sigor@sysoev.ru 
101753Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
101853Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
101953Sigor@sysoev.ru 
102053Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
102153Sigor@sysoev.ru }
102253Sigor@sysoev.ru 
102353Sigor@sysoev.ru 
102453Sigor@sysoev.ru static void
102553Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
102653Sigor@sysoev.ru {
102753Sigor@sysoev.ru     nxt_timer_t              *timer;
102853Sigor@sysoev.ru     nxt_listen_event_t       *listen;
102953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
103053Sigor@sysoev.ru 
103153Sigor@sysoev.ru     timer = obj;
103253Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
103353Sigor@sysoev.ru     joint = listen->socket.data;
103453Sigor@sysoev.ru 
103553Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
103653Sigor@sysoev.ru     nxt_free(listen);
103753Sigor@sysoev.ru 
103853Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
103953Sigor@sysoev.ru }
104053Sigor@sysoev.ru 
104153Sigor@sysoev.ru 
104253Sigor@sysoev.ru static void
104353Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
104453Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
104553Sigor@sysoev.ru {
1046*115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
104753Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
104853Sigor@sysoev.ru 
1049