xref: /unit/src/nxt_router.c (revision 139)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13133Sigor@sysoev.ru     nxt_str_t  type;
14133Sigor@sysoev.ru     uint32_t   workers;
15133Sigor@sysoev.ru } nxt_router_app_conf_t;
16133Sigor@sysoev.ru 
17133Sigor@sysoev.ru 
18133Sigor@sysoev.ru typedef struct {
19133Sigor@sysoev.ru     nxt_str_t  application;
20115Sigor@sysoev.ru } nxt_router_listener_conf_t;
21115Sigor@sysoev.ru 
22115Sigor@sysoev.ru 
23*139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
24*139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
25*139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
26*139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
27*139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
28*139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
29*139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
30*139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
31*139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, size_t size);
32*139Sigor@sysoev.ru static void nxt_router_conf_buf_completion(nxt_task_t *task, void *obj,
33*139Sigor@sysoev.ru     void *data);
3453Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
3553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
3653Sigor@sysoev.ru 
37115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
38115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
39133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
40133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
41133Sigor@sysoev.ru     nxt_str_t *name);
4253Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
4353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
4465Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
4565Sigor@sysoev.ru     nxt_sockaddr_t *sa);
4653Sigor@sysoev.ru 
4753Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
4853Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
4953Sigor@sysoev.ru     const nxt_event_interface_t *interface);
50115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
51115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
52115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
53115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
54115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
55115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
56115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
57115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_mp_t *mp,
58*139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf,
59*139Sigor@sysoev.ru     nxt_queue_t *sockets, nxt_array_t *array, nxt_work_handler_t handler);
60*139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
61*139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
6253Sigor@sysoev.ru 
6353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
6453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
6653Sigor@sysoev.ru     nxt_event_engine_t *engine);
67133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
68133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6953Sigor@sysoev.ru 
7053Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
71*139Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_temp_conf_t *tmcf,
72*139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
7353Sigor@sysoev.ru 
7453Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
7553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
7653Sigor@sysoev.ru     void *data);
7753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
7853Sigor@sysoev.ru     void *data);
7953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
8053Sigor@sysoev.ru     void *data);
8153Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
8253Sigor@sysoev.ru     void *data);
8353Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
8453Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
8553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
8653Sigor@sysoev.ru     void *data);
8753Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
8853Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
8953Sigor@sysoev.ru 
9053Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
9153Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
9253Sigor@sysoev.ru     void *data);
9388Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
9488Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
9588Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
9653Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
9753Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
9853Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
9953Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
10062Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
10120Sigor@sysoev.ru 
102119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
10320Sigor@sysoev.ru 
10420Sigor@sysoev.ru nxt_int_t
10520Sigor@sysoev.ru nxt_router_start(nxt_task_t *task, nxt_runtime_t *rt)
10620Sigor@sysoev.ru {
107115Sigor@sysoev.ru     nxt_int_t     ret;
108115Sigor@sysoev.ru     nxt_router_t  *router;
10953Sigor@sysoev.ru 
11088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
11188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
11288Smax.romanov@nginx.com         return ret;
11388Smax.romanov@nginx.com     }
11488Smax.romanov@nginx.com 
11553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
11653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
11753Sigor@sysoev.ru         return NXT_ERROR;
11853Sigor@sysoev.ru     }
11953Sigor@sysoev.ru 
12053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
12153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
122133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
12353Sigor@sysoev.ru 
124119Smax.romanov@nginx.com     nxt_router = router;
125119Smax.romanov@nginx.com 
126115Sigor@sysoev.ru     return NXT_OK;
127115Sigor@sysoev.ru }
128115Sigor@sysoev.ru 
129115Sigor@sysoev.ru 
130*139Sigor@sysoev.ru void
131*139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
132115Sigor@sysoev.ru {
133*139Sigor@sysoev.ru     size_t                  dump_size;
134*139Sigor@sysoev.ru     nxt_buf_t               *b;
135*139Sigor@sysoev.ru     nxt_int_t               ret;
136*139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
137*139Sigor@sysoev.ru 
138*139Sigor@sysoev.ru     b = msg->buf;
139*139Sigor@sysoev.ru 
140*139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
141*139Sigor@sysoev.ru 
142*139Sigor@sysoev.ru     if (dump_size > 300) {
143*139Sigor@sysoev.ru         dump_size = 300;
14453Sigor@sysoev.ru     }
14553Sigor@sysoev.ru 
146*139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
147*139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
148*139Sigor@sysoev.ru 
149*139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
150*139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
151*139Sigor@sysoev.ru         return;
15253Sigor@sysoev.ru     }
15353Sigor@sysoev.ru 
154*139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
155*139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
156*139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
157*139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
158*139Sigor@sysoev.ru 
159*139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
160*139Sigor@sysoev.ru 
161*139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
162*139Sigor@sysoev.ru 
163*139Sigor@sysoev.ru     if (ret == NXT_OK) {
164*139Sigor@sysoev.ru         return nxt_router_conf_success(task, tmcf);
165*139Sigor@sysoev.ru     }
166*139Sigor@sysoev.ru 
167*139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
168*139Sigor@sysoev.ru 
169*139Sigor@sysoev.ru     return nxt_router_conf_error(task, tmcf);
17053Sigor@sysoev.ru }
17153Sigor@sysoev.ru 
17253Sigor@sysoev.ru 
17353Sigor@sysoev.ru static nxt_router_temp_conf_t *
174*139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
17553Sigor@sysoev.ru {
17665Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
17753Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
17853Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
17953Sigor@sysoev.ru 
18065Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
18153Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
18253Sigor@sysoev.ru         return NULL;
18353Sigor@sysoev.ru     }
18453Sigor@sysoev.ru 
18565Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
18653Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
18753Sigor@sysoev.ru         goto fail;
18853Sigor@sysoev.ru     }
18953Sigor@sysoev.ru 
19053Sigor@sysoev.ru     rtcf->mem_pool = mp;
19153Sigor@sysoev.ru     rtcf->count = 1;
19253Sigor@sysoev.ru 
19365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
19453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
19553Sigor@sysoev.ru         goto fail;
19653Sigor@sysoev.ru     }
19753Sigor@sysoev.ru 
19865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
19953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
20053Sigor@sysoev.ru         goto temp_fail;
20153Sigor@sysoev.ru     }
20253Sigor@sysoev.ru 
20353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
20453Sigor@sysoev.ru     tmcf->conf = rtcf;
205*139Sigor@sysoev.ru     tmcf->count = 1;
206*139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
20753Sigor@sysoev.ru 
20853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
20953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
21053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
21153Sigor@sysoev.ru         goto temp_fail;
21253Sigor@sysoev.ru     }
21353Sigor@sysoev.ru 
21453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
21553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
21653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
21753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
21853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
219133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
220133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
22153Sigor@sysoev.ru 
22253Sigor@sysoev.ru     return tmcf;
22353Sigor@sysoev.ru 
22453Sigor@sysoev.ru temp_fail:
22553Sigor@sysoev.ru 
22665Sigor@sysoev.ru     nxt_mp_destroy(tmp);
22753Sigor@sysoev.ru 
22853Sigor@sysoev.ru fail:
22953Sigor@sysoev.ru 
23065Sigor@sysoev.ru     nxt_mp_destroy(mp);
23153Sigor@sysoev.ru 
23253Sigor@sysoev.ru     return NULL;
23353Sigor@sysoev.ru }
23453Sigor@sysoev.ru 
23553Sigor@sysoev.ru 
236*139Sigor@sysoev.ru static nxt_int_t
237*139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
238*139Sigor@sysoev.ru     u_char *start, u_char *end)
239*139Sigor@sysoev.ru {
240*139Sigor@sysoev.ru     nxt_int_t                    ret;
241*139Sigor@sysoev.ru     nxt_router_t                 *router;
242*139Sigor@sysoev.ru     nxt_runtime_t                *rt;
243*139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
244*139Sigor@sysoev.ru 
245*139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
246*139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
247*139Sigor@sysoev.ru         return ret;
248*139Sigor@sysoev.ru     }
249*139Sigor@sysoev.ru 
250*139Sigor@sysoev.ru     router = tmcf->conf->router;
251*139Sigor@sysoev.ru 
252*139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
253*139Sigor@sysoev.ru 
254*139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
255*139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
256*139Sigor@sysoev.ru         return ret;
257*139Sigor@sysoev.ru     }
258*139Sigor@sysoev.ru 
259*139Sigor@sysoev.ru     rt = task->thread->runtime;
260*139Sigor@sysoev.ru 
261*139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
262*139Sigor@sysoev.ru 
263*139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
264*139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
265*139Sigor@sysoev.ru         return ret;
266*139Sigor@sysoev.ru     }
267*139Sigor@sysoev.ru 
268*139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
269*139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
270*139Sigor@sysoev.ru         return ret;
271*139Sigor@sysoev.ru     }
272*139Sigor@sysoev.ru 
273*139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
274*139Sigor@sysoev.ru 
275*139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
276*139Sigor@sysoev.ru 
277*139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
278*139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
279*139Sigor@sysoev.ru 
280*139Sigor@sysoev.ru     return NXT_OK;
281*139Sigor@sysoev.ru }
282*139Sigor@sysoev.ru 
283*139Sigor@sysoev.ru 
284*139Sigor@sysoev.ru static void
285*139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
286*139Sigor@sysoev.ru {
287*139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
288*139Sigor@sysoev.ru 
289*139Sigor@sysoev.ru     tmcf = obj;
290*139Sigor@sysoev.ru 
291*139Sigor@sysoev.ru     nxt_router_conf_success(task, tmcf);
292*139Sigor@sysoev.ru }
293*139Sigor@sysoev.ru 
294*139Sigor@sysoev.ru 
295*139Sigor@sysoev.ru static void
296*139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
297*139Sigor@sysoev.ru {
298*139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
299*139Sigor@sysoev.ru 
300*139Sigor@sysoev.ru     if (--tmcf->count == 0) {
301*139Sigor@sysoev.ru         nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2);
302*139Sigor@sysoev.ru     }
303*139Sigor@sysoev.ru }
304*139Sigor@sysoev.ru 
305*139Sigor@sysoev.ru 
306*139Sigor@sysoev.ru static void
307*139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
308*139Sigor@sysoev.ru {
309*139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
310*139Sigor@sysoev.ru 
311*139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
312*139Sigor@sysoev.ru }
313*139Sigor@sysoev.ru 
314*139Sigor@sysoev.ru 
315*139Sigor@sysoev.ru static void
316*139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
317*139Sigor@sysoev.ru     u_char *start, size_t size)
318*139Sigor@sysoev.ru {
319*139Sigor@sysoev.ru     nxt_buf_t  *b;
320*139Sigor@sysoev.ru 
321*139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
322*139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
323*139Sigor@sysoev.ru         return;
324*139Sigor@sysoev.ru     }
325*139Sigor@sysoev.ru 
326*139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
327*139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
328*139Sigor@sysoev.ru 
329*139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
330*139Sigor@sysoev.ru                           tmcf->stream, 0, b);
331*139Sigor@sysoev.ru }
332*139Sigor@sysoev.ru 
333*139Sigor@sysoev.ru 
334*139Sigor@sysoev.ru static void
335*139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
336*139Sigor@sysoev.ru {
337*139Sigor@sysoev.ru     nxt_mp_t  *mp;
338*139Sigor@sysoev.ru 
339*139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
340*139Sigor@sysoev.ru     mp = data;
341*139Sigor@sysoev.ru 
342*139Sigor@sysoev.ru     nxt_mp_destroy(mp);
343*139Sigor@sysoev.ru }
344*139Sigor@sysoev.ru 
345*139Sigor@sysoev.ru 
346115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
347115Sigor@sysoev.ru     {
348133Sigor@sysoev.ru         nxt_string("listeners_threads"),
349115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
350115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
351115Sigor@sysoev.ru     },
352115Sigor@sysoev.ru };
353115Sigor@sysoev.ru 
354115Sigor@sysoev.ru 
355133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
356115Sigor@sysoev.ru     {
357133Sigor@sysoev.ru         nxt_string("type"),
358115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
359133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
360115Sigor@sysoev.ru     },
361115Sigor@sysoev.ru 
362115Sigor@sysoev.ru     {
363133Sigor@sysoev.ru         nxt_string("workers"),
364115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
365133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
366133Sigor@sysoev.ru     },
367133Sigor@sysoev.ru };
368133Sigor@sysoev.ru 
369133Sigor@sysoev.ru 
370133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
371133Sigor@sysoev.ru     {
372133Sigor@sysoev.ru         nxt_string("application"),
373133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
374133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
375115Sigor@sysoev.ru     },
376115Sigor@sysoev.ru };
377115Sigor@sysoev.ru 
378115Sigor@sysoev.ru 
379115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
380115Sigor@sysoev.ru     {
381115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
382115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
383115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
384115Sigor@sysoev.ru     },
385115Sigor@sysoev.ru 
386115Sigor@sysoev.ru     {
387115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
388115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
389115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
390115Sigor@sysoev.ru     },
391115Sigor@sysoev.ru 
392115Sigor@sysoev.ru     {
393115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
394115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
395115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
396115Sigor@sysoev.ru     },
397115Sigor@sysoev.ru };
398115Sigor@sysoev.ru 
399115Sigor@sysoev.ru 
40053Sigor@sysoev.ru static nxt_int_t
401115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
402115Sigor@sysoev.ru     u_char *start, u_char *end)
40353Sigor@sysoev.ru {
404133Sigor@sysoev.ru     u_char                      *p;
405133Sigor@sysoev.ru     size_t                      size;
406115Sigor@sysoev.ru     nxt_mp_t                    *mp;
407115Sigor@sysoev.ru     uint32_t                    next;
408115Sigor@sysoev.ru     nxt_int_t                   ret;
409115Sigor@sysoev.ru     nxt_str_t                   name;
410133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
411133Sigor@sysoev.ru     nxt_app_type_t              type;
412115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
413133Sigor@sysoev.ru     nxt_queue_link_t            *qlk, *nqlk;
414133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
415133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
416133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
417115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
418133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
419115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
420115Sigor@sysoev.ru 
421115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
422133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
423115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
424115Sigor@sysoev.ru 
425115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
426115Sigor@sysoev.ru     if (conf == NULL) {
427115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
428115Sigor@sysoev.ru         return NXT_ERROR;
429115Sigor@sysoev.ru     }
430115Sigor@sysoev.ru 
431136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
432136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
433115Sigor@sysoev.ru     if (ret != NXT_OK) {
434133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
435115Sigor@sysoev.ru         return NXT_ERROR;
436115Sigor@sysoev.ru     }
437115Sigor@sysoev.ru 
438117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
439117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
440117Sigor@sysoev.ru     }
441117Sigor@sysoev.ru 
442133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
443133Sigor@sysoev.ru     if (applications == NULL) {
444133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
445115Sigor@sysoev.ru         return NXT_ERROR;
446115Sigor@sysoev.ru     }
447115Sigor@sysoev.ru 
448133Sigor@sysoev.ru     next = 0;
449133Sigor@sysoev.ru 
450133Sigor@sysoev.ru     for ( ;; ) {
451133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
452133Sigor@sysoev.ru         if (application == NULL) {
453133Sigor@sysoev.ru             break;
454133Sigor@sysoev.ru         }
455133Sigor@sysoev.ru 
456133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
457133Sigor@sysoev.ru 
458133Sigor@sysoev.ru         app = nxt_zalloc(sizeof(nxt_app_t));
459133Sigor@sysoev.ru         if (app == NULL) {
460133Sigor@sysoev.ru             goto fail;
461133Sigor@sysoev.ru         }
462133Sigor@sysoev.ru 
463133Sigor@sysoev.ru         size = nxt_conf_json_length(application, NULL);
464133Sigor@sysoev.ru 
465133Sigor@sysoev.ru         app->conf.start = nxt_malloc(size);
466133Sigor@sysoev.ru         if (app->conf.start == NULL) {
467133Sigor@sysoev.ru             nxt_free(app);
468133Sigor@sysoev.ru             goto fail;
469133Sigor@sysoev.ru         }
470133Sigor@sysoev.ru 
471133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
472133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
473133Sigor@sysoev.ru 
474133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
475133Sigor@sysoev.ru 
476133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
477133Sigor@sysoev.ru 
478133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
479133Sigor@sysoev.ru             nxt_free(app->conf.start);
480133Sigor@sysoev.ru             nxt_free(app);
481133Sigor@sysoev.ru 
482133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
483133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
484133Sigor@sysoev.ru             continue;
485133Sigor@sysoev.ru         }
486133Sigor@sysoev.ru 
487136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
488136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
489133Sigor@sysoev.ru         if (ret != NXT_OK) {
490133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
491133Sigor@sysoev.ru             goto app_fail;
492133Sigor@sysoev.ru         }
493115Sigor@sysoev.ru 
494133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
495133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
496133Sigor@sysoev.ru 
497133Sigor@sysoev.ru         if (nxt_str_eq(&apcf.type, "python", 6)) {
498133Sigor@sysoev.ru             type = NXT_APP_PYTHON;
499133Sigor@sysoev.ru 
500133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "php", 3)) {
501133Sigor@sysoev.ru             type = NXT_APP_PHP;
502133Sigor@sysoev.ru 
503133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "ruby", 4)) {
504133Sigor@sysoev.ru             type = NXT_APP_RUBY;
505133Sigor@sysoev.ru 
506133Sigor@sysoev.ru         } else if (nxt_str_eq(&apcf.type, "go", 2)) {
507133Sigor@sysoev.ru             type = NXT_APP_GO;
508133Sigor@sysoev.ru 
509133Sigor@sysoev.ru         } else {
510133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
511133Sigor@sysoev.ru                     &apcf.type);
512133Sigor@sysoev.ru             goto app_fail;
513133Sigor@sysoev.ru         }
514133Sigor@sysoev.ru 
515133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
516133Sigor@sysoev.ru         if (ret != NXT_OK) {
517133Sigor@sysoev.ru             goto app_fail;
518133Sigor@sysoev.ru         }
519133Sigor@sysoev.ru 
520133Sigor@sysoev.ru         app->name = name;
521133Sigor@sysoev.ru         app->type = type;
522133Sigor@sysoev.ru         app->max_workers = apcf.workers;
523133Sigor@sysoev.ru         app->live = 1;
524133Sigor@sysoev.ru 
525133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
526133Sigor@sysoev.ru     }
527133Sigor@sysoev.ru 
528133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
529133Sigor@sysoev.ru #if 0
530133Sigor@sysoev.ru     if (http == NULL) {
531133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
532133Sigor@sysoev.ru         return NXT_ERROR;
533133Sigor@sysoev.ru     }
534133Sigor@sysoev.ru #endif
535133Sigor@sysoev.ru 
536133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
537115Sigor@sysoev.ru     if (listeners == NULL) {
538133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
539115Sigor@sysoev.ru         return NXT_ERROR;
540115Sigor@sysoev.ru     }
54153Sigor@sysoev.ru 
542133Sigor@sysoev.ru     next = 0;
54353Sigor@sysoev.ru 
544133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
545115Sigor@sysoev.ru 
546115Sigor@sysoev.ru     for ( ;; ) {
547115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
548115Sigor@sysoev.ru         if (listener == NULL) {
549115Sigor@sysoev.ru             break;
550115Sigor@sysoev.ru         }
55153Sigor@sysoev.ru 
552115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
553115Sigor@sysoev.ru         if (sa == NULL) {
554115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
555133Sigor@sysoev.ru             goto fail;
556115Sigor@sysoev.ru         }
557115Sigor@sysoev.ru 
558115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
559115Sigor@sysoev.ru 
560115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
561115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
56253Sigor@sysoev.ru 
563115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
564115Sigor@sysoev.ru         if (skcf == NULL) {
565133Sigor@sysoev.ru             goto fail;
566115Sigor@sysoev.ru         }
56753Sigor@sysoev.ru 
568136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
569136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
570115Sigor@sysoev.ru         if (ret != NXT_OK) {
571115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
572133Sigor@sysoev.ru             goto fail;
573115Sigor@sysoev.ru         }
57453Sigor@sysoev.ru 
575133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
576133Sigor@sysoev.ru 
577133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
578133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
579133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
580133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
58153Sigor@sysoev.ru 
582133Sigor@sysoev.ru         if (http != NULL) {
583136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
584136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
585133Sigor@sysoev.ru             if (ret != NXT_OK) {
586133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
587133Sigor@sysoev.ru                 goto fail;
588133Sigor@sysoev.ru             }
589115Sigor@sysoev.ru         }
590115Sigor@sysoev.ru 
591115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
592115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
593133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
594133Sigor@sysoev.ru                                                             &lscf.application);
595115Sigor@sysoev.ru 
596115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
597115Sigor@sysoev.ru     }
59853Sigor@sysoev.ru 
59953Sigor@sysoev.ru     return NXT_OK;
600133Sigor@sysoev.ru 
601133Sigor@sysoev.ru app_fail:
602133Sigor@sysoev.ru 
603133Sigor@sysoev.ru     nxt_free(app->conf.start);
604133Sigor@sysoev.ru     nxt_free(app);
605133Sigor@sysoev.ru 
606133Sigor@sysoev.ru fail:
607133Sigor@sysoev.ru 
608133Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->apps);
609133Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->apps);
610133Sigor@sysoev.ru          qlk = nqlk)
611133Sigor@sysoev.ru     {
612133Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
613133Sigor@sysoev.ru         app = nxt_queue_link_data(qlk, nxt_app_t, link);
614133Sigor@sysoev.ru 
615133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
616133Sigor@sysoev.ru         nxt_free(app);
617133Sigor@sysoev.ru     }
618133Sigor@sysoev.ru 
619133Sigor@sysoev.ru     return NXT_ERROR;
620133Sigor@sysoev.ru }
621133Sigor@sysoev.ru 
622133Sigor@sysoev.ru 
623133Sigor@sysoev.ru static nxt_app_t *
624133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
625133Sigor@sysoev.ru {
626133Sigor@sysoev.ru     nxt_app_t         *app;
627133Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
628133Sigor@sysoev.ru 
629133Sigor@sysoev.ru     for (qlk = nxt_queue_first(queue);
630133Sigor@sysoev.ru          qlk != nxt_queue_tail(queue);
631133Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
632133Sigor@sysoev.ru     {
633133Sigor@sysoev.ru         app = nxt_queue_link_data(qlk, nxt_app_t, link);
634133Sigor@sysoev.ru 
635133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
636133Sigor@sysoev.ru             return app;
637133Sigor@sysoev.ru         }
638133Sigor@sysoev.ru     }
639133Sigor@sysoev.ru 
640133Sigor@sysoev.ru     return NULL;
641133Sigor@sysoev.ru }
642133Sigor@sysoev.ru 
643133Sigor@sysoev.ru 
644133Sigor@sysoev.ru static nxt_app_t *
645133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
646133Sigor@sysoev.ru {
647133Sigor@sysoev.ru     nxt_app_t  *app;
648133Sigor@sysoev.ru 
649133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
650133Sigor@sysoev.ru 
651133Sigor@sysoev.ru     if (app == NULL) {
652134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
653133Sigor@sysoev.ru     }
654133Sigor@sysoev.ru 
655133Sigor@sysoev.ru     return app;
65653Sigor@sysoev.ru }
65753Sigor@sysoev.ru 
65853Sigor@sysoev.ru 
65953Sigor@sysoev.ru static nxt_socket_conf_t *
66065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
66153Sigor@sysoev.ru {
66253Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
66353Sigor@sysoev.ru 
66465Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
66553Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
66653Sigor@sysoev.ru         return NULL;
66753Sigor@sysoev.ru     }
66853Sigor@sysoev.ru 
669115Sigor@sysoev.ru     conf->sockaddr = sa;
670115Sigor@sysoev.ru 
67153Sigor@sysoev.ru     conf->listen.sockaddr = sa;
672103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
673103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
67453Sigor@sysoev.ru 
67553Sigor@sysoev.ru     conf->listen.socket = -1;
67653Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
67753Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
67853Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
67953Sigor@sysoev.ru 
68053Sigor@sysoev.ru     return conf;
68153Sigor@sysoev.ru }
68253Sigor@sysoev.ru 
68353Sigor@sysoev.ru 
68453Sigor@sysoev.ru static void
68553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
68653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
68753Sigor@sysoev.ru {
68853Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
68953Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
69053Sigor@sysoev.ru 
69153Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
69253Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
69353Sigor@sysoev.ru          nqlk = next)
69453Sigor@sysoev.ru     {
69553Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
69653Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
69753Sigor@sysoev.ru 
69853Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
69953Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
70053Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
70153Sigor@sysoev.ru         {
70253Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
70353Sigor@sysoev.ru 
704115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
705115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
706115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
707115Sigor@sysoev.ru 
70853Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
70953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
71053Sigor@sysoev.ru 
71153Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
71253Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
71353Sigor@sysoev.ru 
71453Sigor@sysoev.ru                 break;
71553Sigor@sysoev.ru             }
71653Sigor@sysoev.ru         }
71753Sigor@sysoev.ru     }
71853Sigor@sysoev.ru 
71953Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
720115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
72153Sigor@sysoev.ru }
72253Sigor@sysoev.ru 
72353Sigor@sysoev.ru 
72453Sigor@sysoev.ru static nxt_int_t
72553Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
72653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
72753Sigor@sysoev.ru {
728115Sigor@sysoev.ru     nxt_int_t            ret;
729115Sigor@sysoev.ru     nxt_socket_t         s;
730115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
731115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
732115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
73353Sigor@sysoev.ru 
73453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
73553Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
73653Sigor@sysoev.ru          qlk = nqlk)
73753Sigor@sysoev.ru     {
738115Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
739115Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
74053Sigor@sysoev.ru             return NXT_ERROR;
74153Sigor@sysoev.ru         }
74253Sigor@sysoev.ru 
743115Sigor@sysoev.ru         rtsk->count = 0;
744115Sigor@sysoev.ru 
745115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
746115Sigor@sysoev.ru         skcf->socket = rtsk;
747115Sigor@sysoev.ru 
748115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
749115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
750115Sigor@sysoev.ru             return NXT_ERROR;
751115Sigor@sysoev.ru         }
752115Sigor@sysoev.ru 
753115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
754115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
755115Sigor@sysoev.ru             return NXT_ERROR;
756115Sigor@sysoev.ru         }
757115Sigor@sysoev.ru 
758115Sigor@sysoev.ru         skcf->listen.socket = s;
759115Sigor@sysoev.ru 
760115Sigor@sysoev.ru         rtsk->fd = s;
761115Sigor@sysoev.ru 
76253Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
76353Sigor@sysoev.ru         nxt_queue_remove(qlk);
76453Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
76553Sigor@sysoev.ru     }
76653Sigor@sysoev.ru 
76753Sigor@sysoev.ru     return NXT_OK;
76853Sigor@sysoev.ru }
76953Sigor@sysoev.ru 
77053Sigor@sysoev.ru 
77153Sigor@sysoev.ru static nxt_int_t
77253Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
77353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
77453Sigor@sysoev.ru {
77553Sigor@sysoev.ru     nxt_int_t                 ret;
77653Sigor@sysoev.ru     nxt_uint_t                n, threads;
77753Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
77853Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
77953Sigor@sysoev.ru 
78053Sigor@sysoev.ru     threads = tmcf->conf->threads;
78153Sigor@sysoev.ru 
78253Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
78353Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
78453Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
78553Sigor@sysoev.ru         return NXT_ERROR;
78653Sigor@sysoev.ru     }
78753Sigor@sysoev.ru 
78853Sigor@sysoev.ru     n = 0;
78953Sigor@sysoev.ru 
79053Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
79153Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
79253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
79353Sigor@sysoev.ru     {
79453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
79553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
79653Sigor@sysoev.ru             return NXT_ERROR;
79753Sigor@sysoev.ru         }
79853Sigor@sysoev.ru 
799115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
80053Sigor@sysoev.ru 
80153Sigor@sysoev.ru         if (n < threads) {
802115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
80353Sigor@sysoev.ru 
80453Sigor@sysoev.ru         } else {
805115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
80653Sigor@sysoev.ru         }
80753Sigor@sysoev.ru 
80853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
80953Sigor@sysoev.ru             return ret;
81053Sigor@sysoev.ru         }
81153Sigor@sysoev.ru 
81253Sigor@sysoev.ru         n++;
81353Sigor@sysoev.ru     }
81453Sigor@sysoev.ru 
81553Sigor@sysoev.ru     tmcf->new_threads = n;
81653Sigor@sysoev.ru 
81753Sigor@sysoev.ru     while (n < threads) {
81853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
81953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
82053Sigor@sysoev.ru             return NXT_ERROR;
82153Sigor@sysoev.ru         }
82253Sigor@sysoev.ru 
82353Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
82453Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
82553Sigor@sysoev.ru             return NXT_ERROR;
82653Sigor@sysoev.ru         }
82753Sigor@sysoev.ru 
828115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
82953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
83053Sigor@sysoev.ru             return ret;
83153Sigor@sysoev.ru         }
83253Sigor@sysoev.ru 
833115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
834115Sigor@sysoev.ru 
83553Sigor@sysoev.ru         n++;
83653Sigor@sysoev.ru     }
83753Sigor@sysoev.ru 
83853Sigor@sysoev.ru     return NXT_OK;
83953Sigor@sysoev.ru }
84053Sigor@sysoev.ru 
84153Sigor@sysoev.ru 
84253Sigor@sysoev.ru static nxt_int_t
843115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
844115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
84553Sigor@sysoev.ru {
846115Sigor@sysoev.ru     nxt_mp_t               *mp;
847115Sigor@sysoev.ru     nxt_int_t              ret;
848115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
84953Sigor@sysoev.ru 
85053Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
85153Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
85253Sigor@sysoev.ru         return NXT_ERROR;
85353Sigor@sysoev.ru     }
85453Sigor@sysoev.ru 
855115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
856115Sigor@sysoev.ru 
857*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
858115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
859115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
860115Sigor@sysoev.ru         return ret;
861115Sigor@sysoev.ru     }
862115Sigor@sysoev.ru 
863*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
86453Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
86553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
86653Sigor@sysoev.ru         return ret;
86753Sigor@sysoev.ru     }
86853Sigor@sysoev.ru 
869115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
870115Sigor@sysoev.ru 
871115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
872115Sigor@sysoev.ru 
873115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
874115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
875115Sigor@sysoev.ru 
876115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
877115Sigor@sysoev.ru 
878115Sigor@sysoev.ru     return ret;
87953Sigor@sysoev.ru }
88053Sigor@sysoev.ru 
88153Sigor@sysoev.ru 
88253Sigor@sysoev.ru static nxt_int_t
883115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
884115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
88553Sigor@sysoev.ru {
886115Sigor@sysoev.ru     nxt_mp_t               *mp;
887115Sigor@sysoev.ru     nxt_int_t              ret;
888115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
88953Sigor@sysoev.ru 
89053Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
89153Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
89253Sigor@sysoev.ru         return NXT_ERROR;
89353Sigor@sysoev.ru     }
89453Sigor@sysoev.ru 
895115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
896115Sigor@sysoev.ru 
897*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
89853Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
89953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
90053Sigor@sysoev.ru         return ret;
90153Sigor@sysoev.ru     }
90253Sigor@sysoev.ru 
90353Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
90453Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
90553Sigor@sysoev.ru         return NXT_ERROR;
90653Sigor@sysoev.ru     }
90753Sigor@sysoev.ru 
908*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
90953Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
91053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
91153Sigor@sysoev.ru         return ret;
91253Sigor@sysoev.ru     }
91353Sigor@sysoev.ru 
91453Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
91553Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
91653Sigor@sysoev.ru         return NXT_ERROR;
91753Sigor@sysoev.ru     }
91853Sigor@sysoev.ru 
919*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
920115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
921115Sigor@sysoev.ru         return ret;
922115Sigor@sysoev.ru     }
923115Sigor@sysoev.ru 
924115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
925115Sigor@sysoev.ru 
926115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
927115Sigor@sysoev.ru 
928115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
929115Sigor@sysoev.ru 
930115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
931115Sigor@sysoev.ru 
932115Sigor@sysoev.ru     return ret;
93353Sigor@sysoev.ru }
93453Sigor@sysoev.ru 
93553Sigor@sysoev.ru 
93653Sigor@sysoev.ru static nxt_int_t
937115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
938115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
93953Sigor@sysoev.ru {
94053Sigor@sysoev.ru     nxt_int_t  ret;
94153Sigor@sysoev.ru 
94253Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
94353Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
94453Sigor@sysoev.ru         return NXT_ERROR;
94553Sigor@sysoev.ru     }
94653Sigor@sysoev.ru 
947*139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
94853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
94953Sigor@sysoev.ru         return ret;
95053Sigor@sysoev.ru     }
95153Sigor@sysoev.ru 
952*139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
95353Sigor@sysoev.ru }
95453Sigor@sysoev.ru 
95553Sigor@sysoev.ru 
95653Sigor@sysoev.ru static nxt_int_t
957*139Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_temp_conf_t *tmcf,
958*139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
95953Sigor@sysoev.ru     nxt_work_handler_t handler)
96053Sigor@sysoev.ru {
961*139Sigor@sysoev.ru     nxt_work_t               *work, *back;
96253Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
96353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
96453Sigor@sysoev.ru 
96553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
96653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
96753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
96853Sigor@sysoev.ru     {
969*139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
970*139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
971*139Sigor@sysoev.ru             return NXT_ERROR;
972*139Sigor@sysoev.ru         }
973*139Sigor@sysoev.ru 
974*139Sigor@sysoev.ru         back->next = NULL;
975*139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
976*139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
977*139Sigor@sysoev.ru         back->obj = tmcf;
978*139Sigor@sysoev.ru         back->data = NULL;
979*139Sigor@sysoev.ru 
98053Sigor@sysoev.ru         work = nxt_array_add(array);
98153Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
98253Sigor@sysoev.ru             return NXT_ERROR;
98353Sigor@sysoev.ru         }
98453Sigor@sysoev.ru 
98553Sigor@sysoev.ru         work->next = NULL;
98653Sigor@sysoev.ru         work->handler = handler;
987*139Sigor@sysoev.ru         work->task = &recf->engine->task;
988*139Sigor@sysoev.ru         work->obj = back;
98953Sigor@sysoev.ru 
99065Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
99153Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
99253Sigor@sysoev.ru             return NXT_ERROR;
99353Sigor@sysoev.ru         }
99453Sigor@sysoev.ru 
99553Sigor@sysoev.ru         work->data = joint;
99653Sigor@sysoev.ru 
99753Sigor@sysoev.ru         joint->count = 1;
99853Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
99988Smax.romanov@nginx.com         joint->engine = recf->engine;
1000115Sigor@sysoev.ru 
1001115Sigor@sysoev.ru         nxt_queue_insert_tail(&joint->engine->joints, &joint->link);
100253Sigor@sysoev.ru     }
100353Sigor@sysoev.ru 
100420Sigor@sysoev.ru     return NXT_OK;
100520Sigor@sysoev.ru }
100620Sigor@sysoev.ru 
100720Sigor@sysoev.ru 
1008115Sigor@sysoev.ru static void
1009115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1010115Sigor@sysoev.ru {
1011115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1012115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1013115Sigor@sysoev.ru 
1014115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1015115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1016115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1017115Sigor@sysoev.ru     {
1018115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1019115Sigor@sysoev.ru         skcf->socket->count++;
1020115Sigor@sysoev.ru     }
1021115Sigor@sysoev.ru }
1022115Sigor@sysoev.ru 
1023115Sigor@sysoev.ru 
102420Sigor@sysoev.ru static nxt_int_t
1025*139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1026*139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
102720Sigor@sysoev.ru {
1028*139Sigor@sysoev.ru     nxt_work_t        *work, *back;
102953Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
103020Sigor@sysoev.ru 
103153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
103253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
103353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
103453Sigor@sysoev.ru     {
1035*139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
1036*139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
1037*139Sigor@sysoev.ru             return NXT_ERROR;
1038*139Sigor@sysoev.ru         }
1039*139Sigor@sysoev.ru 
1040*139Sigor@sysoev.ru         back->next = NULL;
1041*139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
1042*139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
1043*139Sigor@sysoev.ru         back->obj = tmcf;
1044*139Sigor@sysoev.ru         back->data = NULL;
1045*139Sigor@sysoev.ru 
1046115Sigor@sysoev.ru         work = nxt_array_add(recf->deleting);
104753Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
104853Sigor@sysoev.ru             return NXT_ERROR;
104953Sigor@sysoev.ru         }
105020Sigor@sysoev.ru 
105153Sigor@sysoev.ru         work->next = NULL;
105253Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
1053*139Sigor@sysoev.ru         work->task = &recf->engine->task;
1054*139Sigor@sysoev.ru         work->obj = back;
105553Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1056