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