xref: /unit/src/nxt_router.c (revision 133)
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>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13*133Sigor@sysoev.ru     nxt_str_t  type;
14*133Sigor@sysoev.ru     uint32_t   workers;
15*133Sigor@sysoev.ru } nxt_router_app_conf_t;
16*133Sigor@sysoev.ru 
17*133Sigor@sysoev.ru 
18*133Sigor@sysoev.ru typedef struct {
19*133Sigor@sysoev.ru     nxt_str_t  application;
20115Sigor@sysoev.ru } nxt_router_listener_conf_t;
21115Sigor@sysoev.ru 
22115Sigor@sysoev.ru 
2353Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task,
2453Sigor@sysoev.ru     nxt_router_t *router);
2553Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
2653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
2753Sigor@sysoev.ru 
28115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
29115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
30*133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
31*133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
32*133Sigor@sysoev.ru     nxt_str_t *name);
3353Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
3453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
3565Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
3665Sigor@sysoev.ru     nxt_sockaddr_t *sa);
3753Sigor@sysoev.ru 
3853Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
3953Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
4053Sigor@sysoev.ru     const nxt_event_interface_t *interface);
41115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
42115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
43115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
44115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
45115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
46115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
47115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
48115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_mp_t *mp,
4965Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
5065Sigor@sysoev.ru     nxt_work_handler_t handler);
51115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_engine_conf_t *recf,
52115Sigor@sysoev.ru     nxt_queue_t *sockets);
5353Sigor@sysoev.ru 
5453Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
5553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
5653Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
5753Sigor@sysoev.ru     nxt_event_engine_t *engine);
58*133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
59*133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6053Sigor@sysoev.ru 
6153Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
6253Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
6353Sigor@sysoev.ru 
6453Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
6553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
6653Sigor@sysoev.ru     void *data);
6753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
6853Sigor@sysoev.ru     void *data);
6953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
7053Sigor@sysoev.ru     void *data);
7153Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
7253Sigor@sysoev.ru     void *data);
7353Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
7453Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
7553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
7653Sigor@sysoev.ru     void *data);
7753Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
7853Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
7953Sigor@sysoev.ru 
8053Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
8153Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
8253Sigor@sysoev.ru     void *data);
8388Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
8488Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
8588Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
8653Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
8753Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
8853Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
8953Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
9062Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
9120Sigor@sysoev.ru 
92119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
9320Sigor@sysoev.ru 
9420Sigor@sysoev.ru nxt_int_t
9520Sigor@sysoev.ru nxt_router_start(nxt_task_t *task, nxt_runtime_t *rt)
9620Sigor@sysoev.ru {
97115Sigor@sysoev.ru     nxt_int_t     ret;
98115Sigor@sysoev.ru     nxt_router_t  *router;
9953Sigor@sysoev.ru 
10088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
10188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
10288Smax.romanov@nginx.com         return ret;
10388Smax.romanov@nginx.com     }
10488Smax.romanov@nginx.com 
10553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
10653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
10753Sigor@sysoev.ru         return NXT_ERROR;
10853Sigor@sysoev.ru     }
10953Sigor@sysoev.ru 
11053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
11153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
112*133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
11353Sigor@sysoev.ru 
114119Smax.romanov@nginx.com     nxt_router = router;
115119Smax.romanov@nginx.com 
116115Sigor@sysoev.ru     return NXT_OK;
117115Sigor@sysoev.ru }
118115Sigor@sysoev.ru 
119115Sigor@sysoev.ru 
120115Sigor@sysoev.ru nxt_int_t
121115Sigor@sysoev.ru nxt_router_new_conf(nxt_task_t *task, nxt_runtime_t *rt, nxt_router_t *router,
122115Sigor@sysoev.ru     u_char *start, u_char *end)
123115Sigor@sysoev.ru {
124115Sigor@sysoev.ru     nxt_int_t                    ret;
125115Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
126115Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
12753Sigor@sysoev.ru 
12853Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task, router);
12953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
13020Sigor@sysoev.ru         return NXT_ERROR;
13120Sigor@sysoev.ru     }
13220Sigor@sysoev.ru 
133115Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
13453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
13553Sigor@sysoev.ru         return ret;
13653Sigor@sysoev.ru     }
13753Sigor@sysoev.ru 
13853Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
13953Sigor@sysoev.ru 
14053Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
14153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
14253Sigor@sysoev.ru         return ret;
14353Sigor@sysoev.ru     }
14453Sigor@sysoev.ru 
14553Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
14653Sigor@sysoev.ru 
14753Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
14853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
14953Sigor@sysoev.ru         return ret;
15053Sigor@sysoev.ru     }
15153Sigor@sysoev.ru 
15253Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
15353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
15453Sigor@sysoev.ru         return ret;
15553Sigor@sysoev.ru     }
15653Sigor@sysoev.ru 
157*133Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
158*133Sigor@sysoev.ru 
15953Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
16053Sigor@sysoev.ru 
16153Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
16253Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
16353Sigor@sysoev.ru 
164115Sigor@sysoev.ru //    nxt_mp_destroy(tmcf->mem_pool);
165115Sigor@sysoev.ru 
16653Sigor@sysoev.ru     return NXT_OK;
16753Sigor@sysoev.ru }
16853Sigor@sysoev.ru 
16953Sigor@sysoev.ru 
17053Sigor@sysoev.ru static nxt_router_temp_conf_t *
17153Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task, nxt_router_t *router)
17253Sigor@sysoev.ru {
17365Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
17453Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
17553Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
17653Sigor@sysoev.ru 
17765Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
17853Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
17953Sigor@sysoev.ru         return NULL;
18053Sigor@sysoev.ru     }
18153Sigor@sysoev.ru 
18265Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
18353Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
18453Sigor@sysoev.ru         goto fail;
18553Sigor@sysoev.ru     }
18653Sigor@sysoev.ru 
18753Sigor@sysoev.ru     rtcf->mem_pool = mp;
18853Sigor@sysoev.ru     rtcf->router = router;
18953Sigor@sysoev.ru     rtcf->count = 1;
19053Sigor@sysoev.ru 
19165Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
19253Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
19353Sigor@sysoev.ru         goto fail;
19453Sigor@sysoev.ru     }
19553Sigor@sysoev.ru 
19665Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
19753Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
19853Sigor@sysoev.ru         goto temp_fail;
19953Sigor@sysoev.ru     }
20053Sigor@sysoev.ru 
20153Sigor@sysoev.ru     tmcf->mem_pool = tmp;
20253Sigor@sysoev.ru     tmcf->conf = rtcf;
20353Sigor@sysoev.ru 
20453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
20553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
20653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
20753Sigor@sysoev.ru         goto temp_fail;
20853Sigor@sysoev.ru     }
20953Sigor@sysoev.ru 
21053Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
21153Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
21253Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
21353Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
21453Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
215*133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
216*133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
21753Sigor@sysoev.ru 
21853Sigor@sysoev.ru     return tmcf;
21953Sigor@sysoev.ru 
22053Sigor@sysoev.ru temp_fail:
22153Sigor@sysoev.ru 
22265Sigor@sysoev.ru     nxt_mp_destroy(tmp);
22353Sigor@sysoev.ru 
22453Sigor@sysoev.ru fail:
22553Sigor@sysoev.ru 
22665Sigor@sysoev.ru     nxt_mp_destroy(mp);
22753Sigor@sysoev.ru 
22853Sigor@sysoev.ru     return NULL;
22953Sigor@sysoev.ru }
23053Sigor@sysoev.ru 
23153Sigor@sysoev.ru 
232115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
233115Sigor@sysoev.ru     {
234*133Sigor@sysoev.ru         nxt_string("listeners_threads"),
235115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
236115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
237115Sigor@sysoev.ru     },
238115Sigor@sysoev.ru 
239115Sigor@sysoev.ru     {
240115Sigor@sysoev.ru         nxt_null_string, 0, 0,
241115Sigor@sysoev.ru     },
242115Sigor@sysoev.ru };
243115Sigor@sysoev.ru 
244115Sigor@sysoev.ru 
245*133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
246115Sigor@sysoev.ru     {
247*133Sigor@sysoev.ru         nxt_string("type"),
248115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
249*133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
250115Sigor@sysoev.ru     },
251115Sigor@sysoev.ru 
252115Sigor@sysoev.ru     {
253*133Sigor@sysoev.ru         nxt_string("workers"),
254115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
255*133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
256*133Sigor@sysoev.ru     },
257*133Sigor@sysoev.ru 
258*133Sigor@sysoev.ru     {
259*133Sigor@sysoev.ru         nxt_null_string, 0, 0,
260*133Sigor@sysoev.ru     },
261*133Sigor@sysoev.ru };
262*133Sigor@sysoev.ru 
263*133Sigor@sysoev.ru 
264*133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
265*133Sigor@sysoev.ru     {
266*133Sigor@sysoev.ru         nxt_string("application"),
267*133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
268*133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
269115Sigor@sysoev.ru     },
270115Sigor@sysoev.ru 
271115Sigor@sysoev.ru     {
272115Sigor@sysoev.ru         nxt_null_string, 0, 0,
273115Sigor@sysoev.ru     },
274115Sigor@sysoev.ru };
275115Sigor@sysoev.ru 
276115Sigor@sysoev.ru 
277115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
278115Sigor@sysoev.ru     {
279115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
280115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
281115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
282115Sigor@sysoev.ru     },
283115Sigor@sysoev.ru 
284115Sigor@sysoev.ru     {
285115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
286115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
287115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
288115Sigor@sysoev.ru     },
289115Sigor@sysoev.ru 
290115Sigor@sysoev.ru     {
291115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
292115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
293115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
294115Sigor@sysoev.ru     },
295115Sigor@sysoev.ru 
296115Sigor@sysoev.ru     {
297115Sigor@sysoev.ru         nxt_null_string, 0, 0,
298115Sigor@sysoev.ru     },
299115Sigor@sysoev.ru };
300115Sigor@sysoev.ru 
301115Sigor@sysoev.ru 
30253Sigor@sysoev.ru static nxt_int_t
303115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
304115Sigor@sysoev.ru     u_char *start, u_char *end)
30553Sigor@sysoev.ru {
306*133Sigor@sysoev.ru     u_char                      *p;
307*133Sigor@sysoev.ru     size_t                      size;
308115Sigor@sysoev.ru     nxt_mp_t                    *mp;
309115Sigor@sysoev.ru     uint32_t                    next;
310115Sigor@sysoev.ru     nxt_int_t                   ret;
311115Sigor@sysoev.ru     nxt_str_t                   name;
312*133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
313*133Sigor@sysoev.ru     nxt_app_type_t              type;
314115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
315*133Sigor@sysoev.ru     nxt_queue_link_t            *qlk, *nqlk;
316*133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
317*133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
318*133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
319115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
320*133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
321115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
322115Sigor@sysoev.ru 
323115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
324*133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
325115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
326115Sigor@sysoev.ru 
327115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
328115Sigor@sysoev.ru     if (conf == NULL) {
329115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
330115Sigor@sysoev.ru         return NXT_ERROR;
331115Sigor@sysoev.ru     }
332115Sigor@sysoev.ru 
333*133Sigor@sysoev.ru     ret = nxt_conf_map_object(conf, nxt_router_conf, tmcf->conf);
334115Sigor@sysoev.ru     if (ret != NXT_OK) {
335*133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
336115Sigor@sysoev.ru         return NXT_ERROR;
337115Sigor@sysoev.ru     }
338115Sigor@sysoev.ru 
339117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
340117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
341117Sigor@sysoev.ru     }
342117Sigor@sysoev.ru 
343*133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
344*133Sigor@sysoev.ru     if (applications == NULL) {
345*133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
346115Sigor@sysoev.ru         return NXT_ERROR;
347115Sigor@sysoev.ru     }
348115Sigor@sysoev.ru 
349*133Sigor@sysoev.ru     next = 0;
350*133Sigor@sysoev.ru 
351*133Sigor@sysoev.ru     for ( ;; ) {
352*133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
353*133Sigor@sysoev.ru         if (application == NULL) {
354*133Sigor@sysoev.ru             break;
355*133Sigor@sysoev.ru         }
356*133Sigor@sysoev.ru 
357*133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
358*133Sigor@sysoev.ru 
359*133Sigor@sysoev.ru         app = nxt_zalloc(sizeof(nxt_app_t));
360*133Sigor@sysoev.ru         if (app == NULL) {
361*133Sigor@sysoev.ru             goto fail;
362*133Sigor@sysoev.ru         }
363*133Sigor@sysoev.ru 
364*133Sigor@sysoev.ru         size = nxt_conf_json_length(application, NULL);
365*133Sigor@sysoev.ru 
366*133Sigor@sysoev.ru         app->conf.start = nxt_malloc(size);
367*133Sigor@sysoev.ru         if (app->conf.start == NULL) {
368*133Sigor@sysoev.ru             nxt_free(app);
369*133Sigor@sysoev.ru             goto fail;
370*133Sigor@sysoev.ru         }
371*133Sigor@sysoev.ru 
372*133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
373*133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
374*133Sigor@sysoev.ru 
375*133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
376*133Sigor@sysoev.ru 
377*133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
378*133Sigor@sysoev.ru 
379*133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
380*133Sigor@sysoev.ru             nxt_free(app->conf.start);
381*133Sigor@sysoev.ru             nxt_free(app);
382*133Sigor@sysoev.ru 
383*133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
384*133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
385*133Sigor@sysoev.ru             continue;
386*133Sigor@sysoev.ru         }
387*133Sigor@sysoev.ru 
388*133Sigor@sysoev.ru         ret = nxt_conf_map_object(application, nxt_router_app_conf, &apcf);
389*133Sigor@sysoev.ru         if (ret != NXT_OK) {
390*133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
391*133Sigor@sysoev.ru             goto app_fail;
392*133Sigor@sysoev.ru         }
393115Sigor@sysoev.ru 
394*133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
395*133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
396*133Sigor@sysoev.ru 
397*133Sigor@sysoev.ru         if (nxt_str_eq(&apcf.type, "python", 6)) {
398*133Sigor@sysoev.ru             type = NXT_APP_PYTHON;
399*133Sigor@sysoev.ru 
400*133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "php", 3)) {
401*133Sigor@sysoev.ru             type = NXT_APP_PHP;
402*133Sigor@sysoev.ru 
403*133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "ruby", 4)) {
404*133Sigor@sysoev.ru             type = NXT_APP_RUBY;
405*133Sigor@sysoev.ru 
406*133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "go", 2)) {
407*133Sigor@sysoev.ru             type = NXT_APP_GO;
408*133Sigor@sysoev.ru 
409*133Sigor@sysoev.ru         } else {
410*133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
411*133Sigor@sysoev.ru                     &apcf.type);
412*133Sigor@sysoev.ru             goto app_fail;
413*133Sigor@sysoev.ru         }
414*133Sigor@sysoev.ru 
415*133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
416*133Sigor@sysoev.ru         if (ret != NXT_OK) {
417*133Sigor@sysoev.ru             goto app_fail;
418*133Sigor@sysoev.ru         }
419*133Sigor@sysoev.ru 
420*133Sigor@sysoev.ru         app->name = name;
421*133Sigor@sysoev.ru         app->type = type;
422*133Sigor@sysoev.ru         app->max_workers = apcf.workers;
423*133Sigor@sysoev.ru         app->live = 1;
424*133Sigor@sysoev.ru 
425*133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
426*133Sigor@sysoev.ru     }
427*133Sigor@sysoev.ru 
428*133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
429*133Sigor@sysoev.ru #if 0
430*133Sigor@sysoev.ru     if (http == NULL) {
431*133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
432*133Sigor@sysoev.ru         return NXT_ERROR;
433*133Sigor@sysoev.ru     }
434*133Sigor@sysoev.ru #endif
435*133Sigor@sysoev.ru 
436*133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
437115Sigor@sysoev.ru     if (listeners == NULL) {
438*133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
439115Sigor@sysoev.ru         return NXT_ERROR;
440115Sigor@sysoev.ru     }
44153Sigor@sysoev.ru 
442*133Sigor@sysoev.ru     next = 0;
44353Sigor@sysoev.ru 
444*133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
445115Sigor@sysoev.ru 
446115Sigor@sysoev.ru     for ( ;; ) {
447115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
448115Sigor@sysoev.ru         if (listener == NULL) {
449115Sigor@sysoev.ru             break;
450115Sigor@sysoev.ru         }
45153Sigor@sysoev.ru 
452115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
453115Sigor@sysoev.ru         if (sa == NULL) {
454115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
455*133Sigor@sysoev.ru             goto fail;
456115Sigor@sysoev.ru         }
457115Sigor@sysoev.ru 
458115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
459115Sigor@sysoev.ru 
460115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
461115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
46253Sigor@sysoev.ru 
463115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
464115Sigor@sysoev.ru         if (skcf == NULL) {
465*133Sigor@sysoev.ru             goto fail;
466115Sigor@sysoev.ru         }
46753Sigor@sysoev.ru 
468115Sigor@sysoev.ru         ret = nxt_conf_map_object(listener, nxt_router_listener_conf, &lscf);
469115Sigor@sysoev.ru         if (ret != NXT_OK) {
470115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
471*133Sigor@sysoev.ru             goto fail;
472115Sigor@sysoev.ru         }
47353Sigor@sysoev.ru 
474*133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
475*133Sigor@sysoev.ru 
476*133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
477*133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
478*133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
479*133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
48053Sigor@sysoev.ru 
481*133Sigor@sysoev.ru         if (http != NULL) {
482*133Sigor@sysoev.ru             ret = nxt_conf_map_object(http, nxt_router_http_conf, skcf);
483*133Sigor@sysoev.ru             if (ret != NXT_OK) {
484*133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
485*133Sigor@sysoev.ru                 goto fail;
486*133Sigor@sysoev.ru             }
487115Sigor@sysoev.ru         }
488115Sigor@sysoev.ru 
489115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
490115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
491*133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
492*133Sigor@sysoev.ru                                                             &lscf.application);
493115Sigor@sysoev.ru 
494115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
495115Sigor@sysoev.ru     }
49653Sigor@sysoev.ru 
49753Sigor@sysoev.ru     return NXT_OK;
498*133Sigor@sysoev.ru 
499*133Sigor@sysoev.ru app_fail:
500*133Sigor@sysoev.ru 
501*133Sigor@sysoev.ru     nxt_free(app->conf.start);
502*133Sigor@sysoev.ru     nxt_free(app);
503*133Sigor@sysoev.ru 
504*133Sigor@sysoev.ru fail:
505*133Sigor@sysoev.ru 
506*133Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->apps);
507*133Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->apps);
508*133Sigor@sysoev.ru          qlk = nqlk)
509*133Sigor@sysoev.ru     {
510*133Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
511*133Sigor@sysoev.ru         app = nxt_queue_link_data(qlk, nxt_app_t, link);
512*133Sigor@sysoev.ru 
513*133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
514*133Sigor@sysoev.ru         nxt_free(app);
515*133Sigor@sysoev.ru     }
516*133Sigor@sysoev.ru 
517*133Sigor@sysoev.ru     return NXT_ERROR;
518*133Sigor@sysoev.ru }
519*133Sigor@sysoev.ru 
520*133Sigor@sysoev.ru 
521*133Sigor@sysoev.ru static nxt_app_t *
522*133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
523*133Sigor@sysoev.ru {
524*133Sigor@sysoev.ru     nxt_app_t         *app;
525*133Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
526*133Sigor@sysoev.ru 
527*133Sigor@sysoev.ru     for (qlk = nxt_queue_first(queue);
528*133Sigor@sysoev.ru          qlk != nxt_queue_tail(queue);
529*133Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
530*133Sigor@sysoev.ru     {
531*133Sigor@sysoev.ru         app = nxt_queue_link_data(qlk, nxt_app_t, link);
532*133Sigor@sysoev.ru 
533*133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
534*133Sigor@sysoev.ru             return app;
535*133Sigor@sysoev.ru         }
536*133Sigor@sysoev.ru     }
537*133Sigor@sysoev.ru 
538*133Sigor@sysoev.ru     return NULL;
539*133Sigor@sysoev.ru }
540*133Sigor@sysoev.ru 
541*133Sigor@sysoev.ru 
542*133Sigor@sysoev.ru static nxt_app_t *
543*133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
544*133Sigor@sysoev.ru {
545*133Sigor@sysoev.ru     nxt_app_t  *app;
546*133Sigor@sysoev.ru 
547*133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
548*133Sigor@sysoev.ru 
549*133Sigor@sysoev.ru     if (app == NULL) {
550*133Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->conf->router->apps, name);
551*133Sigor@sysoev.ru     }
552*133Sigor@sysoev.ru 
553*133Sigor@sysoev.ru     return app;
55453Sigor@sysoev.ru }
55553Sigor@sysoev.ru 
55653Sigor@sysoev.ru 
55753Sigor@sysoev.ru static nxt_socket_conf_t *
55865Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
55953Sigor@sysoev.ru {
56053Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
56153Sigor@sysoev.ru 
56265Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
56353Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
56453Sigor@sysoev.ru         return NULL;
56553Sigor@sysoev.ru     }
56653Sigor@sysoev.ru 
567115Sigor@sysoev.ru     conf->sockaddr = sa;
568115Sigor@sysoev.ru 
56953Sigor@sysoev.ru     conf->listen.sockaddr = sa;
570103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
571103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
57253Sigor@sysoev.ru 
57353Sigor@sysoev.ru     conf->listen.socket = -1;
57453Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
57553Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
57653Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
57753Sigor@sysoev.ru 
57853Sigor@sysoev.ru     return conf;
57953Sigor@sysoev.ru }
58053Sigor@sysoev.ru 
58153Sigor@sysoev.ru 
58253Sigor@sysoev.ru static void
58353Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
58453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
58553Sigor@sysoev.ru {
58653Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
58753Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
58853Sigor@sysoev.ru 
58953Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
59053Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
59153Sigor@sysoev.ru          nqlk = next)
59253Sigor@sysoev.ru     {
59353Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
59453Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
59553Sigor@sysoev.ru 
59653Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
59753Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
59853Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
59953Sigor@sysoev.ru         {
60053Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
60153Sigor@sysoev.ru 
602115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
603115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
604115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
605115Sigor@sysoev.ru 
60653Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
60753Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
60853Sigor@sysoev.ru 
60953Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
61053Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
61153Sigor@sysoev.ru 
61253Sigor@sysoev.ru                 break;
61353Sigor@sysoev.ru             }
61453Sigor@sysoev.ru         }
61553Sigor@sysoev.ru     }
61653Sigor@sysoev.ru 
61753Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
618115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
61953Sigor@sysoev.ru }
62053Sigor@sysoev.ru 
62153Sigor@sysoev.ru 
62253Sigor@sysoev.ru static nxt_int_t
62353Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
62453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
62553Sigor@sysoev.ru {
626115Sigor@sysoev.ru     nxt_int_t            ret;
627115Sigor@sysoev.ru     nxt_socket_t         s;
628115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
629115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
630115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
63153Sigor@sysoev.ru 
63253Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
63353Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
63453Sigor@sysoev.ru          qlk = nqlk)
63553Sigor@sysoev.ru     {
636115Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
637115Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
63853Sigor@sysoev.ru             return NXT_ERROR;
63953Sigor@sysoev.ru         }
64053Sigor@sysoev.ru 
641115Sigor@sysoev.ru         rtsk->count = 0;
642115Sigor@sysoev.ru 
643115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
644115Sigor@sysoev.ru         skcf->socket = rtsk;
645115Sigor@sysoev.ru 
646115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
647115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
648115Sigor@sysoev.ru             return NXT_ERROR;
649115Sigor@sysoev.ru         }
650115Sigor@sysoev.ru 
651115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
652115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
653115Sigor@sysoev.ru             return NXT_ERROR;
654115Sigor@sysoev.ru         }
655115Sigor@sysoev.ru 
656115Sigor@sysoev.ru         skcf->listen.socket = s;
657115Sigor@sysoev.ru 
658115Sigor@sysoev.ru         rtsk->fd = s;
659115Sigor@sysoev.ru 
66053Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
66153Sigor@sysoev.ru         nxt_queue_remove(qlk);
66253Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
66353Sigor@sysoev.ru     }
66453Sigor@sysoev.ru 
66553Sigor@sysoev.ru     return NXT_OK;
66653Sigor@sysoev.ru }
66753Sigor@sysoev.ru 
66853Sigor@sysoev.ru 
66953Sigor@sysoev.ru static nxt_int_t
67053Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
67153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
67253Sigor@sysoev.ru {
67353Sigor@sysoev.ru     nxt_int_t                 ret;
67453Sigor@sysoev.ru     nxt_uint_t                n, threads;
67553Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
67653Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
67753Sigor@sysoev.ru 
67853Sigor@sysoev.ru     threads = tmcf->conf->threads;
67953Sigor@sysoev.ru 
68053Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
68153Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
68253Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
68353Sigor@sysoev.ru         return NXT_ERROR;
68453Sigor@sysoev.ru     }
68553Sigor@sysoev.ru 
68653Sigor@sysoev.ru     n = 0;
68753Sigor@sysoev.ru 
68853Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
68953Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
69053Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
69153Sigor@sysoev.ru     {
69253Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
69353Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
69453Sigor@sysoev.ru             return NXT_ERROR;
69553Sigor@sysoev.ru         }
69653Sigor@sysoev.ru 
697115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
69853Sigor@sysoev.ru         // STUB
69953Sigor@sysoev.ru         recf->task = recf->engine->task;
70053Sigor@sysoev.ru 
70153Sigor@sysoev.ru         if (n < threads) {
702115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
70353Sigor@sysoev.ru 
70453Sigor@sysoev.ru         } else {
705115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
70653Sigor@sysoev.ru         }
70753Sigor@sysoev.ru 
70853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
70953Sigor@sysoev.ru             return ret;
71053Sigor@sysoev.ru         }
71153Sigor@sysoev.ru 
71253Sigor@sysoev.ru         n++;
71353Sigor@sysoev.ru     }
71453Sigor@sysoev.ru 
71553Sigor@sysoev.ru     tmcf->new_threads = n;
71653Sigor@sysoev.ru 
71753Sigor@sysoev.ru     while (n < threads) {
71853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
71953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
72053Sigor@sysoev.ru             return NXT_ERROR;
72153Sigor@sysoev.ru         }
72253Sigor@sysoev.ru 
72353Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
72453Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
72553Sigor@sysoev.ru             return NXT_ERROR;
72653Sigor@sysoev.ru         }
72753Sigor@sysoev.ru         // STUB
72853Sigor@sysoev.ru         recf->task = recf->engine->task;
72953Sigor@sysoev.ru 
730115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
73153Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
73253Sigor@sysoev.ru             return ret;
73353Sigor@sysoev.ru         }
73453Sigor@sysoev.ru 
735115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
736115Sigor@sysoev.ru 
73753Sigor@sysoev.ru         n++;
73853Sigor@sysoev.ru     }
73953Sigor@sysoev.ru 
74053Sigor@sysoev.ru     return NXT_OK;
74153Sigor@sysoev.ru }
74253Sigor@sysoev.ru 
74353Sigor@sysoev.ru 
74453Sigor@sysoev.ru static nxt_int_t
745115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
746115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
74753Sigor@sysoev.ru {
748115Sigor@sysoev.ru     nxt_mp_t               *mp;
749115Sigor@sysoev.ru     nxt_int_t              ret;
750115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
75153Sigor@sysoev.ru 
75253Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
75353Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
75453Sigor@sysoev.ru         return NXT_ERROR;
75553Sigor@sysoev.ru     }
75653Sigor@sysoev.ru 
757115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
758115Sigor@sysoev.ru 
759115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->creating,
760115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
761115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
762115Sigor@sysoev.ru         return ret;
763115Sigor@sysoev.ru     }
764115Sigor@sysoev.ru 
765115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->updating,
76653Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
76753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
76853Sigor@sysoev.ru         return ret;
76953Sigor@sysoev.ru     }
77053Sigor@sysoev.ru 
771115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
772115Sigor@sysoev.ru 
773115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
774115Sigor@sysoev.ru 
775115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
776115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
777115Sigor@sysoev.ru 
778115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
779115Sigor@sysoev.ru 
780115Sigor@sysoev.ru     return ret;
78153Sigor@sysoev.ru }
78253Sigor@sysoev.ru 
78353Sigor@sysoev.ru 
78453Sigor@sysoev.ru static nxt_int_t
785115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
786115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
78753Sigor@sysoev.ru {
788115Sigor@sysoev.ru     nxt_mp_t               *mp;
789115Sigor@sysoev.ru     nxt_int_t              ret;
790115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
79153Sigor@sysoev.ru 
79253Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
79353Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
79453Sigor@sysoev.ru         return NXT_ERROR;
79553Sigor@sysoev.ru     }
79653Sigor@sysoev.ru 
797115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
798115Sigor@sysoev.ru 
799115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->creating,
80053Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
80153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
80253Sigor@sysoev.ru         return ret;
80353Sigor@sysoev.ru     }
80453Sigor@sysoev.ru 
80553Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
80653Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
80753Sigor@sysoev.ru         return NXT_ERROR;
80853Sigor@sysoev.ru     }
80953Sigor@sysoev.ru 
810115Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, recf, &tmcf->updating,
81153Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
81253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
81353Sigor@sysoev.ru         return ret;
81453Sigor@sysoev.ru     }
81553Sigor@sysoev.ru 
81653Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
81753Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
81853Sigor@sysoev.ru         return NXT_ERROR;
81953Sigor@sysoev.ru     }
82053Sigor@sysoev.ru 
821115Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(recf, &tmcf->deleting);
822115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
823115Sigor@sysoev.ru         return ret;
824115Sigor@sysoev.ru     }
825115Sigor@sysoev.ru 
826115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
827115Sigor@sysoev.ru 
828115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
829115Sigor@sysoev.ru 
830115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
831115Sigor@sysoev.ru 
832115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
833115Sigor@sysoev.ru 
834115Sigor@sysoev.ru     return ret;
83553Sigor@sysoev.ru }
83653Sigor@sysoev.ru 
83753Sigor@sysoev.ru 
83853Sigor@sysoev.ru static nxt_int_t
839115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
840115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
84153Sigor@sysoev.ru {
84253Sigor@sysoev.ru     nxt_int_t  ret;
84353Sigor@sysoev.ru 
84453Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
84553Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
84653Sigor@sysoev.ru         return NXT_ERROR;
84753Sigor@sysoev.ru     }
84853Sigor@sysoev.ru 
849115Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(recf, &tmcf->updating);
85053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
85153Sigor@sysoev.ru         return ret;
85253Sigor@sysoev.ru     }
85353Sigor@sysoev.ru 
854115Sigor@sysoev.ru     return nxt_router_engine_joints_delete(recf, &tmcf->deleting);
85553Sigor@sysoev.ru }
85653Sigor@sysoev.ru 
85753Sigor@sysoev.ru 
85853Sigor@sysoev.ru static nxt_int_t
859115Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_engine_conf_t *recf,
860115Sigor@sysoev.ru     nxt_queue_t *sockets, nxt_array_t *array,
86153Sigor@sysoev.ru     nxt_work_handler_t handler)
86253Sigor@sysoev.ru {
86353Sigor@sysoev.ru     nxt_work_t               *work;
86453Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
86553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
86653Sigor@sysoev.ru 
86753Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
86853Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
86953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
87053Sigor@sysoev.ru     {
87153Sigor@sysoev.ru         work = nxt_array_add(array);
87253Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
87353Sigor@sysoev.ru             return NXT_ERROR;
87453Sigor@sysoev.ru         }
87553Sigor@sysoev.ru 
87653Sigor@sysoev.ru         work->next = NULL;
87753Sigor@sysoev.ru         work->handler = handler;
87853Sigor@sysoev.ru         work->task = &recf->task;
87953Sigor@sysoev.ru         work->obj = recf->engine;
88053Sigor@sysoev.ru 
88165Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
88253Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
88353Sigor@sysoev.ru             return NXT_ERROR;
88453Sigor@sysoev.ru         }
88553Sigor@sysoev.ru 
88653Sigor@sysoev.ru         work->data = joint;
88753Sigor@sysoev.ru 
88853Sigor@sysoev.ru         joint->count = 1;
88953Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
89088Smax.romanov@nginx.com         joint->engine = recf->engine;
891115Sigor@sysoev.ru 
892115Sigor@sysoev.ru         nxt_queue_insert_tail(&joint->engine->joints, &joint->link);
89353Sigor@sysoev.ru     }
89453Sigor@sysoev.ru 
89520Sigor@sysoev.ru     return NXT_OK;
89620Sigor@sysoev.ru }
89720Sigor@sysoev.ru 
89820Sigor@sysoev.ru 
899115Sigor@sysoev.ru static void
900115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
901115Sigor@sysoev.ru {
902115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
903115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
904115Sigor@sysoev.ru 
905115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
906115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
907115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
908115Sigor@sysoev.ru     {
909115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
910115Sigor@sysoev.ru         skcf->socket->count++;
911115Sigor@sysoev.ru     }
912115Sigor@sysoev.ru }
913115Sigor@sysoev.ru 
914115Sigor@sysoev.ru 
91520Sigor@sysoev.ru static nxt_int_t
916115Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_engine_conf_t *recf,
917115Sigor@sysoev.ru     nxt_queue_t *sockets)
91820Sigor@sysoev.ru {
91953Sigor@sysoev.ru     nxt_work_t        *work;
92053Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
92120Sigor@sysoev.ru 
92253Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
92353Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
92453Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
92553Sigor@sysoev.ru     {
926115Sigor@sysoev.ru         work = nxt_array_add(recf->deleting);
92753Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
92853Sigor@sysoev.ru             return NXT_ERROR;
92953Sigor@sysoev.ru         }
93020Sigor@sysoev.ru 
93153Sigor@sysoev.ru         work->next = NULL;
93253Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
93353Sigor@sysoev.ru         work->task = &recf->task;
93453Sigor@sysoev.ru         work->obj = recf->engine;
93553Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
93620Sigor@sysoev.ru     }
93720Sigor@sysoev.ru 
93853Sigor@sysoev.ru     return NXT_OK;
93953Sigor@sysoev.ru }
94020Sigor@sysoev.ru 
94120Sigor@sysoev.ru 
94253Sigor@sysoev.ru static nxt_int_t
94353Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
94453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
94553Sigor@sysoev.ru {
94653Sigor@sysoev.ru     nxt_int_t                 ret;
94753Sigor@sysoev.ru     nxt_uint_t                i, threads;
94853Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
94920Sigor@sysoev.ru 
95053Sigor@sysoev.ru     recf = tmcf->engines->elts;
95153Sigor@sysoev.ru     threads = tmcf->conf->threads;
95220Sigor@sysoev.ru 
95353Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
95453Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
95553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
95653Sigor@sysoev.ru             return ret;
95753Sigor@sysoev.ru         }
95820Sigor@sysoev.ru     }
95920Sigor@sysoev.ru 
96020Sigor@sysoev.ru     return NXT_OK;
96120Sigor@sysoev.ru }
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru 
96453Sigor@sysoev.ru static nxt_int_t
96553Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
96653Sigor@sysoev.ru     nxt_event_engine_t *engine)
96753Sigor@sysoev.ru {
96853Sigor@sysoev.ru     nxt_int_t            ret;
96988Smax.romanov@nginx.com     nxt_port_t           *port;
97088Smax.romanov@nginx.com     nxt_process_t        *process;
97153Sigor@sysoev.ru     nxt_thread_link_t    *link;
97253Sigor@sysoev.ru     nxt_thread_handle_t  handle;
97353Sigor@sysoev.ru 
97453Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
97553Sigor@sysoev.ru 
97653Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
97753Sigor@sysoev.ru         return NXT_ERROR;
97853Sigor@sysoev.ru     }
97953Sigor@sysoev.ru 
98053Sigor@sysoev.ru     link->start = nxt_router_thread_start;
98153Sigor@sysoev.ru     link->engine = engine;
98253Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
98353Sigor@sysoev.ru     link->work.task = task;
98453Sigor@sysoev.ru     link->work.data = link;
98553Sigor@sysoev.ru 
98653Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
98753Sigor@sysoev.ru 
98888Smax.romanov@nginx.com     process = nxt_runtime_process_find(rt, nxt_pid);
98988Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
99088Smax.romanov@nginx.com         return NXT_ERROR;
99188Smax.romanov@nginx.com     }
99288Smax.romanov@nginx.com 
99388Smax.romanov@nginx.com     port = nxt_process_port_new(process);
99488Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
99588Smax.romanov@nginx.com         return NXT_ERROR;
99688Smax.romanov@nginx.com     }
99788Smax.romanov@nginx.com 
99888Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
99988Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
100088Smax.romanov@nginx.com         return ret;
100188Smax.romanov@nginx.com     }
100288Smax.romanov@nginx.com 
100388Smax.romanov@nginx.com     port->engine = 0;
100488Smax.romanov@nginx.com     port->type = NXT_PROCESS_ROUTER;
100588Smax.romanov@nginx.com 
100688Smax.romanov@nginx.com     engine->port = port;
100788Smax.romanov@nginx.com 
100888Smax.romanov@nginx.com     nxt_runtime_port_add(rt, port);
100988Smax.romanov@nginx.com 
101053Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
101153Sigor@sysoev.ru 
101253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
101353Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
101453Sigor@sysoev.ru     }
101553Sigor@sysoev.ru 
101653Sigor@sysoev.ru     return ret;
101753Sigor@sysoev.ru }
101853Sigor@sysoev.ru 
101953Sigor@sysoev.ru 
102053Sigor@sysoev.ru static void
1021*133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1022*133Sigor@sysoev.ru {
1023*133Sigor@sysoev.ru     nxt_app_t         *app;
1024*133Sigor@sysoev.ru     nxt_queue_link_t  *qlk, *nqlk;
1025*133Sigor@sysoev.ru 
1026*133Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->apps);
1027*133Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->apps);
1028*133Sigor@sysoev.ru          qlk = nqlk)
1029*133Sigor@sysoev.ru     {
1030*133Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
1031*133Sigor@sysoev.ru         app = nxt_queue_link_data(qlk, nxt_app_t, link);
1032*133Sigor@sysoev.ru 
1033*133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1034*133Sigor@sysoev.ru 
1035*133Sigor@sysoev.ru         // RELEASE APP
1036*133Sigor@sysoev.ru     }
1037*133Sigor@sysoev.ru 
1038*133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1039*133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1040*133Sigor@sysoev.ru }
1041*133Sigor@sysoev.ru 
1042*133Sigor@sysoev.ru 
1043*133Sigor@sysoev.ru static void
104453Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
104553Sigor@sysoev.ru {
104653Sigor@sysoev.ru     nxt_uint_t                n;
104753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
104853Sigor@sysoev.ru 
104953Sigor@sysoev.ru     recf = tmcf->engines->elts;
105053Sigor@sysoev.ru 
105153Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
105253Sigor@sysoev.ru         nxt_router_engine_post(recf);
105353Sigor@sysoev.ru         recf++;
105453Sigor@sysoev.ru     }
105553Sigor@sysoev.ru }
105653Sigor@sysoev.ru 
105753Sigor@sysoev.ru 
105853Sigor@sysoev.ru static void
105953Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
106053Sigor@sysoev.ru {
106153Sigor@sysoev.ru     nxt_uint_t  n;
106253Sigor@sysoev.ru     nxt_work_t  *work;
1063