xref: /unit/src/nxt_router.c (revision 65)
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>
920Sigor@sysoev.ru 
1020Sigor@sysoev.ru 
1153Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task,
1253Sigor@sysoev.ru     nxt_router_t *router);
1353Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
1453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
1553Sigor@sysoev.ru 
1653Sigor@sysoev.ru static nxt_int_t nxt_router_stub_conf(nxt_task_t *task,
1753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
1853Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
1953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
20*65Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
21*65Sigor@sysoev.ru     nxt_sockaddr_t *sa);
2253Sigor@sysoev.ru static nxt_sockaddr_t *nxt_router_listen_sockaddr_stub(nxt_task_t *task,
23*65Sigor@sysoev.ru     nxt_mp_t *mp, uint32_t port);
2453Sigor@sysoev.ru 
2553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
2653Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
2753Sigor@sysoev.ru     const nxt_event_interface_t *interface);
28*65Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_task_t *task, nxt_mp_t *mp,
29*65Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf);
30*65Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_task_t *task, nxt_mp_t *mp,
31*65Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf);
32*65Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_task_t *task, nxt_mp_t *mp,
33*65Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf);
34*65Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_task_t *task, nxt_mp_t *mp,
35*65Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
36*65Sigor@sysoev.ru     nxt_work_handler_t handler);
3753Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_task_t *task,
3853Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array);
3953Sigor@sysoev.ru 
4053Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
4153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
4253Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
4353Sigor@sysoev.ru     nxt_event_engine_t *engine);
4453Sigor@sysoev.ru 
4553Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
4653Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
4753Sigor@sysoev.ru 
4853Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
4953Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
5053Sigor@sysoev.ru     void *data);
5153Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
5253Sigor@sysoev.ru     void *data);
5353Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
5453Sigor@sysoev.ru     void *data);
5553Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
5653Sigor@sysoev.ru     void *data);
5753Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
5853Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
5953Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
6053Sigor@sysoev.ru     void *data);
6153Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
6253Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
6353Sigor@sysoev.ru 
6453Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
6553Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
6653Sigor@sysoev.ru     void *data);
6753Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
6853Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
6953Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
7053Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
7162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
7220Sigor@sysoev.ru 
7320Sigor@sysoev.ru 
7420Sigor@sysoev.ru nxt_int_t
7520Sigor@sysoev.ru nxt_router_start(nxt_task_t *task, nxt_runtime_t *rt)
7620Sigor@sysoev.ru {
7753Sigor@sysoev.ru     nxt_int_t                    ret;
7853Sigor@sysoev.ru     nxt_router_t                 *router;
7953Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
8053Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
8153Sigor@sysoev.ru 
8253Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
8353Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
8453Sigor@sysoev.ru         return NXT_ERROR;
8553Sigor@sysoev.ru     }
8653Sigor@sysoev.ru 
8753Sigor@sysoev.ru     nxt_queue_init(&router->engines);
8853Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
8953Sigor@sysoev.ru 
9053Sigor@sysoev.ru     /**/
9153Sigor@sysoev.ru 
9253Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task, router);
9353Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
9420Sigor@sysoev.ru         return NXT_ERROR;
9520Sigor@sysoev.ru     }
9620Sigor@sysoev.ru 
9753Sigor@sysoev.ru     ret = nxt_router_stub_conf(task, tmcf);
9853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
9953Sigor@sysoev.ru         return ret;
10053Sigor@sysoev.ru     }
10153Sigor@sysoev.ru 
10253Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
10353Sigor@sysoev.ru 
10453Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
10553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
10653Sigor@sysoev.ru         return ret;
10753Sigor@sysoev.ru     }
10853Sigor@sysoev.ru 
10953Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
11053Sigor@sysoev.ru 
11153Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
11253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
11353Sigor@sysoev.ru         return ret;
11453Sigor@sysoev.ru     }
11553Sigor@sysoev.ru 
11653Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
11753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
11853Sigor@sysoev.ru         return ret;
11953Sigor@sysoev.ru     }
12053Sigor@sysoev.ru 
12153Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
12253Sigor@sysoev.ru 
12353Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
12453Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
12553Sigor@sysoev.ru 
12653Sigor@sysoev.ru     return NXT_OK;
12753Sigor@sysoev.ru }
12853Sigor@sysoev.ru 
12953Sigor@sysoev.ru 
13053Sigor@sysoev.ru static nxt_router_temp_conf_t *
13153Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task, nxt_router_t *router)
13253Sigor@sysoev.ru {
133*65Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
13453Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
13553Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
13653Sigor@sysoev.ru 
137*65Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
13853Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
13953Sigor@sysoev.ru         return NULL;
14053Sigor@sysoev.ru     }
14153Sigor@sysoev.ru 
142*65Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
14353Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
14453Sigor@sysoev.ru         goto fail;
14553Sigor@sysoev.ru     }
14653Sigor@sysoev.ru 
14753Sigor@sysoev.ru     rtcf->mem_pool = mp;
14853Sigor@sysoev.ru     rtcf->router = router;
14953Sigor@sysoev.ru     rtcf->count = 1;
15053Sigor@sysoev.ru 
151*65Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
15253Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
15353Sigor@sysoev.ru         goto fail;
15453Sigor@sysoev.ru     }
15553Sigor@sysoev.ru 
156*65Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
15753Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
15853Sigor@sysoev.ru         goto temp_fail;
15953Sigor@sysoev.ru     }
16053Sigor@sysoev.ru 
16153Sigor@sysoev.ru     tmcf->mem_pool = tmp;
16253Sigor@sysoev.ru     tmcf->conf = rtcf;
16353Sigor@sysoev.ru 
16453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
16553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
16653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
16753Sigor@sysoev.ru         goto temp_fail;
16853Sigor@sysoev.ru     }
16953Sigor@sysoev.ru 
17053Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
17153Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
17253Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
17353Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
17453Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
17553Sigor@sysoev.ru 
17653Sigor@sysoev.ru     return tmcf;
17753Sigor@sysoev.ru 
17853Sigor@sysoev.ru temp_fail:
17953Sigor@sysoev.ru 
180*65Sigor@sysoev.ru     nxt_mp_destroy(tmp);
18153Sigor@sysoev.ru 
18253Sigor@sysoev.ru fail:
18353Sigor@sysoev.ru 
184*65Sigor@sysoev.ru     nxt_mp_destroy(mp);
18553Sigor@sysoev.ru 
18653Sigor@sysoev.ru     return NULL;
18753Sigor@sysoev.ru }
18853Sigor@sysoev.ru 
18953Sigor@sysoev.ru 
19053Sigor@sysoev.ru static nxt_int_t
19153Sigor@sysoev.ru nxt_router_stub_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
19253Sigor@sysoev.ru {
193*65Sigor@sysoev.ru     nxt_mp_t           *mp;
19453Sigor@sysoev.ru     nxt_sockaddr_t     *sa;
19553Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
19653Sigor@sysoev.ru 
19753Sigor@sysoev.ru     tmcf->conf->threads = 1;
19853Sigor@sysoev.ru 
19953Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
20053Sigor@sysoev.ru 
20153Sigor@sysoev.ru     sa = nxt_router_listen_sockaddr_stub(task, mp, 8000);
20253Sigor@sysoev.ru     skcf = nxt_router_socket_conf(task, mp, sa);
20353Sigor@sysoev.ru 
20453Sigor@sysoev.ru     skcf->listen.handler = nxt_router_conn_init;
20553Sigor@sysoev.ru     skcf->header_buffer_size = 2048;
20653Sigor@sysoev.ru     skcf->large_header_buffer_size = 8192;
20753Sigor@sysoev.ru     skcf->header_read_timeout = 5000;
20853Sigor@sysoev.ru 
20953Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
21053Sigor@sysoev.ru 
21153Sigor@sysoev.ru     sa = nxt_router_listen_sockaddr_stub(task, mp, 8001);
21253Sigor@sysoev.ru     skcf = nxt_router_socket_conf(task, mp, sa);
21353Sigor@sysoev.ru 
21453Sigor@sysoev.ru     skcf->listen.handler = nxt_stream_connection_init;
21553Sigor@sysoev.ru     skcf->header_read_timeout = 5000;
21653Sigor@sysoev.ru 
21753Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
21853Sigor@sysoev.ru 
21953Sigor@sysoev.ru     return NXT_OK;
22053Sigor@sysoev.ru }
22153Sigor@sysoev.ru 
22253Sigor@sysoev.ru 
22353Sigor@sysoev.ru static nxt_socket_conf_t *
224*65Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
22553Sigor@sysoev.ru {
22653Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
22753Sigor@sysoev.ru 
228*65Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
22953Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
23053Sigor@sysoev.ru         return NULL;
23153Sigor@sysoev.ru     }
23253Sigor@sysoev.ru 
23353Sigor@sysoev.ru     conf->listen.sockaddr = sa;
23453Sigor@sysoev.ru 
23553Sigor@sysoev.ru     conf->listen.socket = -1;
23653Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
23753Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
23853Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
23953Sigor@sysoev.ru 
24053Sigor@sysoev.ru     return conf;
24153Sigor@sysoev.ru }
24253Sigor@sysoev.ru 
24353Sigor@sysoev.ru 
24453Sigor@sysoev.ru static nxt_sockaddr_t *
245*65Sigor@sysoev.ru nxt_router_listen_sockaddr_stub(nxt_task_t *task, nxt_mp_t *mp, uint32_t port)
24653Sigor@sysoev.ru {
24753Sigor@sysoev.ru     nxt_sockaddr_t      *sa;
24853Sigor@sysoev.ru     struct sockaddr_in  sin;
24953Sigor@sysoev.ru 
25053Sigor@sysoev.ru     nxt_memzero(&sin, sizeof(struct sockaddr_in));
25153Sigor@sysoev.ru 
25253Sigor@sysoev.ru     sin.sin_family = AF_INET;
25353Sigor@sysoev.ru     sin.sin_port = htons(port);
25453Sigor@sysoev.ru 
25553Sigor@sysoev.ru     sa = nxt_sockaddr_create(mp, (struct sockaddr *) &sin,
25653Sigor@sysoev.ru                              sizeof(struct sockaddr_in), NXT_INET_ADDR_STR_LEN);
25753Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
25853Sigor@sysoev.ru         return NULL;
25953Sigor@sysoev.ru     }
26053Sigor@sysoev.ru 
26153Sigor@sysoev.ru     sa->type = SOCK_STREAM;
26253Sigor@sysoev.ru 
26353Sigor@sysoev.ru     nxt_sockaddr_text(sa);
26453Sigor@sysoev.ru 
26553Sigor@sysoev.ru     return sa;
26653Sigor@sysoev.ru }
26753Sigor@sysoev.ru 
26853Sigor@sysoev.ru 
26953Sigor@sysoev.ru static void
27053Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
27153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
27253Sigor@sysoev.ru {
27353Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
27453Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
27553Sigor@sysoev.ru 
27653Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
27753Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
27853Sigor@sysoev.ru          nqlk = next)
27953Sigor@sysoev.ru     {
28053Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
28153Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
28253Sigor@sysoev.ru 
28353Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
28453Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
28553Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
28653Sigor@sysoev.ru         {
28753Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
28853Sigor@sysoev.ru 
28953Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->listen.sockaddr,
29053Sigor@sysoev.ru                                  oskcf->listen.sockaddr))
29153Sigor@sysoev.ru             {
29253Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
29353Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
29453Sigor@sysoev.ru 
29553Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
29653Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
29753Sigor@sysoev.ru 
29853Sigor@sysoev.ru                 break;
29953Sigor@sysoev.ru             }
30053Sigor@sysoev.ru         }
30153Sigor@sysoev.ru     }
30253Sigor@sysoev.ru 
30353Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
30453Sigor@sysoev.ru }
30553Sigor@sysoev.ru 
30653Sigor@sysoev.ru 
30753Sigor@sysoev.ru static nxt_int_t
30853Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
30953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
31053Sigor@sysoev.ru {
31153Sigor@sysoev.ru     nxt_queue_link_t   *qlk, *nqlk;
31253Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
31353Sigor@sysoev.ru 
31453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
31553Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
31653Sigor@sysoev.ru          qlk = nqlk)
31753Sigor@sysoev.ru     {
31853Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
31953Sigor@sysoev.ru 
32053Sigor@sysoev.ru         if (nxt_listen_socket_create(task, &skcf->listen, 0) != NXT_OK) {
32153Sigor@sysoev.ru             return NXT_ERROR;
32253Sigor@sysoev.ru         }
32353Sigor@sysoev.ru 
32453Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
32553Sigor@sysoev.ru         nxt_queue_remove(qlk);
32653Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
32753Sigor@sysoev.ru     }
32853Sigor@sysoev.ru 
32953Sigor@sysoev.ru     return NXT_OK;
33053Sigor@sysoev.ru }
33153Sigor@sysoev.ru 
33253Sigor@sysoev.ru 
33353Sigor@sysoev.ru static nxt_int_t
33453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
33553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
33653Sigor@sysoev.ru {
337*65Sigor@sysoev.ru     nxt_mp_t                  *mp;
33853Sigor@sysoev.ru     nxt_int_t                 ret;
33953Sigor@sysoev.ru     nxt_uint_t                n, threads;
34053Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
34153Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
34253Sigor@sysoev.ru 
34353Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
34453Sigor@sysoev.ru     threads = tmcf->conf->threads;
34553Sigor@sysoev.ru 
34653Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
34753Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
34853Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
34953Sigor@sysoev.ru         return NXT_ERROR;
35053Sigor@sysoev.ru     }
35153Sigor@sysoev.ru 
35253Sigor@sysoev.ru     n = 0;
35353Sigor@sysoev.ru 
35453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
35553Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
35653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
35753Sigor@sysoev.ru     {
35853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
35953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
36053Sigor@sysoev.ru             return NXT_ERROR;
36153Sigor@sysoev.ru         }
36253Sigor@sysoev.ru 
36353Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link);
36453Sigor@sysoev.ru         // STUB
36553Sigor@sysoev.ru         recf->task = recf->engine->task;
36653Sigor@sysoev.ru 
36753Sigor@sysoev.ru         if (n < threads) {
36853Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(task, mp, tmcf, recf);
36953Sigor@sysoev.ru 
37053Sigor@sysoev.ru         } else {
37153Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(task, mp, tmcf, recf);
37253Sigor@sysoev.ru         }
37353Sigor@sysoev.ru 
37453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
37553Sigor@sysoev.ru             return ret;
37653Sigor@sysoev.ru         }
37753Sigor@sysoev.ru 
37853Sigor@sysoev.ru         n++;
37953Sigor@sysoev.ru     }
38053Sigor@sysoev.ru 
38153Sigor@sysoev.ru     tmcf->new_threads = n;
38253Sigor@sysoev.ru 
38353Sigor@sysoev.ru     while (n < threads) {
38453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
38553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
38653Sigor@sysoev.ru             return NXT_ERROR;
38753Sigor@sysoev.ru         }
38853Sigor@sysoev.ru 
38953Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
39053Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
39153Sigor@sysoev.ru             return NXT_ERROR;
39253Sigor@sysoev.ru         }
39353Sigor@sysoev.ru         // STUB
39453Sigor@sysoev.ru         recf->task = recf->engine->task;
39553Sigor@sysoev.ru 
39653Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(task, mp, tmcf, recf);
39753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
39853Sigor@sysoev.ru             return ret;
39953Sigor@sysoev.ru         }
40053Sigor@sysoev.ru 
40153Sigor@sysoev.ru         n++;
40253Sigor@sysoev.ru     }
40353Sigor@sysoev.ru 
40453Sigor@sysoev.ru     return NXT_OK;
40553Sigor@sysoev.ru }
40653Sigor@sysoev.ru 
40753Sigor@sysoev.ru 
40853Sigor@sysoev.ru static nxt_int_t
409*65Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_task_t *task, nxt_mp_t *mp,
41053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
41153Sigor@sysoev.ru {
41253Sigor@sysoev.ru     nxt_int_t  ret;
41353Sigor@sysoev.ru 
41453Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
41553Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
41653Sigor@sysoev.ru         return NXT_ERROR;
41753Sigor@sysoev.ru     }
41853Sigor@sysoev.ru 
41953Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->creating,
42053Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
42153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
42253Sigor@sysoev.ru         return ret;
42353Sigor@sysoev.ru     }
42453Sigor@sysoev.ru 
42553Sigor@sysoev.ru     return nxt_router_engine_joints_create(task, mp, recf, &tmcf->updating,
42653Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
42753Sigor@sysoev.ru }
42853Sigor@sysoev.ru 
42953Sigor@sysoev.ru 
43053Sigor@sysoev.ru static nxt_int_t
431*65Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_task_t *task, nxt_mp_t *mp,
43253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
43353Sigor@sysoev.ru {
43453Sigor@sysoev.ru     nxt_int_t  ret;
43553Sigor@sysoev.ru 
43653Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
43753Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
43853Sigor@sysoev.ru         return NXT_ERROR;
43953Sigor@sysoev.ru     }
44053Sigor@sysoev.ru 
44153Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->creating,
44253Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
44353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
44453Sigor@sysoev.ru         return ret;
44553Sigor@sysoev.ru     }
44653Sigor@sysoev.ru 
44753Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
44853Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
44953Sigor@sysoev.ru         return NXT_ERROR;
45053Sigor@sysoev.ru     }
45153Sigor@sysoev.ru 
45253Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(task, mp, recf, &tmcf->updating,
45353Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
45453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
45553Sigor@sysoev.ru         return ret;
45653Sigor@sysoev.ru     }
45753Sigor@sysoev.ru 
45853Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
45953Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
46053Sigor@sysoev.ru         return NXT_ERROR;
46153Sigor@sysoev.ru     }
46253Sigor@sysoev.ru 
46353Sigor@sysoev.ru     return nxt_router_engine_joints_delete(task, recf, &tmcf->deleting,
46453Sigor@sysoev.ru                                            recf->deleting);
46553Sigor@sysoev.ru }
46653Sigor@sysoev.ru 
46753Sigor@sysoev.ru 
46853Sigor@sysoev.ru static nxt_int_t
469*65Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_task_t *task, nxt_mp_t *mp,
47053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf)
47153Sigor@sysoev.ru {
47253Sigor@sysoev.ru     nxt_int_t  ret;
47353Sigor@sysoev.ru 
47453Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
47553Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
47653Sigor@sysoev.ru         return NXT_ERROR;
47753Sigor@sysoev.ru     }
47853Sigor@sysoev.ru 
47953Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(task, recf, &tmcf->updating,
48053Sigor@sysoev.ru                                           recf->deleting);
48153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
48253Sigor@sysoev.ru         return ret;
48353Sigor@sysoev.ru     }
48453Sigor@sysoev.ru 
48553Sigor@sysoev.ru     return nxt_router_engine_joints_delete(task, recf, &tmcf->deleting,
48653Sigor@sysoev.ru                                            recf->deleting);
48753Sigor@sysoev.ru }
48853Sigor@sysoev.ru 
48953Sigor@sysoev.ru 
49053Sigor@sysoev.ru static nxt_int_t
491*65Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_task_t *task, nxt_mp_t *mp,
49253Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
49353Sigor@sysoev.ru     nxt_work_handler_t handler)
49453Sigor@sysoev.ru {
49553Sigor@sysoev.ru     nxt_work_t               *work;
49653Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
49753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
49853Sigor@sysoev.ru 
49953Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
50053Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
50153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
50253Sigor@sysoev.ru     {
50353Sigor@sysoev.ru         work = nxt_array_add(array);
50453Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
50553Sigor@sysoev.ru             return NXT_ERROR;
50653Sigor@sysoev.ru         }
50753Sigor@sysoev.ru 
50853Sigor@sysoev.ru         work->next = NULL;
50953Sigor@sysoev.ru         work->handler = handler;
51053Sigor@sysoev.ru         work->task = &recf->task;
51153Sigor@sysoev.ru         work->obj = recf->engine;
51253Sigor@sysoev.ru 
513*65Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
51453Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
51553Sigor@sysoev.ru             return NXT_ERROR;
51653Sigor@sysoev.ru         }
51753Sigor@sysoev.ru 
51853Sigor@sysoev.ru         work->data = joint;
51953Sigor@sysoev.ru 
52053Sigor@sysoev.ru         joint->count = 1;
52153Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
52253Sigor@sysoev.ru     }
52353Sigor@sysoev.ru 
52420Sigor@sysoev.ru     return NXT_OK;
52520Sigor@sysoev.ru }
52620Sigor@sysoev.ru 
52720Sigor@sysoev.ru 
52820Sigor@sysoev.ru static nxt_int_t
52953Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_task_t *task,
53053Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array)
53120Sigor@sysoev.ru {
53253Sigor@sysoev.ru     nxt_work_t        *work;
53353Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
53420Sigor@sysoev.ru 
53553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
53653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
53753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
53853Sigor@sysoev.ru     {
53953Sigor@sysoev.ru         work = nxt_array_add(array);
54053Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
54153Sigor@sysoev.ru             return NXT_ERROR;
54253Sigor@sysoev.ru         }
54320Sigor@sysoev.ru 
54453Sigor@sysoev.ru         work->next = NULL;
54553Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
54653Sigor@sysoev.ru         work->task = &recf->task;
54753Sigor@sysoev.ru         work->obj = recf->engine;
54853Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
54920Sigor@sysoev.ru     }
55020Sigor@sysoev.ru 
55153Sigor@sysoev.ru     return NXT_OK;
55253Sigor@sysoev.ru }
55320Sigor@sysoev.ru 
55420Sigor@sysoev.ru 
55553Sigor@sysoev.ru static nxt_int_t
55653Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
55753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
55853Sigor@sysoev.ru {
55953Sigor@sysoev.ru     nxt_int_t                 ret;
56053Sigor@sysoev.ru     nxt_uint_t                i, threads;
56153Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
56220Sigor@sysoev.ru 
56353Sigor@sysoev.ru     recf = tmcf->engines->elts;
56453Sigor@sysoev.ru     threads = tmcf->conf->threads;
56520Sigor@sysoev.ru 
56653Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
56753Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
56853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
56953Sigor@sysoev.ru             return ret;
57053Sigor@sysoev.ru         }
57120Sigor@sysoev.ru     }
57220Sigor@sysoev.ru 
57320Sigor@sysoev.ru     return NXT_OK;
57420Sigor@sysoev.ru }
57553Sigor@sysoev.ru 
57653Sigor@sysoev.ru 
57753Sigor@sysoev.ru static nxt_int_t
57853Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
57953Sigor@sysoev.ru     nxt_event_engine_t *engine)
58053Sigor@sysoev.ru {
58153Sigor@sysoev.ru     nxt_int_t            ret;
58253Sigor@sysoev.ru     nxt_thread_link_t    *link;
58353Sigor@sysoev.ru     nxt_thread_handle_t  handle;
58453Sigor@sysoev.ru 
58553Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
58653Sigor@sysoev.ru 
58753Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
58853Sigor@sysoev.ru         return NXT_ERROR;
58953Sigor@sysoev.ru     }
59053Sigor@sysoev.ru 
59153Sigor@sysoev.ru     link->start = nxt_router_thread_start;
59253Sigor@sysoev.ru     link->engine = engine;
59353Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
59453Sigor@sysoev.ru     link->work.task = task;
59553Sigor@sysoev.ru     link->work.data = link;
59653Sigor@sysoev.ru 
59753Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
59853Sigor@sysoev.ru 
59953Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
60053Sigor@sysoev.ru 
60153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
60253Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
60353Sigor@sysoev.ru     }
60453Sigor@sysoev.ru 
60553Sigor@sysoev.ru     return ret;
60653Sigor@sysoev.ru }
60753Sigor@sysoev.ru 
60853Sigor@sysoev.ru 
60953Sigor@sysoev.ru static void
61053Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
61153Sigor@sysoev.ru {
61253Sigor@sysoev.ru     nxt_uint_t                n;
61353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
61453Sigor@sysoev.ru 
61553Sigor@sysoev.ru     recf = tmcf->engines->elts;
61653Sigor@sysoev.ru 
61753Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
61853Sigor@sysoev.ru         nxt_router_engine_post(recf);
61953Sigor@sysoev.ru         recf++;
62053Sigor@sysoev.ru     }
62153Sigor@sysoev.ru }
62253Sigor@sysoev.ru 
62353Sigor@sysoev.ru 
62453Sigor@sysoev.ru static void
62553Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
62653Sigor@sysoev.ru {
62753Sigor@sysoev.ru     nxt_uint_t  n;
62853Sigor@sysoev.ru     nxt_work_t  *work;
62953Sigor@sysoev.ru 
63053Sigor@sysoev.ru     work = recf->creating->elts;
63153Sigor@sysoev.ru 
63253Sigor@sysoev.ru     for (n = recf->creating->nelts; n != 0; n--) {
63353Sigor@sysoev.ru         nxt_event_engine_post(recf->engine, work);
63453Sigor@sysoev.ru         work++;
63553Sigor@sysoev.ru     }
63653Sigor@sysoev.ru }
63753Sigor@sysoev.ru 
63853Sigor@sysoev.ru 
63953Sigor@sysoev.ru static void
64053Sigor@sysoev.ru nxt_router_thread_start(void *data)
64153Sigor@sysoev.ru {
64253Sigor@sysoev.ru     nxt_thread_t        *thread;
64353Sigor@sysoev.ru     nxt_thread_link_t   *link;
64453Sigor@sysoev.ru     nxt_event_engine_t  *engine;
64553Sigor@sysoev.ru 
64653Sigor@sysoev.ru     link = data;
64753Sigor@sysoev.ru     engine = link->engine;
64853Sigor@sysoev.ru 
64953Sigor@sysoev.ru     thread = nxt_thread();
65053Sigor@sysoev.ru 
65153Sigor@sysoev.ru     /* STUB */
65253Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
65353Sigor@sysoev.ru 
65453Sigor@sysoev.ru     engine->task.thread = thread;
65553Sigor@sysoev.ru     engine->task.log = thread->log;
65653Sigor@sysoev.ru     thread->engine = engine;
65763Sigor@sysoev.ru     thread->task = &engine->task;
65853Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
65953Sigor@sysoev.ru 
66063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
66153Sigor@sysoev.ru 
66253Sigor@sysoev.ru     nxt_event_engine_start(engine);
66353Sigor@sysoev.ru }
66453Sigor@sysoev.ru 
66553Sigor@sysoev.ru 
66653Sigor@sysoev.ru static void
66753Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
66853Sigor@sysoev.ru {
66953Sigor@sysoev.ru     nxt_listen_event_t       *listen;
67053Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
67153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
67253Sigor@sysoev.ru 
67353Sigor@sysoev.ru     joint = data;
67453Sigor@sysoev.ru 
67553Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
67653Sigor@sysoev.ru 
67753Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
67853Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
67953Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
68053Sigor@sysoev.ru         return;
68153Sigor@sysoev.ru     }
68253Sigor@sysoev.ru 
68353Sigor@sysoev.ru     listen->socket.data = joint;
68453Sigor@sysoev.ru }
68553Sigor@sysoev.ru 
68653Sigor@sysoev.ru 
68753Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
68853Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
68953Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
69053Sigor@sysoev.ru {
69153Sigor@sysoev.ru     nxt_socket_t        socket;
69253Sigor@sysoev.ru     nxt_queue_link_t    *link;
69353Sigor@sysoev.ru     nxt_listen_event_t  *listen;
69453Sigor@sysoev.ru 
69553Sigor@sysoev.ru     socket = skcf->listen.socket;
69653Sigor@sysoev.ru 
69753Sigor@sysoev.ru     for (link = nxt_queue_first(listen_connections);
69853Sigor@sysoev.ru          link != nxt_queue_tail(listen_connections);
69953Sigor@sysoev.ru          link = nxt_queue_next(link))
70053Sigor@sysoev.ru     {
70153Sigor@sysoev.ru         listen = nxt_queue_link_data(link, nxt_listen_event_t, link);
70253Sigor@sysoev.ru 
70353Sigor@sysoev.ru         if (socket == listen->socket.fd) {
70453Sigor@sysoev.ru             return listen;
70553Sigor@sysoev.ru         }
70653Sigor@sysoev.ru     }
70753Sigor@sysoev.ru 
70853Sigor@sysoev.ru     return NULL;
70953Sigor@sysoev.ru }
71053Sigor@sysoev.ru 
71153Sigor@sysoev.ru 
71253Sigor@sysoev.ru static void
71353Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
71453Sigor@sysoev.ru {
71553Sigor@sysoev.ru     nxt_event_engine_t       *engine;
71653Sigor@sysoev.ru     nxt_listen_event_t       *listen;
71753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
71853Sigor@sysoev.ru 
71953Sigor@sysoev.ru     engine = obj;
72053Sigor@sysoev.ru     joint = data;
72153Sigor@sysoev.ru 
72253Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
72353Sigor@sysoev.ru                                      joint->socket_conf);
72453Sigor@sysoev.ru 
72553Sigor@sysoev.ru     old = listen->socket.data;
72653Sigor@sysoev.ru     listen->socket.data = joint;
72753Sigor@sysoev.ru 
72853Sigor@sysoev.ru     nxt_router_conf_release(task, old);
72953Sigor@sysoev.ru }
73053Sigor@sysoev.ru 
73153Sigor@sysoev.ru 
73253Sigor@sysoev.ru static void
73353Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
73453Sigor@sysoev.ru {
73553Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
73653Sigor@sysoev.ru     nxt_listen_event_t  *listen;
73753Sigor@sysoev.ru     nxt_event_engine_t  *engine;
73853Sigor@sysoev.ru 
73953Sigor@sysoev.ru     engine = obj;
74053Sigor@sysoev.ru     skcf = data;
74153Sigor@sysoev.ru 
74253Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
74353Sigor@sysoev.ru 
74453Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
74553Sigor@sysoev.ru 
74653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
74753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
74853Sigor@sysoev.ru 
74953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
75053Sigor@sysoev.ru }
75153Sigor@sysoev.ru 
75253Sigor@sysoev.ru 
75353Sigor@sysoev.ru static void
75453Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
75553Sigor@sysoev.ru {
75653Sigor@sysoev.ru     nxt_timer_t              *timer;
75753Sigor@sysoev.ru     nxt_listen_event_t       *listen;
75853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
75953Sigor@sysoev.ru 
76053Sigor@sysoev.ru     timer = obj;
76153Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
76253Sigor@sysoev.ru     joint = listen->socket.data;
76353Sigor@sysoev.ru 
76453Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
76553Sigor@sysoev.ru     nxt_free(listen);
76653Sigor@sysoev.ru 
76753Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
76853Sigor@sysoev.ru }
76953Sigor@sysoev.ru 
77053Sigor@sysoev.ru 
77153Sigor@sysoev.ru static void
77253Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
77353Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
77453Sigor@sysoev.ru {
77553Sigor@sysoev.ru     nxt_socket_t           s;
77653Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
77753Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
77853Sigor@sysoev.ru 
77953Sigor@sysoev.ru     s = -1;
78053Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
78153Sigor@sysoev.ru     lock = &joint->socket_conf->router_conf->router->lock;
78253Sigor@sysoev.ru 
78353Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
78453Sigor@sysoev.ru 
78553Sigor@sysoev.ru     if (--ls->count == 0) {
78653Sigor@sysoev.ru         s = ls->socket;
78753Sigor@sysoev.ru         ls->socket = -1;
78853Sigor@sysoev.ru     }
78953Sigor@sysoev.ru 
79053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
79153Sigor@sysoev.ru 
79253Sigor@sysoev.ru     if (s != -1) {
79353Sigor@sysoev.ru         nxt_socket_close(task, s);
79453Sigor@sysoev.ru     }
79553Sigor@sysoev.ru 
79653Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
79753Sigor@sysoev.ru }
79853Sigor@sysoev.ru 
79953Sigor@sysoev.ru 
80053Sigor@sysoev.ru static void
80153Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
80253Sigor@sysoev.ru {
80353Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
80453Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
80553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
80653Sigor@sysoev.ru 
80753Sigor@sysoev.ru     nxt_debug(task, "conf joint count: %D", joint->count);
80853Sigor@sysoev.ru 
80953Sigor@sysoev.ru     if (--joint->count != 0) {
81053Sigor@sysoev.ru         return;
81153Sigor@sysoev.ru     }
81253Sigor@sysoev.ru 
81353Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
81453Sigor@sysoev.ru 
81553Sigor@sysoev.ru     skcf = joint->socket_conf;
81653Sigor@sysoev.ru     rtcf = skcf->router_conf;
81753Sigor@sysoev.ru     lock = &rtcf->router->lock;
81853Sigor@sysoev.ru 
81953Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
82053Sigor@sysoev.ru 
82153Sigor@sysoev.ru     if (--skcf->count != 0) {
82253Sigor@sysoev.ru         rtcf = NULL;
82353Sigor@sysoev.ru 
82453Sigor@sysoev.ru     } else {
82553Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
82653Sigor@sysoev.ru 
82753Sigor@sysoev.ru         if (--rtcf->count != 0) {
82853Sigor@sysoev.ru             rtcf = NULL;
82953Sigor@sysoev.ru         }
83053Sigor@sysoev.ru     }
83153Sigor@sysoev.ru 
83253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
83353Sigor@sysoev.ru 
83453Sigor@sysoev.ru     if (rtcf != NULL) {
835*65Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
83653Sigor@sysoev.ru     }
83753Sigor@sysoev.ru 
83853Sigor@sysoev.ru     if (nxt_queue_is_empty(&joint->engine->joints)) {
83953Sigor@sysoev.ru         nxt_thread_exit(task->thread);
84053Sigor@sysoev.ru     }
84153Sigor@sysoev.ru }
84253Sigor@sysoev.ru 
84353Sigor@sysoev.ru 
84453Sigor@sysoev.ru static void
84553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
84653Sigor@sysoev.ru {
84753Sigor@sysoev.ru     nxt_thread_link_t    *link;
84853Sigor@sysoev.ru     nxt_event_engine_t   *engine;
84953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
85053Sigor@sysoev.ru 
85158Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
85253Sigor@sysoev.ru     link = data;
85353Sigor@sysoev.ru 
85453Sigor@sysoev.ru     nxt_thread_wait(handle);
85553Sigor@sysoev.ru 
85653Sigor@sysoev.ru     engine = link->engine;
85753Sigor@sysoev.ru 
85853Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
85953Sigor@sysoev.ru 
86063Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
86153Sigor@sysoev.ru 
86253Sigor@sysoev.ru     nxt_event_engine_free(engine);
86353Sigor@sysoev.ru 
86453Sigor@sysoev.ru     nxt_free(link);
86553Sigor@sysoev.ru 
86653Sigor@sysoev.ru     // TODO: free port
86753Sigor@sysoev.ru }
86853Sigor@sysoev.ru 
86953Sigor@sysoev.ru 
87062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_read_state
87153Sigor@sysoev.ru     nxt_aligned(64) =
87253Sigor@sysoev.ru {
87353Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
87453Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
87553Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
87653Sigor@sysoev.ru 
87753Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
87853Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
87953Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
88053Sigor@sysoev.ru };
88153Sigor@sysoev.ru 
88253Sigor@sysoev.ru 
88353Sigor@sysoev.ru static void
88453Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
88553Sigor@sysoev.ru {
88653Sigor@sysoev.ru     size_t                   size;
88762Sigor@sysoev.ru     nxt_conn_t               *c;
88853Sigor@sysoev.ru     nxt_event_engine_t       *engine;
88953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
89053Sigor@sysoev.ru 
89153Sigor@sysoev.ru     c = obj;
89253Sigor@sysoev.ru     joint = data;
89353Sigor@sysoev.ru 
89453Sigor@sysoev.ru     nxt_debug(task, "router conn init");
89553Sigor@sysoev.ru 
89653Sigor@sysoev.ru     joint->count++;
89753Sigor@sysoev.ru 
89853Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
89953Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
90053Sigor@sysoev.ru 
90153Sigor@sysoev.ru     c->socket.data = NULL;
90253Sigor@sysoev.ru 
90353Sigor@sysoev.ru     engine = task->thread->engine;
90453Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
90553Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
90653Sigor@sysoev.ru 
90753Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
90853Sigor@sysoev.ru 
90962Sigor@sysoev.ru     nxt_conn_read(engine, c);
91053Sigor@sysoev.ru }
91153Sigor@sysoev.ru 
91253Sigor@sysoev.ru 
91362Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
91453Sigor@sysoev.ru     nxt_aligned(64) =
91553Sigor@sysoev.ru {
91653Sigor@sysoev.ru     .ready_handler = nxt_router_conn_close,
91753Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
91853Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
91953Sigor@sysoev.ru };
92053Sigor@sysoev.ru 
92153Sigor@sysoev.ru 
92253Sigor@sysoev.ru static void
92353Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
92453Sigor@sysoev.ru {
92553Sigor@sysoev.ru     size_t                    size;
92653Sigor@sysoev.ru     nxt_int_t                 ret;
92753Sigor@sysoev.ru     nxt_buf_t                 *b;
92862Sigor@sysoev.ru     nxt_conn_t                *c;
92953Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
93053Sigor@sysoev.ru     nxt_http_request_parse_t  *rp;
93153Sigor@sysoev.ru 
93253Sigor@sysoev.ru     c = obj;
93353Sigor@sysoev.ru     rp = data;
93453Sigor@sysoev.ru 
93553Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
93653Sigor@sysoev.ru 
93753Sigor@sysoev.ru     if (rp == NULL) {
938*65Sigor@sysoev.ru         rp = nxt_mp_zget(c->mem_pool, sizeof(nxt_http_request_parse_t));
93953Sigor@sysoev.ru         if (nxt_slow_path(rp == NULL)) {
94053Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
94153Sigor@sysoev.ru             return;
94253Sigor@sysoev.ru         }
94353Sigor@sysoev.ru 
94453Sigor@sysoev.ru         c->socket.data = rp;
94561Sigor@sysoev.ru 
94661Sigor@sysoev.ru         ret = nxt_http_parse_request_init(rp, c->mem_pool);
94761Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
94861Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
94961Sigor@sysoev.ru             return;
95061Sigor@sysoev.ru         }
95153Sigor@sysoev.ru     }
95253Sigor@sysoev.ru 
95353Sigor@sysoev.ru     ret = nxt_http_parse_request(rp, &c->read->mem);
95453Sigor@sysoev.ru 
95553Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
95653Sigor@sysoev.ru 
95753Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
95853Sigor@sysoev.ru 
95953Sigor@sysoev.ru     case NXT_DONE:
96053Sigor@sysoev.ru         break;
96153Sigor@sysoev.ru 
96253Sigor@sysoev.ru     case NXT_ERROR:
96353Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
96453Sigor@sysoev.ru         return;
96553Sigor@sysoev.ru 
96653Sigor@sysoev.ru     default:  /* NXT_AGAIN */
96753Sigor@sysoev.ru 
96853Sigor@sysoev.ru         if (c->read->mem.free == c->read->mem.end) {
96953Sigor@sysoev.ru             joint = c->listen->socket.data;
97053Sigor@sysoev.ru             size = joint->socket_conf->large_header_buffer_size,
97153Sigor@sysoev.ru 
97253Sigor@sysoev.ru             b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
97353Sigor@sysoev.ru             if (nxt_slow_path(b == NULL)) {
97453Sigor@sysoev.ru                 nxt_router_conn_close(task, c, data);
97553Sigor@sysoev.ru                 return;
97653Sigor@sysoev.ru             }
97753Sigor@sysoev.ru 
97853Sigor@sysoev.ru             size = c->read->mem.free - c->read->mem.pos;
97953Sigor@sysoev.ru             nxt_memcpy(b->mem.pos, c->read->mem.pos, size);
98053Sigor@sysoev.ru 
98153Sigor@sysoev.ru             b->mem.free += size;
98253Sigor@sysoev.ru             c->read = b;
98353Sigor@sysoev.ru         }
98453Sigor@sysoev.ru 
98562Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
98653Sigor@sysoev.ru         return;
98753Sigor@sysoev.ru     }
98853Sigor@sysoev.ru 
98953Sigor@sysoev.ru     c->write = c->read;
99053Sigor@sysoev.ru     c->write->mem.pos = c->write->mem.start;
99153Sigor@sysoev.ru     c->write_state = &nxt_router_conn_write_state;
99253Sigor@sysoev.ru 
99362Sigor@sysoev.ru     nxt_conn_write(task->thread->engine, c);
99453Sigor@sysoev.ru }
99553Sigor@sysoev.ru 
99653Sigor@sysoev.ru 
99762Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
99853Sigor@sysoev.ru     nxt_aligned(64) =
99953Sigor@sysoev.ru {
100053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
100153Sigor@sysoev.ru };
100253Sigor@sysoev.ru 
100353Sigor@sysoev.ru 
100453Sigor@sysoev.ru static void
100553Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
100653Sigor@sysoev.ru {
100762Sigor@sysoev.ru     nxt_conn_t  *c;
100853Sigor@sysoev.ru 
100953Sigor@sysoev.ru     c = obj;
101053Sigor@sysoev.ru 
101153Sigor@sysoev.ru     nxt_debug(task, "router conn close");
101253Sigor@sysoev.ru 
101353Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
101453Sigor@sysoev.ru 
101562Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
101653Sigor@sysoev.ru }
101753Sigor@sysoev.ru 
101853Sigor@sysoev.ru 
101953Sigor@sysoev.ru static void
102053Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
102153Sigor@sysoev.ru {
102262Sigor@sysoev.ru     nxt_conn_t               *c;
102353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
102453Sigor@sysoev.ru 
102553Sigor@sysoev.ru     c = obj;
102653Sigor@sysoev.ru 
102753Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
102853Sigor@sysoev.ru 
102953Sigor@sysoev.ru     joint = c->listen->socket.data;
103053Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
103153Sigor@sysoev.ru 
1032*65Sigor@sysoev.ru     nxt_mp_destroy(c->mem_pool);
103353Sigor@sysoev.ru }
103453Sigor@sysoev.ru 
103553Sigor@sysoev.ru 
103653Sigor@sysoev.ru static void
103753Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
103853Sigor@sysoev.ru {
103962Sigor@sysoev.ru     nxt_conn_t  *c;
104053Sigor@sysoev.ru 
104153Sigor@sysoev.ru     c = obj;
104253Sigor@sysoev.ru 
104353Sigor@sysoev.ru     nxt_debug(task, "router conn error");
104453Sigor@sysoev.ru 
104553Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
104653Sigor@sysoev.ru 
104762Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
104853Sigor@sysoev.ru }
104953Sigor@sysoev.ru 
105053Sigor@sysoev.ru 
105153Sigor@sysoev.ru static void
105253Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
105353Sigor@sysoev.ru {
105462Sigor@sysoev.ru     nxt_conn_t   *c;
105562Sigor@sysoev.ru     nxt_timer_t  *timer;
105653Sigor@sysoev.ru 
105753Sigor@sysoev.ru     timer = obj;
105853Sigor@sysoev.ru 
105953Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
106053Sigor@sysoev.ru 
106162Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
106253Sigor@sysoev.ru 
106353Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
106453Sigor@sysoev.ru 
106562Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
106653Sigor@sysoev.ru }
106753Sigor@sysoev.ru 
106853Sigor@sysoev.ru 
106953Sigor@sysoev.ru static nxt_msec_t
107062Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
107153Sigor@sysoev.ru {
107253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
107353