xref: /unit/src/nxt_router.c (revision 163)
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 
23141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
24141Smax.romanov@nginx.com 
25141Smax.romanov@nginx.com struct nxt_start_worker_s {
26141Smax.romanov@nginx.com     uint32_t               stream;
27141Smax.romanov@nginx.com     nxt_app_t              *app;
28141Smax.romanov@nginx.com     nxt_req_conn_link_t    *rc;
29141Smax.romanov@nginx.com     nxt_mp_t               *mem_pool;
30141Smax.romanov@nginx.com     void                   *joint;
31141Smax.romanov@nginx.com 
32141Smax.romanov@nginx.com     nxt_work_t             work;
33141Smax.romanov@nginx.com };
34141Smax.romanov@nginx.com 
35141Smax.romanov@nginx.com 
36139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
37139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
38139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
39139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
40139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
41139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
42139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
43139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
44139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, size_t size);
45139Sigor@sysoev.ru static void nxt_router_conf_buf_completion(nxt_task_t *task, void *obj,
46139Sigor@sysoev.ru     void *data);
4753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
4853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
4953Sigor@sysoev.ru 
50115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
51115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
52133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
53133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
54133Sigor@sysoev.ru     nxt_str_t *name);
5553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
5653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
5765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
5865Sigor@sysoev.ru     nxt_sockaddr_t *sa);
5953Sigor@sysoev.ru 
6053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
6153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
6253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
63115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
64115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
65115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
66115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
67115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
68115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
69115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
70154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
71154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
72154Sigor@sysoev.ru     nxt_work_handler_t handler);
73139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
74139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
7553Sigor@sysoev.ru 
7653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
7753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
7853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
7953Sigor@sysoev.ru     nxt_event_engine_t *engine);
80133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
81133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
8253Sigor@sysoev.ru 
8353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
84154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
8553Sigor@sysoev.ru 
8653Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
8753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
8853Sigor@sysoev.ru     void *data);
8953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
9053Sigor@sysoev.ru     void *data);
9153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
9253Sigor@sysoev.ru     void *data);
9353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
9453Sigor@sysoev.ru     void *data);
9553Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
9653Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
9753Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
9853Sigor@sysoev.ru     void *data);
9953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
10053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
10153Sigor@sysoev.ru 
102*163Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_app_t *app);
103141Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app);
104141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
105141Smax.romanov@nginx.com     void *data);
106141Smax.romanov@nginx.com 
107141Smax.romanov@nginx.com static void nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
108141Smax.romanov@nginx.com     nxt_start_worker_t *sw);
109141Smax.romanov@nginx.com static nxt_start_worker_t *nxt_router_sw_find_remove(nxt_task_t *task,
110141Smax.romanov@nginx.com     nxt_router_t *router, uint32_t id);
111141Smax.romanov@nginx.com 
11253Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
11353Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
11453Sigor@sysoev.ru     void *data);
11588Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
11688Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
117141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
118141Smax.romanov@nginx.com     nxt_req_conn_link_t *rc, nxt_mp_t *mp);
11988Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
12053Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
12153Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
12253Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
12353Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
12462Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
12520Sigor@sysoev.ru 
126141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
127141Smax.romanov@nginx.com     const char* fmt, ...);
128141Smax.romanov@nginx.com 
129119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
13020Sigor@sysoev.ru 
13120Sigor@sysoev.ru nxt_int_t
132141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
13320Sigor@sysoev.ru {
134141Smax.romanov@nginx.com     nxt_int_t      ret;
135141Smax.romanov@nginx.com     nxt_router_t   *router;
136141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
137141Smax.romanov@nginx.com 
138141Smax.romanov@nginx.com     rt = task->thread->runtime;
13953Sigor@sysoev.ru 
14088Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
14188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14288Smax.romanov@nginx.com         return ret;
14388Smax.romanov@nginx.com     }
14488Smax.romanov@nginx.com 
14553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
14653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
14753Sigor@sysoev.ru         return NXT_ERROR;
14853Sigor@sysoev.ru     }
14953Sigor@sysoev.ru 
15053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
15153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
152133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
15353Sigor@sysoev.ru 
154119Smax.romanov@nginx.com     nxt_router = router;
155119Smax.romanov@nginx.com 
156115Sigor@sysoev.ru     return NXT_OK;
157115Sigor@sysoev.ru }
158115Sigor@sysoev.ru 
159115Sigor@sysoev.ru 
160141Smax.romanov@nginx.com static void
161141Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, void *obj, void *data)
162141Smax.romanov@nginx.com {
163141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
164141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
165141Smax.romanov@nginx.com 
166141Smax.romanov@nginx.com     sw = obj;
167141Smax.romanov@nginx.com     joint = sw->joint;
168141Smax.romanov@nginx.com 
169141Smax.romanov@nginx.com     nxt_debug(task, "sw #%uxD release", sw->stream);
170141Smax.romanov@nginx.com 
171141Smax.romanov@nginx.com     if (nxt_mp_release(sw->mem_pool, sw) == 0) {
172141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
173141Smax.romanov@nginx.com     }
174141Smax.romanov@nginx.com }
175141Smax.romanov@nginx.com 
176141Smax.romanov@nginx.com 
177141Smax.romanov@nginx.com void
178141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
179141Smax.romanov@nginx.com {
180141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
181141Smax.romanov@nginx.com 
182141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
183141Smax.romanov@nginx.com 
184141Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
185141Smax.romanov@nginx.com         return;
186141Smax.romanov@nginx.com     }
187141Smax.romanov@nginx.com 
188141Smax.romanov@nginx.com     sw = nxt_router_sw_find_remove(task, nxt_router, msg->port_msg.stream);
189141Smax.romanov@nginx.com 
190141Smax.romanov@nginx.com     if (nxt_fast_path(sw != NULL)) {
191141Smax.romanov@nginx.com         msg->new_port->app = sw->app;
192141Smax.romanov@nginx.com 
193*163Smax.romanov@nginx.com         sw->app->workers++;
194*163Smax.romanov@nginx.com 
195*163Smax.romanov@nginx.com         nxt_assert(sw->app->pending_workers != 0);
196*163Smax.romanov@nginx.com 
197*163Smax.romanov@nginx.com         sw->app->pending_workers--;
198*163Smax.romanov@nginx.com 
199141Smax.romanov@nginx.com         nxt_router_app_release_port(task, msg->new_port, sw->app);
200141Smax.romanov@nginx.com 
201141Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
202141Smax.romanov@nginx.com 
203141Smax.romanov@nginx.com         nxt_debug(task, "post sw #%uxD release to %p", sw->stream,
204141Smax.romanov@nginx.com                   sw->work.data);
205141Smax.romanov@nginx.com 
206141Smax.romanov@nginx.com         nxt_event_engine_post(sw->work.data, &sw->work);
207141Smax.romanov@nginx.com     }
208141Smax.romanov@nginx.com }
209141Smax.romanov@nginx.com 
210141Smax.romanov@nginx.com 
211139Sigor@sysoev.ru void
212139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
213115Sigor@sysoev.ru {
214139Sigor@sysoev.ru     size_t                  dump_size;
215139Sigor@sysoev.ru     nxt_buf_t               *b;
216139Sigor@sysoev.ru     nxt_int_t               ret;
217139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
218139Sigor@sysoev.ru 
219139Sigor@sysoev.ru     b = msg->buf;
220139Sigor@sysoev.ru 
221139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
222139Sigor@sysoev.ru 
223139Sigor@sysoev.ru     if (dump_size > 300) {
224139Sigor@sysoev.ru         dump_size = 300;
22553Sigor@sysoev.ru     }
22653Sigor@sysoev.ru 
227139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
228139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
229139Sigor@sysoev.ru 
230139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
231139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
232139Sigor@sysoev.ru         return;
23353Sigor@sysoev.ru     }
23453Sigor@sysoev.ru 
235139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
236139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
237139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
238139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
239139Sigor@sysoev.ru 
240139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
241139Sigor@sysoev.ru 
242139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
243139Sigor@sysoev.ru 
244139Sigor@sysoev.ru     if (ret == NXT_OK) {
245139Sigor@sysoev.ru         return nxt_router_conf_success(task, tmcf);
246139Sigor@sysoev.ru     }
247139Sigor@sysoev.ru 
248139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
249139Sigor@sysoev.ru 
250139Sigor@sysoev.ru     return nxt_router_conf_error(task, tmcf);
25153Sigor@sysoev.ru }
25253Sigor@sysoev.ru 
25353Sigor@sysoev.ru 
25453Sigor@sysoev.ru static nxt_router_temp_conf_t *
255139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
25653Sigor@sysoev.ru {
25765Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
25853Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
25953Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
26053Sigor@sysoev.ru 
26165Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
26253Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
26353Sigor@sysoev.ru         return NULL;
26453Sigor@sysoev.ru     }
26553Sigor@sysoev.ru 
26665Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
26753Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
26853Sigor@sysoev.ru         goto fail;
26953Sigor@sysoev.ru     }
27053Sigor@sysoev.ru 
27153Sigor@sysoev.ru     rtcf->mem_pool = mp;
27253Sigor@sysoev.ru 
27365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
27453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
27553Sigor@sysoev.ru         goto fail;
27653Sigor@sysoev.ru     }
27753Sigor@sysoev.ru 
27865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
27953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
28053Sigor@sysoev.ru         goto temp_fail;
28153Sigor@sysoev.ru     }
28253Sigor@sysoev.ru 
28353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
28453Sigor@sysoev.ru     tmcf->conf = rtcf;
285139Sigor@sysoev.ru     tmcf->count = 1;
286139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
28753Sigor@sysoev.ru 
28853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
28953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
29053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
29153Sigor@sysoev.ru         goto temp_fail;
29253Sigor@sysoev.ru     }
29353Sigor@sysoev.ru 
29453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
29553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
29653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
29753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
29853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
299133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
300133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
30153Sigor@sysoev.ru 
30253Sigor@sysoev.ru     return tmcf;
30353Sigor@sysoev.ru 
30453Sigor@sysoev.ru temp_fail:
30553Sigor@sysoev.ru 
30665Sigor@sysoev.ru     nxt_mp_destroy(tmp);
30753Sigor@sysoev.ru 
30853Sigor@sysoev.ru fail:
30953Sigor@sysoev.ru 
31065Sigor@sysoev.ru     nxt_mp_destroy(mp);
31153Sigor@sysoev.ru 
31253Sigor@sysoev.ru     return NULL;
31353Sigor@sysoev.ru }
31453Sigor@sysoev.ru 
31553Sigor@sysoev.ru 
316139Sigor@sysoev.ru static nxt_int_t
317139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
318139Sigor@sysoev.ru     u_char *start, u_char *end)
319139Sigor@sysoev.ru {
320139Sigor@sysoev.ru     nxt_int_t                    ret;
321139Sigor@sysoev.ru     nxt_router_t                 *router;
322139Sigor@sysoev.ru     nxt_runtime_t                *rt;
323139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
324139Sigor@sysoev.ru 
325139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
326139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
327139Sigor@sysoev.ru         return ret;
328139Sigor@sysoev.ru     }
329139Sigor@sysoev.ru 
330139Sigor@sysoev.ru     router = tmcf->conf->router;
331139Sigor@sysoev.ru 
332139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
333139Sigor@sysoev.ru 
334139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
335139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
336139Sigor@sysoev.ru         return ret;
337139Sigor@sysoev.ru     }
338139Sigor@sysoev.ru 
339139Sigor@sysoev.ru     rt = task->thread->runtime;
340139Sigor@sysoev.ru 
341139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
344139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
345139Sigor@sysoev.ru         return ret;
346139Sigor@sysoev.ru     }
347139Sigor@sysoev.ru 
348139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
349139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
350139Sigor@sysoev.ru         return ret;
351139Sigor@sysoev.ru     }
352139Sigor@sysoev.ru 
353139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
354139Sigor@sysoev.ru 
355139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
356139Sigor@sysoev.ru 
357139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
358139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
359139Sigor@sysoev.ru 
360139Sigor@sysoev.ru     return NXT_OK;
361139Sigor@sysoev.ru }
362139Sigor@sysoev.ru 
363139Sigor@sysoev.ru 
364139Sigor@sysoev.ru static void
365139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
366139Sigor@sysoev.ru {
367153Sigor@sysoev.ru     nxt_joint_job_t  *job;
368153Sigor@sysoev.ru 
369153Sigor@sysoev.ru     job = obj;
370153Sigor@sysoev.ru 
371153Sigor@sysoev.ru     nxt_router_conf_success(task, job->tmcf);
372139Sigor@sysoev.ru }
373139Sigor@sysoev.ru 
374139Sigor@sysoev.ru 
375139Sigor@sysoev.ru static void
376139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
377139Sigor@sysoev.ru {
378139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
379139Sigor@sysoev.ru 
380139Sigor@sysoev.ru     if (--tmcf->count == 0) {
381139Sigor@sysoev.ru         nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2);
382139Sigor@sysoev.ru     }
383139Sigor@sysoev.ru }
384139Sigor@sysoev.ru 
385139Sigor@sysoev.ru 
386139Sigor@sysoev.ru static void
387139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
388139Sigor@sysoev.ru {
389148Sigor@sysoev.ru     nxt_socket_t       s;
390149Sigor@sysoev.ru     nxt_router_t       *router;
391148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
392148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
393148Sigor@sysoev.ru 
394148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
395148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
396148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
397148Sigor@sysoev.ru     {
398148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
399148Sigor@sysoev.ru         s = skcf->listen.socket;
400148Sigor@sysoev.ru 
401148Sigor@sysoev.ru         if (s != -1) {
402148Sigor@sysoev.ru             nxt_socket_close(task, s);
403148Sigor@sysoev.ru         }
404148Sigor@sysoev.ru 
405148Sigor@sysoev.ru         nxt_free(skcf->socket);
406148Sigor@sysoev.ru     }
407148Sigor@sysoev.ru 
408149Sigor@sysoev.ru     router = tmcf->conf->router;
409149Sigor@sysoev.ru 
410149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
411149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
412149Sigor@sysoev.ru 
413148Sigor@sysoev.ru     // TODO: new engines and threads
414148Sigor@sysoev.ru 
415139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
416139Sigor@sysoev.ru 
417139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
418139Sigor@sysoev.ru }
419139Sigor@sysoev.ru 
420139Sigor@sysoev.ru 
421139Sigor@sysoev.ru static void
422139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
423139Sigor@sysoev.ru     u_char *start, size_t size)
424139Sigor@sysoev.ru {
425139Sigor@sysoev.ru     nxt_buf_t  *b;
426139Sigor@sysoev.ru 
427139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
428139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
429139Sigor@sysoev.ru         return;
430139Sigor@sysoev.ru     }
431139Sigor@sysoev.ru 
432140Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, start, size);
433140Svbart@nginx.com 
434139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
435139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
436139Sigor@sysoev.ru 
437139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
438139Sigor@sysoev.ru                           tmcf->stream, 0, b);
439139Sigor@sysoev.ru }
440139Sigor@sysoev.ru 
441139Sigor@sysoev.ru 
442139Sigor@sysoev.ru static void
443139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
444139Sigor@sysoev.ru {
445139Sigor@sysoev.ru     nxt_mp_t  *mp;
446139Sigor@sysoev.ru 
447139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
448139Sigor@sysoev.ru     mp = data;
449139Sigor@sysoev.ru 
450139Sigor@sysoev.ru     nxt_mp_destroy(mp);
451139Sigor@sysoev.ru }
452139Sigor@sysoev.ru 
453139Sigor@sysoev.ru 
454115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
455115Sigor@sysoev.ru     {
456133Sigor@sysoev.ru         nxt_string("listeners_threads"),
457115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
458115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
459115Sigor@sysoev.ru     },
460115Sigor@sysoev.ru };
461115Sigor@sysoev.ru 
462115Sigor@sysoev.ru 
463133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
464115Sigor@sysoev.ru     {
465133Sigor@sysoev.ru         nxt_string("type"),
466115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
467133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
468115Sigor@sysoev.ru     },
469115Sigor@sysoev.ru 
470115Sigor@sysoev.ru     {
471133Sigor@sysoev.ru         nxt_string("workers"),
472115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
473133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
474133Sigor@sysoev.ru     },
475133Sigor@sysoev.ru };
476133Sigor@sysoev.ru 
477133Sigor@sysoev.ru 
478133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
479133Sigor@sysoev.ru     {
480133Sigor@sysoev.ru         nxt_string("application"),
481133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
482133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
483115Sigor@sysoev.ru     },
484115Sigor@sysoev.ru };
485115Sigor@sysoev.ru 
486115Sigor@sysoev.ru 
487115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
488115Sigor@sysoev.ru     {
489115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
490115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
491115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
492115Sigor@sysoev.ru     },
493115Sigor@sysoev.ru 
494115Sigor@sysoev.ru     {
495115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
496115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
497115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
498115Sigor@sysoev.ru     },
499115Sigor@sysoev.ru 
500115Sigor@sysoev.ru     {
501115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
502115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
503115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
504115Sigor@sysoev.ru     },
505115Sigor@sysoev.ru };
506115Sigor@sysoev.ru 
507115Sigor@sysoev.ru 
50853Sigor@sysoev.ru static nxt_int_t
509115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
510115Sigor@sysoev.ru     u_char *start, u_char *end)
51153Sigor@sysoev.ru {
512133Sigor@sysoev.ru     u_char                      *p;
513133Sigor@sysoev.ru     size_t                      size;
514115Sigor@sysoev.ru     nxt_mp_t                    *mp;
515115Sigor@sysoev.ru     uint32_t                    next;
516115Sigor@sysoev.ru     nxt_int_t                   ret;
517115Sigor@sysoev.ru     nxt_str_t                   name;
518133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
519133Sigor@sysoev.ru     nxt_app_type_t              type;
520115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
521133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
522133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
523133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
524115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
525133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
526115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
527115Sigor@sysoev.ru 
528115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
529133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
530115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
531115Sigor@sysoev.ru 
532115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
533115Sigor@sysoev.ru     if (conf == NULL) {
534115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
535115Sigor@sysoev.ru         return NXT_ERROR;
536115Sigor@sysoev.ru     }
537115Sigor@sysoev.ru 
538136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
539136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
540115Sigor@sysoev.ru     if (ret != NXT_OK) {
541133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
542115Sigor@sysoev.ru         return NXT_ERROR;
543115Sigor@sysoev.ru     }
544115Sigor@sysoev.ru 
545117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
546117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
547117Sigor@sysoev.ru     }
548117Sigor@sysoev.ru 
549133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
550133Sigor@sysoev.ru     if (applications == NULL) {
551133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
552115Sigor@sysoev.ru         return NXT_ERROR;
553115Sigor@sysoev.ru     }
554115Sigor@sysoev.ru 
555133Sigor@sysoev.ru     next = 0;
556133Sigor@sysoev.ru 
557133Sigor@sysoev.ru     for ( ;; ) {
558133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
559133Sigor@sysoev.ru         if (application == NULL) {
560133Sigor@sysoev.ru             break;
561133Sigor@sysoev.ru         }
562133Sigor@sysoev.ru 
563133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
564133Sigor@sysoev.ru 
565144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
566144Smax.romanov@nginx.com 
567144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
568133Sigor@sysoev.ru         if (app == NULL) {
569133Sigor@sysoev.ru             goto fail;
570133Sigor@sysoev.ru         }
571133Sigor@sysoev.ru 
572144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
573144Smax.romanov@nginx.com 
574144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
575144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
576133Sigor@sysoev.ru 
577133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
578133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
579133Sigor@sysoev.ru 
580144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
581144Smax.romanov@nginx.com 
582133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
583133Sigor@sysoev.ru 
584133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
585133Sigor@sysoev.ru 
586133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
587133Sigor@sysoev.ru             nxt_free(app);
588133Sigor@sysoev.ru 
589133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
590133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
591133Sigor@sysoev.ru             continue;
592133Sigor@sysoev.ru         }
593133Sigor@sysoev.ru 
594136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
595136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
596133Sigor@sysoev.ru         if (ret != NXT_OK) {
597133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
598133Sigor@sysoev.ru             goto app_fail;
599133Sigor@sysoev.ru         }
600115Sigor@sysoev.ru 
601133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
602133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
603133Sigor@sysoev.ru 
604141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
605141Smax.romanov@nginx.com 
606141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
607141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
608141Smax.romanov@nginx.com                     &apcf.type);
609141Smax.romanov@nginx.com             goto app_fail;
610141Smax.romanov@nginx.com         }
611141Smax.romanov@nginx.com 
612141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
613133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
614133Sigor@sysoev.ru                     &apcf.type);
615133Sigor@sysoev.ru             goto app_fail;
616133Sigor@sysoev.ru         }
617133Sigor@sysoev.ru 
618133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
619133Sigor@sysoev.ru         if (ret != NXT_OK) {
620133Sigor@sysoev.ru             goto app_fail;
621133Sigor@sysoev.ru         }
622133Sigor@sysoev.ru 
623141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
624141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
625141Smax.romanov@nginx.com 
626144Smax.romanov@nginx.com         app->name.length = name.length;
627144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
628144Smax.romanov@nginx.com 
629133Sigor@sysoev.ru         app->type = type;
630133Sigor@sysoev.ru         app->max_workers = apcf.workers;
631133Sigor@sysoev.ru         app->live = 1;
632141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
633133Sigor@sysoev.ru 
634133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
635133Sigor@sysoev.ru     }
636133Sigor@sysoev.ru 
637133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
638133Sigor@sysoev.ru #if 0
639133Sigor@sysoev.ru     if (http == NULL) {
640133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
641133Sigor@sysoev.ru         return NXT_ERROR;
642133Sigor@sysoev.ru     }
643133Sigor@sysoev.ru #endif
644133Sigor@sysoev.ru 
645133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
646115Sigor@sysoev.ru     if (listeners == NULL) {
647133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
648115Sigor@sysoev.ru         return NXT_ERROR;
649115Sigor@sysoev.ru     }
65053Sigor@sysoev.ru 
651133Sigor@sysoev.ru     next = 0;
65253Sigor@sysoev.ru 
653133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
654115Sigor@sysoev.ru 
655115Sigor@sysoev.ru     for ( ;; ) {
656115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
657115Sigor@sysoev.ru         if (listener == NULL) {
658115Sigor@sysoev.ru             break;
659115Sigor@sysoev.ru         }
66053Sigor@sysoev.ru 
661115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
662115Sigor@sysoev.ru         if (sa == NULL) {
663115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
664133Sigor@sysoev.ru             goto fail;
665115Sigor@sysoev.ru         }
666115Sigor@sysoev.ru 
667115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
668115Sigor@sysoev.ru 
669115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
670115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
67153Sigor@sysoev.ru 
672115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
673115Sigor@sysoev.ru         if (skcf == NULL) {
674133Sigor@sysoev.ru             goto fail;
675115Sigor@sysoev.ru         }
67653Sigor@sysoev.ru 
677136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
678136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
679115Sigor@sysoev.ru         if (ret != NXT_OK) {
680115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
681133Sigor@sysoev.ru             goto fail;
682115Sigor@sysoev.ru         }
68353Sigor@sysoev.ru 
684133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
685133Sigor@sysoev.ru 
686133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
687133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
688133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
689133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
69053Sigor@sysoev.ru 
691133Sigor@sysoev.ru         if (http != NULL) {
692136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
693136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
694133Sigor@sysoev.ru             if (ret != NXT_OK) {
695133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
696133Sigor@sysoev.ru                 goto fail;
697133Sigor@sysoev.ru             }
698115Sigor@sysoev.ru         }
699115Sigor@sysoev.ru 
700115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
701115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
702160Sigor@sysoev.ru         skcf->router_conf->count++;
703133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
704133Sigor@sysoev.ru                                                             &lscf.application);
705115Sigor@sysoev.ru 
706115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
707115Sigor@sysoev.ru     }
70853Sigor@sysoev.ru 
70953Sigor@sysoev.ru     return NXT_OK;
710133Sigor@sysoev.ru 
711133Sigor@sysoev.ru app_fail:
712133Sigor@sysoev.ru 
713133Sigor@sysoev.ru     nxt_free(app);
714133Sigor@sysoev.ru 
715133Sigor@sysoev.ru fail:
716133Sigor@sysoev.ru 
717141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
718141Smax.romanov@nginx.com 
719141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
720133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
721133Sigor@sysoev.ru         nxt_free(app);
722141Smax.romanov@nginx.com 
723141Smax.romanov@nginx.com     } nxt_queue_loop;
724133Sigor@sysoev.ru 
725133Sigor@sysoev.ru     return NXT_ERROR;
726133Sigor@sysoev.ru }
727133Sigor@sysoev.ru 
728133Sigor@sysoev.ru 
729133Sigor@sysoev.ru static nxt_app_t *
730133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
731133Sigor@sysoev.ru {
732141Smax.romanov@nginx.com     nxt_app_t  *app;
733141Smax.romanov@nginx.com 
734141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
735133Sigor@sysoev.ru 
736133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
737133Sigor@sysoev.ru             return app;
738133Sigor@sysoev.ru         }
739141Smax.romanov@nginx.com 
740141Smax.romanov@nginx.com     } nxt_queue_loop;
741133Sigor@sysoev.ru 
742133Sigor@sysoev.ru     return NULL;
743133Sigor@sysoev.ru }
744133Sigor@sysoev.ru 
745133Sigor@sysoev.ru 
746133Sigor@sysoev.ru static nxt_app_t *
747133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
748133Sigor@sysoev.ru {
749133Sigor@sysoev.ru     nxt_app_t  *app;
750133Sigor@sysoev.ru 
751133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
752133Sigor@sysoev.ru 
753133Sigor@sysoev.ru     if (app == NULL) {
754134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
755133Sigor@sysoev.ru     }
756133Sigor@sysoev.ru 
757133Sigor@sysoev.ru     return app;
75853Sigor@sysoev.ru }
75953Sigor@sysoev.ru 
76053Sigor@sysoev.ru 
76153Sigor@sysoev.ru static nxt_socket_conf_t *
76265Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
76353Sigor@sysoev.ru {
764*163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
765*163Smax.romanov@nginx.com 
766*163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
767*163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
76853Sigor@sysoev.ru         return NULL;
76953Sigor@sysoev.ru     }
77053Sigor@sysoev.ru 
771*163Smax.romanov@nginx.com     skcf->sockaddr = sa;
772*163Smax.romanov@nginx.com 
773*163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
774*163Smax.romanov@nginx.com     skcf->listen.socklen = sa->socklen;
775*163Smax.romanov@nginx.com     skcf->listen.address_length = sa->length;
776*163Smax.romanov@nginx.com 
777*163Smax.romanov@nginx.com     skcf->listen.socket = -1;
778*163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
779*163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
780*163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
781*163Smax.romanov@nginx.com 
782*163Smax.romanov@nginx.com     return skcf;
78353Sigor@sysoev.ru }
78453Sigor@sysoev.ru 
78553Sigor@sysoev.ru 
78653Sigor@sysoev.ru static void
78753Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
78853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
78953Sigor@sysoev.ru {
79053Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
79153Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
79253Sigor@sysoev.ru 
79353Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
79453Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
79553Sigor@sysoev.ru          nqlk = next)
79653Sigor@sysoev.ru     {
79753Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
79853Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
79953Sigor@sysoev.ru 
80053Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
80153Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
80253Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
80353Sigor@sysoev.ru         {
80453Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
80553Sigor@sysoev.ru 
806115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
807115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
808115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
809115Sigor@sysoev.ru 
81053Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
81153Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
81253Sigor@sysoev.ru 
81353Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
81453Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
81553Sigor@sysoev.ru 
81653Sigor@sysoev.ru                 break;
81753Sigor@sysoev.ru             }
81853Sigor@sysoev.ru         }
81953Sigor@sysoev.ru     }
82053Sigor@sysoev.ru 
82153Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
822115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
82353Sigor@sysoev.ru }
82453Sigor@sysoev.ru 
82553Sigor@sysoev.ru 
82653Sigor@sysoev.ru static nxt_int_t
82753Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
82853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
82953Sigor@sysoev.ru {
830115Sigor@sysoev.ru     nxt_int_t            ret;
831115Sigor@sysoev.ru     nxt_socket_t         s;
832115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
833115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
834115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
83553Sigor@sysoev.ru 
83653Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
83753Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
83853Sigor@sysoev.ru          qlk = nqlk)
83953Sigor@sysoev.ru     {
840115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
841115Sigor@sysoev.ru 
842115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
843115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
844115Sigor@sysoev.ru             return NXT_ERROR;
845115Sigor@sysoev.ru         }
846115Sigor@sysoev.ru 
847115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
848115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
849148Sigor@sysoev.ru             goto fail;
850115Sigor@sysoev.ru         }
851115Sigor@sysoev.ru 
852115Sigor@sysoev.ru         skcf->listen.socket = s;
853115Sigor@sysoev.ru 
854148Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
855148Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
856148Sigor@sysoev.ru             goto fail;
857148Sigor@sysoev.ru         }
858148Sigor@sysoev.ru 
859148Sigor@sysoev.ru         rtsk->count = 0;
860148Sigor@sysoev.ru         rtsk->fd = skcf->listen.socket;
861148Sigor@sysoev.ru         skcf->socket = rtsk;
862115Sigor@sysoev.ru 
86353Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
86453Sigor@sysoev.ru         nxt_queue_remove(qlk);
86553Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
86653Sigor@sysoev.ru     }
86753Sigor@sysoev.ru 
86853Sigor@sysoev.ru     return NXT_OK;
869148Sigor@sysoev.ru 
870148Sigor@sysoev.ru fail:
871148Sigor@sysoev.ru 
872148Sigor@sysoev.ru     nxt_socket_close(task, s);
873148Sigor@sysoev.ru 
874148Sigor@sysoev.ru     return NXT_ERROR;
87553Sigor@sysoev.ru }
87653Sigor@sysoev.ru 
87753Sigor@sysoev.ru 
87853Sigor@sysoev.ru static nxt_int_t
87953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
88053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
88153Sigor@sysoev.ru {
88253Sigor@sysoev.ru     nxt_int_t                 ret;
88353Sigor@sysoev.ru     nxt_uint_t                n, threads;
88453Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
88553Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
88653Sigor@sysoev.ru 
88753Sigor@sysoev.ru     threads = tmcf->conf->threads;
88853Sigor@sysoev.ru 
88953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
89053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
89153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
89253Sigor@sysoev.ru         return NXT_ERROR;
89353Sigor@sysoev.ru     }
89453Sigor@sysoev.ru 
89553Sigor@sysoev.ru     n = 0;
89653Sigor@sysoev.ru 
89753Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
89853Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
89953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
90053Sigor@sysoev.ru     {
90153Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
90253Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
90353Sigor@sysoev.ru             return NXT_ERROR;
90453Sigor@sysoev.ru         }
90553Sigor@sysoev.ru 
906115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
90753Sigor@sysoev.ru 
90853Sigor@sysoev.ru         if (n < threads) {
909115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
91053Sigor@sysoev.ru 
91153Sigor@sysoev.ru         } else {
912115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
91353Sigor@sysoev.ru         }
91453Sigor@sysoev.ru 
91553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
91653Sigor@sysoev.ru             return ret;
91753Sigor@sysoev.ru         }
91853Sigor@sysoev.ru 
91953Sigor@sysoev.ru         n++;
92053Sigor@sysoev.ru     }
92153Sigor@sysoev.ru 
92253Sigor@sysoev.ru     tmcf->new_threads = n;
92353Sigor@sysoev.ru 
92453Sigor@sysoev.ru     while (n < threads) {
92553Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
92653Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
92753Sigor@sysoev.ru             return NXT_ERROR;
92853Sigor@sysoev.ru         }
92953Sigor@sysoev.ru 
93053Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
93153Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
93253Sigor@sysoev.ru             return NXT_ERROR;
93353Sigor@sysoev.ru         }
93453Sigor@sysoev.ru 
935115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
93653Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
93753Sigor@sysoev.ru             return ret;
93853Sigor@sysoev.ru         }
93953Sigor@sysoev.ru 
940115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
941115Sigor@sysoev.ru 
94253Sigor@sysoev.ru         n++;
94353Sigor@sysoev.ru     }
94453Sigor@sysoev.ru 
94553Sigor@sysoev.ru     return NXT_OK;
94653Sigor@sysoev.ru }
94753Sigor@sysoev.ru 
94853Sigor@sysoev.ru 
94953Sigor@sysoev.ru static nxt_int_t
950115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
951115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
95253Sigor@sysoev.ru {
953115Sigor@sysoev.ru     nxt_int_t              ret;
954115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
95553Sigor@sysoev.ru 
956154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
957154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
958115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
959115Sigor@sysoev.ru         return ret;
960115Sigor@sysoev.ru     }
961115Sigor@sysoev.ru 
962154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
963154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
96453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
96553Sigor@sysoev.ru         return ret;
96653Sigor@sysoev.ru     }
96753Sigor@sysoev.ru 
968115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
969115Sigor@sysoev.ru 
970115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
971115Sigor@sysoev.ru 
972115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
973115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
974115Sigor@sysoev.ru 
975115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
976115Sigor@sysoev.ru 
977115Sigor@sysoev.ru     return ret;
97853Sigor@sysoev.ru }
97953Sigor@sysoev.ru 
98053Sigor@sysoev.ru 
98153Sigor@sysoev.ru static nxt_int_t
982115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
983115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
98453Sigor@sysoev.ru {
985115Sigor@sysoev.ru     nxt_int_t              ret;
986115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
98753Sigor@sysoev.ru 
988154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
989154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
99053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
99153Sigor@sysoev.ru         return ret;
99253Sigor@sysoev.ru     }
99353Sigor@sysoev.ru 
994154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
995154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
99653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
99753Sigor@sysoev.ru         return ret;
99853Sigor@sysoev.ru     }
99953Sigor@sysoev.ru 
1000139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1001115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1002115Sigor@sysoev.ru         return ret;
1003115Sigor@sysoev.ru     }
1004115Sigor@sysoev.ru 
1005115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1006115Sigor@sysoev.ru 
1007115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1008115Sigor@sysoev.ru 
1009115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1010115Sigor@sysoev.ru 
1011115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1012115Sigor@sysoev.ru 
1013115Sigor@sysoev.ru     return ret;
101453Sigor@sysoev.ru }
101553Sigor@sysoev.ru 
101653Sigor@sysoev.ru 
101753Sigor@sysoev.ru static nxt_int_t
1018115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1019115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
102053Sigor@sysoev.ru {
102153Sigor@sysoev.ru     nxt_int_t  ret;
102253Sigor@sysoev.ru 
1023139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
102453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
102553Sigor@sysoev.ru         return ret;
102653Sigor@sysoev.ru     }
102753Sigor@sysoev.ru 
1028139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
102953Sigor@sysoev.ru }
103053Sigor@sysoev.ru 
103153Sigor@sysoev.ru 
103253Sigor@sysoev.ru static nxt_int_t
1033154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1034154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
103553Sigor@sysoev.ru     nxt_work_handler_t handler)
103653Sigor@sysoev.ru {
1037153Sigor@sysoev.ru     nxt_joint_job_t          *job;
103853Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1039155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
104053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
104153Sigor@sysoev.ru 
104253Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
104353Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
104453Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
104553Sigor@sysoev.ru     {
1046154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1047153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1048139Sigor@sysoev.ru             return NXT_ERROR;
1049139Sigor@sysoev.ru         }
1050139Sigor@sysoev.ru 
1051154Sigor@sysoev.ru         job->work.next = recf->jobs;
1052154Sigor@sysoev.ru         recf->jobs = &job->work;
1053154Sigor@sysoev.ru 
1054153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1055153Sigor@sysoev.ru         job->work.handler = handler;
1056153Sigor@sysoev.ru         job->work.task = &job->task;
1057153Sigor@sysoev.ru         job->work.obj = job;
1058153Sigor@sysoev.ru         job->tmcf = tmcf;
105953Sigor@sysoev.ru 
1060154Sigor@sysoev.ru         tmcf->count++;
1061154Sigor@sysoev.ru 
1062154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1063154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
106453Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
106553Sigor@sysoev.ru             return NXT_ERROR;
106653Sigor@sysoev.ru         }
106753Sigor@sysoev.ru 
1068153Sigor@sysoev.ru         job->work.data = joint;
106953Sigor@sysoev.ru 
107053Sigor@sysoev.ru         joint->count = 1;
1071155Sigor@sysoev.ru 
1072155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1073155Sigor@sysoev.ru         skcf->count++;
1074155Sigor@sysoev.ru         joint->socket_conf = skcf;
1075155Sigor@sysoev.ru 
107688Smax.romanov@nginx.com         joint->engine = recf->engine;
107753Sigor@sysoev.ru     }
107853Sigor@sysoev.ru 
107920Sigor@sysoev.ru     return NXT_OK;
108020Sigor@sysoev.ru }
108120Sigor@sysoev.ru 
108220Sigor@sysoev.ru 
1083115Sigor@sysoev.ru static void
1084115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1085115Sigor@sysoev.ru {
1086115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1087115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1088115Sigor@sysoev.ru 
1089115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1090115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1091115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1092115Sigor@sysoev.ru     {
1093115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1094115Sigor@sysoev.ru         skcf->socket->count++;
1095115Sigor@sysoev.ru     }
1096115Sigor@sysoev.ru }
1097115Sigor@sysoev.ru 
1098115Sigor@sysoev.ru 
109920Sigor@sysoev.ru static nxt_int_t
1100139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1101139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
110220Sigor@sysoev.ru {
1103153Sigor@sysoev.ru     nxt_joint_job_t   *job;
110453Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
110520Sigor@sysoev.ru 
110653Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
110753Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
110853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
110953Sigor@sysoev.ru     {
1110154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1111153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1112139Sigor@sysoev.ru             return NXT_ERROR;
1113139Sigor@sysoev.ru         }
1114139Sigor@sysoev.ru 
1115154Sigor@sysoev.ru         job->work.next = recf->jobs;
1116154Sigor@sysoev.ru         recf->jobs = &job->work;
1117154Sigor@sysoev.ru 
1118153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1119153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1120153Sigor@sysoev.ru         job->work.task = &job->task;
1121153Sigor@sysoev.ru         job->work.obj = job;
1122153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1123153Sigor@sysoev.ru         job->tmcf = tmcf;
1124154Sigor@sysoev.ru 
1125154Sigor@sysoev.ru         tmcf->count++;
112620Sigor@sysoev.ru     }
112720Sigor@sysoev.ru 
112853Sigor@sysoev.ru     return NXT_OK;
112953Sigor@sysoev.ru }
113020Sigor@sysoev.ru 
113120Sigor@sysoev.ru 
113253Sigor@sysoev.ru static nxt_int_t
113353Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
113453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
113553Sigor@sysoev.ru {
113653Sigor@sysoev.ru     nxt_int_t                 ret;
113753Sigor@sysoev.ru     nxt_uint_t                i, threads;
113853Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
113920Sigor@sysoev.ru 
114053Sigor@sysoev.ru     recf = tmcf->engines->elts;
114153Sigor@sysoev.ru     threads = tmcf->conf->threads;
114220Sigor@sysoev.ru 
114353Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
114453Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
114553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
114653Sigor@sysoev.ru             return ret;
114753Sigor@sysoev.ru         }
114820Sigor@sysoev.ru     }
114920Sigor@sysoev.ru 
115020Sigor@sysoev.ru     return NXT_OK;
115120Sigor@sysoev.ru }
115253Sigor@sysoev.ru 
115353Sigor@sysoev.ru 
115453Sigor@sysoev.ru static nxt_int_t
115553Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
115653Sigor@sysoev.ru     nxt_event_engine_t *engine)
115753Sigor@sysoev.ru {
115853Sigor@sysoev.ru     nxt_int_t            ret;
115953Sigor@sysoev.ru     nxt_thread_link_t    *link;
116053Sigor@sysoev.ru     nxt_thread_handle_t  handle;
116153Sigor@sysoev.ru 
116253Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
116353Sigor@sysoev.ru 
116453Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
116553Sigor@sysoev.ru         return NXT_ERROR;
116653Sigor@sysoev.ru     }
116753Sigor@sysoev.ru 
116853Sigor@sysoev.ru     link->start = nxt_router_thread_start;
116953Sigor@sysoev.ru     link->engine = engine;
117053Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
117153Sigor@sysoev.ru     link->work.task = task;
117253Sigor@sysoev.ru     link->work.data = link;
117353Sigor@sysoev.ru 
117453Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
117553Sigor@sysoev.ru 
117653Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
117753Sigor@sysoev.ru 
117853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
117953Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
118053Sigor@sysoev.ru     }
118153Sigor@sysoev.ru 
118253Sigor@sysoev.ru     return ret;
118353Sigor@sysoev.ru }
118453Sigor@sysoev.ru 
118553Sigor@sysoev.ru 
118653Sigor@sysoev.ru static void
1187133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1188133Sigor@sysoev.ru {
1189*163Smax.romanov@nginx.com     nxt_app_t   *app;
1190*163Smax.romanov@nginx.com     nxt_port_t  *port;
1191141Smax.romanov@nginx.com 
1192141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1193133Sigor@sysoev.ru 
1194133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1195133Sigor@sysoev.ru 
1196*163Smax.romanov@nginx.com         app->live = 0;
1197*163Smax.romanov@nginx.com 
1198*163Smax.romanov@nginx.com         if (nxt_router_app_free(app) != 0) {
1199*163Smax.romanov@nginx.com             continue;
1200*163Smax.romanov@nginx.com         }
1201*163Smax.romanov@nginx.com 
1202*163Smax.romanov@nginx.com         if (nxt_queue_is_empty(&app->requests)) {
1203*163Smax.romanov@nginx.com 
1204*163Smax.romanov@nginx.com             do {
1205*163Smax.romanov@nginx.com                 port = nxt_router_app_get_port(app);
1206*163Smax.romanov@nginx.com                 if (port == NULL) {
1207*163Smax.romanov@nginx.com                     break;
1208*163Smax.romanov@nginx.com                 }
1209*163Smax.romanov@nginx.com 
1210*163Smax.romanov@nginx.com                 nxt_port_socket_write(&port->engine->task, port,
1211*163Smax.romanov@nginx.com                                       NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
1212*163Smax.romanov@nginx.com             } while (1);
1213*163Smax.romanov@nginx.com 
1214*163Smax.romanov@nginx.com         }
1215*163Smax.romanov@nginx.com 
1216141Smax.romanov@nginx.com     } nxt_queue_loop;
1217133Sigor@sysoev.ru 
1218133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1219133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1220133Sigor@sysoev.ru }
1221133Sigor@sysoev.ru 
1222133Sigor@sysoev.ru 
1223133Sigor@sysoev.ru static void
122453Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
122553Sigor@sysoev.ru {
122653Sigor@sysoev.ru     nxt_uint_t                n;
122753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
122853Sigor@sysoev.ru 
122953Sigor@sysoev.ru     recf = tmcf->engines->elts;
123053Sigor@sysoev.ru 
123153Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1232154Sigor@sysoev.ru         nxt_router_engine_post(recf);
123353Sigor@sysoev.ru         recf++;
123453Sigor@sysoev.ru     }
123553Sigor@sysoev.ru }
123653Sigor@sysoev.ru 
123753Sigor@sysoev.ru 
123853Sigor@sysoev.ru static void
1239154Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
124053Sigor@sysoev.ru {
1241154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1242154Sigor@sysoev.ru 
1243154Sigor@sysoev.ru     for (work = recf->jobs; work != NULL; work = next) {
1244154Sigor@sysoev.ru         next = work->next;
1245154Sigor@sysoev.ru         work->next = NULL;
1246154Sigor@sysoev.ru 
1247154Sigor@sysoev.ru         nxt_event_engine_post(recf->engine, work);
124853Sigor@sysoev.ru     }
124953Sigor@sysoev.ru }
125053Sigor@sysoev.ru 
125153Sigor@sysoev.ru 
125253Sigor@sysoev.ru static void
1253119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
125488Smax.romanov@nginx.com 
1255119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
125688Smax.romanov@nginx.com     NULL,
125788Smax.romanov@nginx.com     nxt_port_new_port_handler,
125888Smax.romanov@nginx.com     nxt_port_change_log_file_handler,
125988Smax.romanov@nginx.com     nxt_port_mmap_handler,
1260119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1261125Smax.romanov@nginx.com     nxt_port_remove_pid_handler,
126288Smax.romanov@nginx.com };
126388Smax.romanov@nginx.com 
126488Smax.romanov@nginx.com 
126588Smax.romanov@nginx.com static void
126653Sigor@sysoev.ru nxt_router_thread_start(void *data)
126753Sigor@sysoev.ru {
1268141Smax.romanov@nginx.com     nxt_int_t           ret;
1269141Smax.romanov@nginx.com     nxt_port_t          *port;
127088Smax.romanov@nginx.com     nxt_task_t          *task;
127153Sigor@sysoev.ru     nxt_thread_t        *thread;
127253Sigor@sysoev.ru     nxt_thread_link_t   *link;
127353Sigor@sysoev.ru     nxt_event_engine_t  *engine;
127453Sigor@sysoev.ru 
127553Sigor@sysoev.ru     link = data;
127653Sigor@sysoev.ru     engine = link->engine;
127788Smax.romanov@nginx.com     task = &engine->task;
127853Sigor@sysoev.ru 
127953Sigor@sysoev.ru     thread = nxt_thread();
128053Sigor@sysoev.ru 
128153Sigor@sysoev.ru     /* STUB */
128253Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
128353Sigor@sysoev.ru 
128453Sigor@sysoev.ru     engine->task.thread = thread;
128553Sigor@sysoev.ru     engine->task.log = thread->log;
128653Sigor@sysoev.ru     thread->engine = engine;
128763Sigor@sysoev.ru     thread->task = &engine->task;
128853Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
128953Sigor@sysoev.ru 
129063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
129153Sigor@sysoev.ru 
1292*163Smax.romanov@nginx.com     port = nxt_port_new(nxt_port_get_next_id(), nxt_pid, NXT_PROCESS_ROUTER);
1293141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1294141Smax.romanov@nginx.com         return;
1295141Smax.romanov@nginx.com     }
1296141Smax.romanov@nginx.com 
1297141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1298141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1299*163Smax.romanov@nginx.com         nxt_mp_release(port->mem_pool, port);
1300141Smax.romanov@nginx.com         return;
1301141Smax.romanov@nginx.com     }
1302141Smax.romanov@nginx.com 
1303141Smax.romanov@nginx.com     engine->port = port;
1304141Smax.romanov@nginx.com 
1305141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1306141Smax.romanov@nginx.com 
130753Sigor@sysoev.ru     nxt_event_engine_start(engine);
130853Sigor@sysoev.ru }
130953Sigor@sysoev.ru 
131053Sigor@sysoev.ru 
131153Sigor@sysoev.ru static void
131253Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
131353Sigor@sysoev.ru {
1314153Sigor@sysoev.ru     nxt_joint_job_t          *job;
131553Sigor@sysoev.ru     nxt_listen_event_t       *listen;
131653Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
131753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
131853Sigor@sysoev.ru 
1319153Sigor@sysoev.ru     job = obj;
132053Sigor@sysoev.ru     joint = data;
132153Sigor@sysoev.ru 
132253Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
132353Sigor@sysoev.ru 
1324159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1325159Sigor@sysoev.ru 
132653Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
132753Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
132853Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
132953Sigor@sysoev.ru         return;
133053Sigor@sysoev.ru     }
133153Sigor@sysoev.ru 
133253Sigor@sysoev.ru     listen->socket.data = joint;
1333139Sigor@sysoev.ru 
1334153Sigor@sysoev.ru     job->work.next = NULL;
1335153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1336153Sigor@sysoev.ru 
1337153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
133853Sigor@sysoev.ru }
133953Sigor@sysoev.ru 
134053Sigor@sysoev.ru 
134153Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
134253Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
134353Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
134453Sigor@sysoev.ru {
1345115Sigor@sysoev.ru     nxt_socket_t        fd;
1346115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
134753Sigor@sysoev.ru     nxt_listen_event_t  *listen;
134853Sigor@sysoev.ru 
1349115Sigor@sysoev.ru     fd = skcf->socket->fd;
135053Sigor@sysoev.ru 
1351115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1352115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1353115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
135453Sigor@sysoev.ru     {
1355115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
135653Sigor@sysoev.ru 
1357115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
135853Sigor@sysoev.ru             return listen;
135953Sigor@sysoev.ru         }
136053Sigor@sysoev.ru     }
136153Sigor@sysoev.ru 
136253Sigor@sysoev.ru     return NULL;
136353Sigor@sysoev.ru }
136453Sigor@sysoev.ru 
136553Sigor@sysoev.ru 
136653Sigor@sysoev.ru static void
136753Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
136853Sigor@sysoev.ru {
1369153Sigor@sysoev.ru     nxt_joint_job_t          *job;
137053Sigor@sysoev.ru     nxt_event_engine_t       *engine;
137153Sigor@sysoev.ru     nxt_listen_event_t       *listen;
137253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
137353Sigor@sysoev.ru 
1374153Sigor@sysoev.ru     job = obj;
137553Sigor@sysoev.ru     joint = data;
137653Sigor@sysoev.ru 
1377139Sigor@sysoev.ru     engine = task->thread->engine;
1378139Sigor@sysoev.ru 
1379159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
1380159Sigor@sysoev.ru 
138153Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
138253Sigor@sysoev.ru                                      joint->socket_conf);
138353Sigor@sysoev.ru 
138453Sigor@sysoev.ru     old = listen->socket.data;
138553Sigor@sysoev.ru     listen->socket.data = joint;
138653Sigor@sysoev.ru 
1387153Sigor@sysoev.ru     job->work.next = NULL;
1388153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1389153Sigor@sysoev.ru 
1390153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
1391139Sigor@sysoev.ru 
139253Sigor@sysoev.ru     nxt_router_conf_release(task, old);
139353Sigor@sysoev.ru }
139453Sigor@sysoev.ru 
139553Sigor@sysoev.ru 
139653Sigor@sysoev.ru static void
139753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
139853Sigor@sysoev.ru {
1399153Sigor@sysoev.ru     nxt_joint_job_t     *job;
1400153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
1401153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
1402153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1403153Sigor@sysoev.ru 
1404153Sigor@sysoev.ru     job = obj;
140553Sigor@sysoev.ru     skcf = data;
140653Sigor@sysoev.ru 
1407139Sigor@sysoev.ru     engine = task->thread->engine;
1408139Sigor@sysoev.ru 
140953Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
141053Sigor@sysoev.ru 
141153Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
141253Sigor@sysoev.ru 
1413*163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
1414*163Smax.romanov@nginx.com               listen->socket.fd);
1415*163Smax.romanov@nginx.com 
141653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
141753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
141853Sigor@sysoev.ru 
141953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1420139Sigor@sysoev.ru 
1421153Sigor@sysoev.ru     job->work.next = NULL;
1422153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1423153Sigor@sysoev.ru 
1424153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
142553Sigor@sysoev.ru }
142653Sigor@sysoev.ru 
142753Sigor@sysoev.ru 
142853Sigor@sysoev.ru static void
142953Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
143053Sigor@sysoev.ru {
143153Sigor@sysoev.ru     nxt_timer_t              *timer;
143253Sigor@sysoev.ru     nxt_listen_event_t       *listen;
143353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
143453Sigor@sysoev.ru 
143553Sigor@sysoev.ru     timer = obj;
143653Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
143753Sigor@sysoev.ru     joint = listen->socket.data;
143853Sigor@sysoev.ru 
1439*163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
1440*163Smax.romanov@nginx.com               listen->socket.fd);
1441*163Smax.romanov@nginx.com 
144253Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1443123Smax.romanov@nginx.com 
1444123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1445123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1446123Smax.romanov@nginx.com 
144753Sigor@sysoev.ru     nxt_free(listen);
144853Sigor@sysoev.ru 
144953Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
145053Sigor@sysoev.ru }
145153Sigor@sysoev.ru 
145253Sigor@sysoev.ru 
145353Sigor@sysoev.ru static void
145453Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
145553Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
145653Sigor@sysoev.ru {
1457118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1458115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
145953Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
146053Sigor@sysoev.ru 
1461118Sigor@sysoev.ru     skcf = joint->socket_conf;
1462118Sigor@sysoev.ru     rtsk = skcf->socket;
1463118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
146453Sigor@sysoev.ru 
146553Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
146653Sigor@sysoev.ru 
1467*163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
1468*163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
1469*163Smax.romanov@nginx.com 
1470115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1471115Sigor@sysoev.ru         rtsk = NULL;
147253Sigor@sysoev.ru     }
147353Sigor@sysoev.ru 
147453Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
147553Sigor@sysoev.ru 
1476115Sigor@sysoev.ru     if (rtsk != NULL) {
1477115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1478115Sigor@sysoev.ru         nxt_free(rtsk);
1479118Sigor@sysoev.ru         skcf->socket = NULL;
148053Sigor@sysoev.ru     }
148153Sigor@sysoev.ru 
148253Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
148353Sigor@sysoev.ru }
148453Sigor@sysoev.ru 
148553Sigor@sysoev.ru 
148653Sigor@sysoev.ru static void
148753Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
148853Sigor@sysoev.ru {
1489156Sigor@sysoev.ru     nxt_bool_t             exit;
149053Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
149153Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
149253Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
149353Sigor@sysoev.ru 
1494*163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
149553Sigor@sysoev.ru 
149653Sigor@sysoev.ru     if (--joint->count != 0) {
149753Sigor@sysoev.ru         return;
149853Sigor@sysoev.ru     }
149953Sigor@sysoev.ru 
150053Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
150153Sigor@sysoev.ru 
150253Sigor@sysoev.ru     skcf = joint->socket_conf;
150353Sigor@sysoev.ru     rtcf = skcf->router_conf;
150453Sigor@sysoev.ru     lock = &rtcf->router->lock;
150553Sigor@sysoev.ru 
150653Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
150753Sigor@sysoev.ru 
1508*163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
1509*163Smax.romanov@nginx.com               rtcf, rtcf->count);
1510*163Smax.romanov@nginx.com 
151153Sigor@sysoev.ru     if (--skcf->count != 0) {
151253Sigor@sysoev.ru         rtcf = NULL;
151353Sigor@sysoev.ru 
151453Sigor@sysoev.ru     } else {
151553Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
151653Sigor@sysoev.ru 
151753Sigor@sysoev.ru         if (--rtcf->count != 0) {
151853Sigor@sysoev.ru             rtcf = NULL;
151953Sigor@sysoev.ru         }
152053Sigor@sysoev.ru     }
152153Sigor@sysoev.ru 
152253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
152353Sigor@sysoev.ru 
1524141Smax.romanov@nginx.com     /* TODO remove engine->port */
1525141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1526141Smax.romanov@nginx.com 
1527156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
1528156Sigor@sysoev.ru     exit = nxt_queue_is_empty(&joint->engine->joints);
1529156Sigor@sysoev.ru 
153053Sigor@sysoev.ru     if (rtcf != NULL) {
1531115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1532131Smax.romanov@nginx.com 
1533131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1534131Smax.romanov@nginx.com 
153565Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
153653Sigor@sysoev.ru     }
153753Sigor@sysoev.ru 
1538156Sigor@sysoev.ru     if (exit) {
153953Sigor@sysoev.ru         nxt_thread_exit(task->thread);
154053Sigor@sysoev.ru     }
154153Sigor@sysoev.ru }
154253Sigor@sysoev.ru 
154353Sigor@sysoev.ru 
154453Sigor@sysoev.ru static void
154553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
154653Sigor@sysoev.ru {
1547141Smax.romanov@nginx.com     nxt_port_t           *port;
154853Sigor@sysoev.ru     nxt_thread_link_t    *link;
154953Sigor@sysoev.ru     nxt_event_engine_t   *engine;
155053Sigor@sysoev.ru     nxt_thread_handle_t  handle;
155153Sigor@sysoev.ru 
155258Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
155353Sigor@sysoev.ru     link = data;
155453Sigor@sysoev.ru 
155553Sigor@sysoev.ru     nxt_thread_wait(handle);
155653Sigor@sysoev.ru 
155753Sigor@sysoev.ru     engine = link->engine;
155853Sigor@sysoev.ru 
155953Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
156053Sigor@sysoev.ru 
1561141Smax.romanov@nginx.com     port = engine->port;
1562141Smax.romanov@nginx.com 
1563141Smax.romanov@nginx.com     // TODO notify all apps
1564141Smax.romanov@nginx.com 
1565*163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
1566*163Smax.romanov@nginx.com     nxt_port_release(port);
1567*163Smax.romanov@nginx.com 
1568*163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
156963Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
157053Sigor@sysoev.ru 
157153Sigor@sysoev.ru     nxt_event_engine_free(engine);
157253Sigor@sysoev.ru 
157353Sigor@sysoev.ru     nxt_free(link);
157453Sigor@sysoev.ru }
157553Sigor@sysoev.ru 
157653Sigor@sysoev.ru 
157762Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_read_state
157853Sigor@sysoev.ru     nxt_aligned(64) =
157953Sigor@sysoev.ru {
158053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
158153Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
158253Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
158353Sigor@sysoev.ru 
158453Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
158553Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
158653Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
158753Sigor@sysoev.ru };
158853Sigor@sysoev.ru 
158953Sigor@sysoev.ru 
159053Sigor@sysoev.ru static void
159153Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
159253Sigor@sysoev.ru {
159353Sigor@sysoev.ru     size_t                   size;
159462Sigor@sysoev.ru     nxt_conn_t               *c;
159553Sigor@sysoev.ru     nxt_event_engine_t       *engine;
159653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
159753Sigor@sysoev.ru 
159853Sigor@sysoev.ru     c = obj;
159953Sigor@sysoev.ru     joint = data;
160053Sigor@sysoev.ru 
160153Sigor@sysoev.ru     nxt_debug(task, "router conn init");
160253Sigor@sysoev.ru 
160353Sigor@sysoev.ru     joint->count++;
160453Sigor@sysoev.ru 
160553Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
160653Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
160753Sigor@sysoev.ru 
160853Sigor@sysoev.ru     c->socket.data = NULL;
160953Sigor@sysoev.ru 
161053Sigor@sysoev.ru     engine = task->thread->engine;
161153Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
161253Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
161353Sigor@sysoev.ru 
161453Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
161553Sigor@sysoev.ru 
161662Sigor@sysoev.ru     nxt_conn_read(engine, c);
161753Sigor@sysoev.ru }
161853Sigor@sysoev.ru 
161953Sigor@sysoev.ru 
162062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
162153Sigor@sysoev.ru     nxt_aligned(64) =
162253Sigor@sysoev.ru {
162388Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
162453Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
162553Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
162653Sigor@sysoev.ru };
162753Sigor@sysoev.ru 
162853Sigor@sysoev.ru 
162953Sigor@sysoev.ru static void
1630119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
163188Smax.romanov@nginx.com {
163288Smax.romanov@nginx.com     size_t               dump_size;
163388Smax.romanov@nginx.com     nxt_buf_t            *b, *i, *last;
163488Smax.romanov@nginx.com     nxt_conn_t           *c;
163588Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
163688Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
163788Smax.romanov@nginx.com 
163888Smax.romanov@nginx.com     b = msg->buf;
163988Smax.romanov@nginx.com     engine = task->thread->engine;
164088Smax.romanov@nginx.com 
164188Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
164288Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
164388Smax.romanov@nginx.com 
164488Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
164588Smax.romanov@nginx.com 
164695Smax.romanov@nginx.com         /* Mark buffers as read. */
164788Smax.romanov@nginx.com         for (i = b; i != NULL; i = i->next) {
164888Smax.romanov@nginx.com             i->mem.pos = i->mem.free;
164988Smax.romanov@nginx.com         }
165088Smax.romanov@nginx.com 
165188Smax.romanov@nginx.com         return;
165288Smax.romanov@nginx.com     }
165388Smax.romanov@nginx.com 
165488Smax.romanov@nginx.com     c = rc->conn;
165588Smax.romanov@nginx.com 
165688Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
165788Smax.romanov@nginx.com 
165888Smax.romanov@nginx.com     if (dump_size > 300) {
165988Smax.romanov@nginx.com         dump_size = 300;
166088Smax.romanov@nginx.com     }
166188Smax.romanov@nginx.com 
1662119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
166388Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
166488Smax.romanov@nginx.com               b->mem.pos);
166588Smax.romanov@nginx.com 
166688Smax.romanov@nginx.com     if (msg->size == 0) {
166788Smax.romanov@nginx.com         b = NULL;
166888Smax.romanov@nginx.com     }
166988Smax.romanov@nginx.com 
167088Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
167188Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
167288Smax.romanov@nginx.com 
167388Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
167488Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
167588Smax.romanov@nginx.com             /* TODO pogorevaTb */
167688Smax.romanov@nginx.com         }
167788Smax.romanov@nginx.com 
167888Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
167988Smax.romanov@nginx.com     }
168088Smax.romanov@nginx.com 
168188Smax.romanov@nginx.com     if (b == NULL) {
168288Smax.romanov@nginx.com         return;
168388Smax.romanov@nginx.com     }
168488Smax.romanov@nginx.com 
168588Smax.romanov@nginx.com     if (c->write == NULL) {
168688Smax.romanov@nginx.com         c->write = b;
168788Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
168888Smax.romanov@nginx.com 
168988Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
169088Smax.romanov@nginx.com     } else {
169188Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
169288Smax.romanov@nginx.com 
169388Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
169488Smax.romanov@nginx.com     }
169588Smax.romanov@nginx.com }
169688Smax.romanov@nginx.com 
1697141Smax.romanov@nginx.com nxt_inline const char *
1698141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
1699141Smax.romanov@nginx.com {
1700141Smax.romanov@nginx.com     switch (code) {
1701141Smax.romanov@nginx.com     case 400: return "Bad request";
1702141Smax.romanov@nginx.com     case 404: return "Not found";
1703141Smax.romanov@nginx.com     case 403: return "Forbidden";
1704141Smax.romanov@nginx.com     case 500:
1705141Smax.romanov@nginx.com     default:  return "Internal server error";
1706141Smax.romanov@nginx.com     }
1707141Smax.romanov@nginx.com }
1708141Smax.romanov@nginx.com 
1709*163Smax.romanov@nginx.com 
1710*163Smax.romanov@nginx.com static nxt_buf_t *
1711*163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
1712*163Smax.romanov@nginx.com     const char* fmt, va_list args)
171388Smax.romanov@nginx.com {
1714*163Smax.romanov@nginx.com     nxt_buf_t   *b, *last;
1715*163Smax.romanov@nginx.com     const char  *msg;
1716*163Smax.romanov@nginx.com 
1717*163Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, mp, 16384);
1718141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1719*163Smax.romanov@nginx.com         return NULL;
1720141Smax.romanov@nginx.com     }
1721141Smax.romanov@nginx.com 
1722141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
1723141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
1724141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
1725141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
1726141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
1727141Smax.romanov@nginx.com 
1728141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
1729141Smax.romanov@nginx.com 
1730141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
1731141Smax.romanov@nginx.com 
1732141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
1733141Smax.romanov@nginx.com 
1734*163Smax.romanov@nginx.com     last = nxt_buf_mem_ts_alloc(task, mp, 0);
1735*163Smax.romanov@nginx.com 
1736141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
1737*163Smax.romanov@nginx.com         nxt_mp_release(mp, b);
1738*163Smax.romanov@nginx.com         return NULL;
1739141Smax.romanov@nginx.com     }
1740141Smax.romanov@nginx.com 
1741*163Smax.romanov@nginx.com     nxt_buf_set_sync(last);
1742*163Smax.romanov@nginx.com     nxt_buf_set_last(last);
1743*163Smax.romanov@nginx.com 
1744141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
1745141Smax.romanov@nginx.com 
1746*163Smax.romanov@nginx.com     return b;
1747*163Smax.romanov@nginx.com }
1748*163Smax.romanov@nginx.com 
1749*163Smax.romanov@nginx.com 
1750*163Smax.romanov@nginx.com 
1751*163Smax.romanov@nginx.com static void
1752*163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
1753*163Smax.romanov@nginx.com     const char* fmt, ...)
1754*163Smax.romanov@nginx.com {
1755*163Smax.romanov@nginx.com     va_list    args;
1756*163Smax.romanov@nginx.com     nxt_buf_t  *b;
1757*163Smax.romanov@nginx.com 
1758*163Smax.romanov@nginx.com     va_start(args, fmt);
1759*163Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args);
1760*163Smax.romanov@nginx.com     va_end(args);
1761*163Smax.romanov@nginx.com 
1762141Smax.romanov@nginx.com     if (c->write == NULL) {
1763141Smax.romanov@nginx.com         c->write = b;
1764141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
1765141Smax.romanov@nginx.com 
1766141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
1767141Smax.romanov@nginx.com     } else {
1768141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
1769141Smax.romanov@nginx.com 
1770141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
1771141Smax.romanov@nginx.com     }
1772141Smax.romanov@nginx.com }
1773141Smax.romanov@nginx.com 
1774141Smax.romanov@nginx.com 
1775141Smax.romanov@nginx.com static void
1776141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
1777141Smax.romanov@nginx.com {
1778141Smax.romanov@nginx.com     nxt_buf_t           *b;
1779141Smax.romanov@nginx.com     nxt_app_t           *app;
1780141Smax.romanov@nginx.com     nxt_port_t          *port;
1781141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
1782141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1783141Smax.romanov@nginx.com 
1784141Smax.romanov@nginx.com     sw = obj;
1785141Smax.romanov@nginx.com     app = sw->app;
1786141Smax.romanov@nginx.com 
1787*163Smax.romanov@nginx.com     if (app->workers + app->pending_workers >= app->max_workers) {
1788*163Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
1789*163Smax.romanov@nginx.com 
1790*163Smax.romanov@nginx.com         nxt_debug(task, "%uD/%uD running/penging workers, post sw #%uxD "
1791*163Smax.romanov@nginx.com                   "release to %p", sw->stream, sw->work.data);
1792*163Smax.romanov@nginx.com 
1793*163Smax.romanov@nginx.com         nxt_event_engine_post(sw->work.data, &sw->work);
1794*163Smax.romanov@nginx.com 
1795*163Smax.romanov@nginx.com         return;
1796*163Smax.romanov@nginx.com     }
1797*163Smax.romanov@nginx.com 
1798*163Smax.romanov@nginx.com     app->pending_workers++;
1799*163Smax.romanov@nginx.com 
1800141Smax.romanov@nginx.com     nxt_debug(task, "send sw #%uD", sw->stream);
1801141Smax.romanov@nginx.com 
1802141Smax.romanov@nginx.com     nxt_router_sw_add(task, nxt_router, sw);
1803141Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->rc->app_link);
180488Smax.romanov@nginx.com 
1805119Smax.romanov@nginx.com     rt = task->thread->runtime;
1806141Smax.romanov@nginx.com     port = rt->port_by_type[NXT_PROCESS_MASTER];
1807141Smax.romanov@nginx.com 
1808141Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(port->mem_pool, app->conf.length, 0);
1809141Smax.romanov@nginx.com 
1810141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1811141Smax.romanov@nginx.com 
1812141Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_DATA, -1, sw->stream, 0, b);
1813141Smax.romanov@nginx.com }
1814141Smax.romanov@nginx.com 
1815141Smax.romanov@nginx.com 
1816*163Smax.romanov@nginx.com static nxt_bool_t
1817*163Smax.romanov@nginx.com nxt_router_app_free(nxt_app_t *app)
1818*163Smax.romanov@nginx.com {
1819*163Smax.romanov@nginx.com     if (app->live == 0 && app->workers == 0 &&
1820*163Smax.romanov@nginx.com         app->pending_workers == 0 &&
1821*163Smax.romanov@nginx.com         nxt_queue_is_empty(&app->requests)) {
1822*163Smax.romanov@nginx.com 
1823*163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
1824*163Smax.romanov@nginx.com         nxt_free(app);
1825*163Smax.romanov@nginx.com 
1826*163Smax.romanov@nginx.com         return 1;
1827*163Smax.romanov@nginx.com     }
1828*163Smax.romanov@nginx.com 
1829*163Smax.romanov@nginx.com     return 0;
1830*163Smax.romanov@nginx.com }
1831*163Smax.romanov@nginx.com 
1832*163Smax.romanov@nginx.com 
1833141Smax.romanov@nginx.com static nxt_port_t *
1834141Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app)
1835141Smax.romanov@nginx.com {
1836141Smax.romanov@nginx.com     nxt_port_t        *port;
1837141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
1838141Smax.romanov@nginx.com 
1839141Smax.romanov@nginx.com     port = NULL;
1840141Smax.romanov@nginx.com 
1841141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1842141Smax.romanov@nginx.com 
1843141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
1844141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
1845141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1846141Smax.romanov@nginx.com 
1847141Smax.romanov@nginx.com         lnk->next = NULL;
1848141Smax.romanov@nginx.com 
1849141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
1850141Smax.romanov@nginx.com     }
1851141Smax.romanov@nginx.com 
1852141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1853141Smax.romanov@nginx.com 
1854141Smax.romanov@nginx.com     return port;
1855141Smax.romanov@nginx.com }
1856141Smax.romanov@nginx.com 
1857141Smax.romanov@nginx.com 
1858141Smax.romanov@nginx.com static void
1859141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
1860141Smax.romanov@nginx.com {
1861141Smax.romanov@nginx.com     nxt_app_t            *app;
1862141Smax.romanov@nginx.com     nxt_port_t           *port;
1863141Smax.romanov@nginx.com     nxt_work_t           *work;
1864*163Smax.romanov@nginx.com     nxt_process_t        *process;
1865141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
1866141Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
1867141Smax.romanov@nginx.com 
1868141Smax.romanov@nginx.com     port = obj;
1869141Smax.romanov@nginx.com     app = data;
1870141Smax.romanov@nginx.com 
1871141Smax.romanov@nginx.com     nxt_assert(app != NULL);
1872141Smax.romanov@nginx.com     nxt_assert(app == port->app);
1873141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
1874141Smax.romanov@nginx.com 
1875141Smax.romanov@nginx.com 
1876141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
1877*163Smax.romanov@nginx.com         work = &port->work;
1878141Smax.romanov@nginx.com 
1879141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
1880141Smax.romanov@nginx.com 
1881141Smax.romanov@nginx.com         work->next = NULL;
1882141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
1883141Smax.romanov@nginx.com         work->task = port->socket.task;
1884141Smax.romanov@nginx.com         work->obj = port;
1885141Smax.romanov@nginx.com         work->data = app;
1886141Smax.romanov@nginx.com 
1887141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
1888141Smax.romanov@nginx.com 
1889141Smax.romanov@nginx.com         return;
1890141Smax.romanov@nginx.com     }
1891141Smax.romanov@nginx.com 
1892141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
1893141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
1894141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1895141Smax.romanov@nginx.com 
1896141Smax.romanov@nginx.com         rc = nxt_queue_link_data(lnk, nxt_req_conn_link_t, app_link);
1897141Smax.romanov@nginx.com 
1898*163Smax.romanov@nginx.com         nxt_debug(task, "app '%V' process next request #%uxD",
1899*163Smax.romanov@nginx.com                   &app->name, rc->req_id);
1900141Smax.romanov@nginx.com 
1901141Smax.romanov@nginx.com         rc->app_port = port;
1902141Smax.romanov@nginx.com 
1903141Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, rc, rc->app_port->mem_pool);
1904141Smax.romanov@nginx.com 
1905141Smax.romanov@nginx.com         return;
1906141Smax.romanov@nginx.com     }
1907141Smax.romanov@nginx.com 
1908*163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
1909*163Smax.romanov@nginx.com         nxt_debug(task, "app '%V' port already closed (pid %PI dead?)",
1910*163Smax.romanov@nginx.com                   &app->name, port->pid);
1911*163Smax.romanov@nginx.com 
1912*163Smax.romanov@nginx.com         app->workers--;
1913*163Smax.romanov@nginx.com         nxt_router_app_free(app);
1914*163Smax.romanov@nginx.com 
1915*163Smax.romanov@nginx.com         port->app = NULL;
1916*163Smax.romanov@nginx.com         process = port->process;
1917*163Smax.romanov@nginx.com 
1918*163Smax.romanov@nginx.com         nxt_port_release(port);
1919*163Smax.romanov@nginx.com 
1920*163Smax.romanov@nginx.com         if (nxt_queue_is_empty(&process->ports)) {
1921*163Smax.romanov@nginx.com             nxt_runtime_process_destroy(task->thread->runtime, process);
1922*163Smax.romanov@nginx.com         }
1923*163Smax.romanov@nginx.com 
1924*163Smax.romanov@nginx.com         return;
1925*163Smax.romanov@nginx.com     }
1926*163Smax.romanov@nginx.com 
1927*163Smax.romanov@nginx.com     if (!app->live) {
1928*163Smax.romanov@nginx.com         nxt_debug(task, "app '%V' is not alive, send QUIT to port",
1929*163Smax.romanov@nginx.com                   &app->name);
1930*163Smax.romanov@nginx.com 
1931*163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
1932*163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
1933*163Smax.romanov@nginx.com 
1934*163Smax.romanov@nginx.com         return;
1935*163Smax.romanov@nginx.com     }
1936*163Smax.romanov@nginx.com 
1937*163Smax.romanov@nginx.com     nxt_debug(task, "app '%V' requests queue is empty, keep the port",
1938*163Smax.romanov@nginx.com               &app->name);
1939141Smax.romanov@nginx.com 
1940141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1941141Smax.romanov@nginx.com 
1942141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
1943141Smax.romanov@nginx.com 
1944141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1945141Smax.romanov@nginx.com }
1946141Smax.romanov@nginx.com 
1947141Smax.romanov@nginx.com 
1948*163Smax.romanov@nginx.com nxt_bool_t
1949141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
1950141Smax.romanov@nginx.com {
1951*163Smax.romanov@nginx.com     nxt_app_t   *app;
1952*163Smax.romanov@nginx.com     nxt_bool_t  busy;
1953141Smax.romanov@nginx.com 
1954141Smax.romanov@nginx.com     app = port->app;
1955*163Smax.romanov@nginx.com     busy = 1;
1956*163Smax.romanov@nginx.com 
1957*163Smax.romanov@nginx.com     if (app == NULL) {
1958*163Smax.romanov@nginx.com         nxt_assert(port->app_link.next == NULL);
1959*163Smax.romanov@nginx.com 
1960*163Smax.romanov@nginx.com         return 1;
1961141Smax.romanov@nginx.com     }
1962141Smax.romanov@nginx.com 
1963141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1964141Smax.romanov@nginx.com 
1965*163Smax.romanov@nginx.com     if (port->app_link.next != NULL) {
1966*163Smax.romanov@nginx.com 
1967*163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
1968*163Smax.romanov@nginx.com         port->app_link.next = NULL;
1969*163Smax.romanov@nginx.com 
1970*163Smax.romanov@nginx.com         busy = 0;
1971*163Smax.romanov@nginx.com     }
1972141Smax.romanov@nginx.com 
1973141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1974*163Smax.romanov@nginx.com 
1975*163Smax.romanov@nginx.com     if (busy == 0) {
1976*163Smax.romanov@nginx.com 
1977*163Smax.romanov@nginx.com         app->workers--;
1978*163Smax.romanov@nginx.com         nxt_router_app_free(app);
1979*163Smax.romanov@nginx.com 
1980*163Smax.romanov@nginx.com         return 1;
1981*163Smax.romanov@nginx.com     }
1982*163Smax.romanov@nginx.com 
1983*163Smax.romanov@nginx.com     return 0;
1984141Smax.romanov@nginx.com }
1985141Smax.romanov@nginx.com 
1986141Smax.romanov@nginx.com 
1987141Smax.romanov@nginx.com nxt_inline nxt_int_t
1988141Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_conn_link_t *rc)
1989141Smax.romanov@nginx.com {
1990141Smax.romanov@nginx.com     nxt_app_t                *app;
1991141Smax.romanov@nginx.com     nxt_conn_t               *c;
1992141Smax.romanov@nginx.com     nxt_port_t               *port, *master_port;
1993141Smax.romanov@nginx.com     nxt_runtime_t            *rt;
1994141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
1995141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
1996141Smax.romanov@nginx.com 
1997141Smax.romanov@nginx.com     port = NULL;
1998141Smax.romanov@nginx.com     c = rc->conn;
1999141Smax.romanov@nginx.com 
2000141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2001141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2002141Smax.romanov@nginx.com 
2003141Smax.romanov@nginx.com 
2004141Smax.romanov@nginx.com     if (app == NULL) {
2005141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2006141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2007141Smax.romanov@nginx.com         return NXT_ERROR;
2008141Smax.romanov@nginx.com     }
2009141Smax.romanov@nginx.com 
2010141Smax.romanov@nginx.com 
2011141Smax.romanov@nginx.com     port = nxt_router_app_get_port(app);
2012141Smax.romanov@nginx.com 
2013141Smax.romanov@nginx.com     if (port != NULL) {
2014*163Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V'", &app->name);
2015*163Smax.romanov@nginx.com 
2016141Smax.romanov@nginx.com         rc->app_port = port;
2017141Smax.romanov@nginx.com         return NXT_OK;
2018141Smax.romanov@nginx.com     }
2019141Smax.romanov@nginx.com 
2020141Smax.romanov@nginx.com     sw = nxt_mp_retain(c->mem_pool, sizeof(nxt_start_worker_t));
2021141Smax.romanov@nginx.com 
2022141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
2023141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2024141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
2025141Smax.romanov@nginx.com         return NXT_ERROR;
2026141Smax.romanov@nginx.com     }
2027141Smax.romanov@nginx.com 
2028141Smax.romanov@nginx.com     nxt_memzero(sw, sizeof(nxt_start_worker_t));
2029141Smax.romanov@nginx.com 
2030141Smax.romanov@nginx.com     sw->stream = nxt_random(&task->thread->random);
2031141Smax.romanov@nginx.com     sw->app = app;
2032141Smax.romanov@nginx.com     sw->rc = rc;
2033141Smax.romanov@nginx.com     sw->mem_pool = c->mem_pool;
2034141Smax.romanov@nginx.com     sw->joint = c->listen->socket.data;
2035141Smax.romanov@nginx.com 
2036141Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
2037141Smax.romanov@nginx.com     sw->work.task = task;
2038141Smax.romanov@nginx.com     sw->work.obj = sw;
2039141Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
2040141Smax.romanov@nginx.com 
2041141Smax.romanov@nginx.com     rt = task->thread->runtime;
2042141Smax.romanov@nginx.com 
2043141Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
2044141Smax.romanov@nginx.com 
2045141Smax.romanov@nginx.com     nxt_debug(task, "post send sw %uxD to master engine %p", sw->stream,
2046141Smax.romanov@nginx.com               master_port->engine);
2047141Smax.romanov@nginx.com 
2048141Smax.romanov@nginx.com     nxt_event_engine_post(master_port->engine, &sw->work);
2049141Smax.romanov@nginx.com 
2050141Smax.romanov@nginx.com     return NXT_AGAIN;
205188Smax.romanov@nginx.com }
205288Smax.romanov@nginx.com 
205388Smax.romanov@nginx.com 
205488Smax.romanov@nginx.com static void
205553Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
205653Sigor@sysoev.ru {
205788Smax.romanov@nginx.com     size_t                    size, preread;
205853Sigor@sysoev.ru     nxt_int_t                 ret;
205953Sigor@sysoev.ru     nxt_buf_t                 *b;
206062Sigor@sysoev.ru     nxt_conn_t                *c;
206188Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
206253Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
206388Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
206453Sigor@sysoev.ru 
206553Sigor@sysoev.ru     c = obj;
206688Smax.romanov@nginx.com     ap = data;
206788Smax.romanov@nginx.com     b = c->read;
206853Sigor@sysoev.ru 
206953Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
207053Sigor@sysoev.ru 
207188Smax.romanov@nginx.com     if (ap == NULL) {
207288Smax.romanov@nginx.com         ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
207388Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
207453Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
207553Sigor@sysoev.ru             return;
207653Sigor@sysoev.ru         }
207753Sigor@sysoev.ru 
207888Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
207961Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
208061Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
208161Sigor@sysoev.ru             return;
208261Sigor@sysoev.ru         }
208388Smax.romanov@nginx.com 
208488Smax.romanov@nginx.com         c->socket.data = ap;
2085113Smax.romanov@nginx.com 
2086113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2087113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
208853Sigor@sysoev.ru     }
208953Sigor@sysoev.ru 
209088Smax.romanov@nginx.com     h = &ap->r.header;
209188Smax.romanov@nginx.com 
209288Smax.romanov@nginx.com     ret = nxt_app_http_req_parse(task, ap, b);
209353Sigor@sysoev.ru 
209453Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
209553Sigor@sysoev.ru 
209653Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
209753Sigor@sysoev.ru 
209853Sigor@sysoev.ru     case NXT_DONE:
209988Smax.romanov@nginx.com         preread = nxt_buf_mem_used_size(&b->mem);
210088Smax.romanov@nginx.com 
210188Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
210288Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
210388Smax.romanov@nginx.com                   h->parsed_content_length, preread);
210488Smax.romanov@nginx.com 
210588Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
210688Smax.romanov@nginx.com         return;
210753Sigor@sysoev.ru 
210853Sigor@sysoev.ru     case NXT_ERROR:
210953Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
211053Sigor@sysoev.ru         return;
211153Sigor@sysoev.ru 
211253Sigor@sysoev.ru     default:  /* NXT_AGAIN */
211353Sigor@sysoev.ru 
211488Smax.romanov@nginx.com         if (h->done == 0) {
211588Smax.romanov@nginx.com 
211688Smax.romanov@nginx.com             if (c->read->mem.free == c->read->mem.end) {
211788Smax.romanov@nginx.com                 joint = c->listen->socket.data;
211888Smax.romanov@nginx.com                 size = joint->socket_conf->large_header_buffer_size;
211988Smax.romanov@nginx.com 
212088Smax.romanov@nginx.com                 if (size > (size_t) nxt_buf_mem_size(&b->mem)) {
212188Smax.romanov@nginx.com                     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
212288Smax.romanov@nginx.com                     if (nxt_slow_path(b == NULL)) {
212388Smax.romanov@nginx.com                         nxt_router_conn_close(task, c, data);
212488Smax.romanov@nginx.com                         return;
212588Smax.romanov@nginx.com                     }
212688Smax.romanov@nginx.com 
212788Smax.romanov@nginx.com                     size = c->read->mem.free - c->read->mem.pos;
2128141Smax.romanov@nginx.com 
2129141Smax.romanov@nginx.com                     c->read = nxt_buf_cpy(b, c->read->mem.pos, size);
213088Smax.romanov@nginx.com                 } else {
2131141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 400,
2132141Smax.romanov@nginx.com                                          "Too long request headers");
2133141Smax.romanov@nginx.com                     return;
213488Smax.romanov@nginx.com                 }
213588Smax.romanov@nginx.com             }
213688Smax.romanov@nginx.com         }
213788Smax.romanov@nginx.com 
213888Smax.romanov@nginx.com         if (ap->r.body.done == 0) {
213988Smax.romanov@nginx.com 
214088Smax.romanov@nginx.com             preread = nxt_buf_mem_used_size(&b->mem);
214188Smax.romanov@nginx.com 
214288Smax.romanov@nginx.com             if (h->parsed_content_length - preread >
214388Smax.romanov@nginx.com                 (size_t) nxt_buf_mem_free_size(&b->mem)) {
214488Smax.romanov@nginx.com 
214588Smax.romanov@nginx.com                 b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0);
214688Smax.romanov@nginx.com                 if (nxt_slow_path(b == NULL)) {
2147141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 500, "Failed to allocate "
2148141Smax.romanov@nginx.com                                          "buffer for request body");
2149141Smax.romanov@nginx.com                     return;
215088Smax.romanov@nginx.com                 }
215188Smax.romanov@nginx.com 
2152141Smax.romanov@nginx.com                 c->read = nxt_buf_cpy(b, c->read->mem.pos, preread);
215353Sigor@sysoev.ru             }
215453Sigor@sysoev.ru 
215588Smax.romanov@nginx.com             nxt_debug(task, "router request body read again, rest: %uz",
215688Smax.romanov@nginx.com                       h->parsed_content_length - preread);
215753Sigor@sysoev.ru 
215853Sigor@sysoev.ru         }
215953Sigor@sysoev.ru 
216088Smax.romanov@nginx.com     }
216188Smax.romanov@nginx.com 
216288Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
216388Smax.romanov@nginx.com }
216488Smax.romanov@nginx.com 
216588Smax.romanov@nginx.com 
216688Smax.romanov@nginx.com static void
216788Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
216888Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
216988Smax.romanov@nginx.com {
2170122Smax.romanov@nginx.com     nxt_int_t            res;
217188Smax.romanov@nginx.com     nxt_req_id_t         req_id;
217288Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
217388Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
217488Smax.romanov@nginx.com 
217588Smax.romanov@nginx.com     engine = task->thread->engine;
217688Smax.romanov@nginx.com 
217788Smax.romanov@nginx.com     do {
2178138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
217988Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
218088Smax.romanov@nginx.com 
218188Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2182122Smax.romanov@nginx.com 
218388Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2184141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2185141Smax.romanov@nginx.com                              "req->conn link");
2186141Smax.romanov@nginx.com 
2187141Smax.romanov@nginx.com         return;
218888Smax.romanov@nginx.com     }
218988Smax.romanov@nginx.com 
2190*163Smax.romanov@nginx.com     rc->ap = ap;
2191*163Smax.romanov@nginx.com 
219288Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
219388Smax.romanov@nginx.com 
219488Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
219588Smax.romanov@nginx.com               req_id, c, engine);
219653Sigor@sysoev.ru 
2197141Smax.romanov@nginx.com     rc->reply_port = engine->port;
2198141Smax.romanov@nginx.com 
2199141Smax.romanov@nginx.com     res = nxt_router_app_port(task, rc);
2200141Smax.romanov@nginx.com 
2201141Smax.romanov@nginx.com     if (res != NXT_OK) {
2202141Smax.romanov@nginx.com         return;
2203141Smax.romanov@nginx.com     }
2204141Smax.romanov@nginx.com 
2205141Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, rc, c->mem_pool);
2206141Smax.romanov@nginx.com }
2207141Smax.romanov@nginx.com 
2208141Smax.romanov@nginx.com 
2209141Smax.romanov@nginx.com static void
2210141Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_conn_link_t *rc,
2211141Smax.romanov@nginx.com     nxt_mp_t *mp)
2212141Smax.romanov@nginx.com {
2213141Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2214141Smax.romanov@nginx.com     nxt_int_t            res;
2215141Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
2216141Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2217141Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2218141Smax.romanov@nginx.com 
2219141Smax.romanov@nginx.com     port = rc->app_port;
2220141Smax.romanov@nginx.com 
2221141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2222141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2223141Smax.romanov@nginx.com         return;
2224141Smax.romanov@nginx.com     }
2225141Smax.romanov@nginx.com 
2226141Smax.romanov@nginx.com     reply_port = rc->reply_port;
2227*163Smax.romanov@nginx.com     ap = rc->ap;
2228141Smax.romanov@nginx.com 
2229122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2230141Smax.romanov@nginx.com     port->mem_pool = mp;
2231141Smax.romanov@nginx.com 
2232141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2233141Smax.romanov@nginx.com                                              reply_port->id);
2234141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2235141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2236122Smax.romanov@nginx.com 
2237122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2238141Smax.romanov@nginx.com             nxt_router_gen_error(task, rc->conn, 500,
2239141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2240141Smax.romanov@nginx.com             goto fail;
2241122Smax.romanov@nginx.com         }
2242122Smax.romanov@nginx.com 
2243141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
224488Smax.romanov@nginx.com     }
224588Smax.romanov@nginx.com 
224688Smax.romanov@nginx.com     wmsg.port = port;
224788Smax.romanov@nginx.com     wmsg.write = NULL;
224888Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2249141Smax.romanov@nginx.com     wmsg.stream = rc->req_id;
2250141Smax.romanov@nginx.com 
2251141Smax.romanov@nginx.com     res = rc->app_port->app->module->prepare_msg(task, &ap->r, &wmsg);
2252122Smax.romanov@nginx.com 
2253122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2254141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2255141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2256141Smax.romanov@nginx.com         goto fail;
2257122Smax.romanov@nginx.com     }
225888Smax.romanov@nginx.com 
225988Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
226088Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
226188Smax.romanov@nginx.com                     wmsg.port->socket.fd);
226288Smax.romanov@nginx.com 
2263122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2264141Smax.romanov@nginx.com                                  -1, rc->req_id, reply_port->id, wmsg.write);
2265122Smax.romanov@nginx.com 
2266122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2267141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2268141Smax.romanov@nginx.com                              "Failed to send message to application");
2269141Smax.romanov@nginx.com         goto fail;
2270122Smax.romanov@nginx.com     }
2271122Smax.romanov@nginx.com 
2272141Smax.romanov@nginx.com fail:
2273122Smax.romanov@nginx.com     port->mem_pool = port_mp;
227453Sigor@sysoev.ru }
227553Sigor@sysoev.ru 
227653Sigor@sysoev.ru 
227762Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
227853Sigor@sysoev.ru     nxt_aligned(64) =
227953Sigor@sysoev.ru {
228053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
228153Sigor@sysoev.ru };
228253Sigor@sysoev.ru 
228353Sigor@sysoev.ru 
228453Sigor@sysoev.ru static void
228588Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
228688Smax.romanov@nginx.com {
228788Smax.romanov@nginx.com     nxt_buf_t         *b;
228888Smax.romanov@nginx.com     nxt_bool_t        last;
228988Smax.romanov@nginx.com     nxt_conn_t        *c;
229088Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
229188Smax.romanov@nginx.com 
229288Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
229388Smax.romanov@nginx.com 
229488Smax.romanov@nginx.com     c = obj;
229588Smax.romanov@nginx.com     b = c->write;
229688Smax.romanov@nginx.com 
229788Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
229888Smax.romanov@nginx.com 
229988Smax.romanov@nginx.com     last = 0;
230088Smax.romanov@nginx.com 
230188Smax.romanov@nginx.com     while (b != NULL) {
230288Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
230388Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
230488Smax.romanov@nginx.com                 break;
230588Smax.romanov@nginx.com             }
230688Smax.romanov@nginx.com         }
230788Smax.romanov@nginx.com 
230888Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
230988Smax.romanov@nginx.com             last = 1;
231088Smax.romanov@nginx.com         }
231188Smax.romanov@nginx.com 
231288Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
231388Smax.romanov@nginx.com 
231488Smax.romanov@nginx.com         b = b->next;
231588Smax.romanov@nginx.com     }
231688Smax.romanov@nginx.com 
231788Smax.romanov@nginx.com     c->write = b;
231888Smax.romanov@nginx.com 
231988Smax.romanov@nginx.com     if (b != NULL) {
232088Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
232188Smax.romanov@nginx.com 
232288Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
232388Smax.romanov@nginx.com     } else {
232488Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
232588Smax.romanov@nginx.com                   last);
232688Smax.romanov@nginx.com 
232788Smax.romanov@nginx.com         if (last != 0) {
232888Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
232988Smax.romanov@nginx.com 
233088Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
233188Smax.romanov@nginx.com                                c->socket.data);
233288Smax.romanov@nginx.com         }
233388Smax.romanov@nginx.com     }
233488Smax.romanov@nginx.com }
233588Smax.romanov@nginx.com 
233688Smax.romanov@nginx.com 
233788Smax.romanov@nginx.com static void
233853Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
233953Sigor@sysoev.ru {
234062Sigor@sysoev.ru     nxt_conn_t  *c;
234153Sigor@sysoev.ru 
234253Sigor@sysoev.ru     c = obj;
234353Sigor@sysoev.ru 
234453Sigor@sysoev.ru     nxt_debug(task, "router conn close");
234553Sigor@sysoev.ru 
234653Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
234753Sigor@sysoev.ru 
234862Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
234953Sigor@sysoev.ru }
235053Sigor@sysoev.ru 
235153Sigor@sysoev.ru 
235253Sigor@sysoev.ru static void
235353Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
235453Sigor@sysoev.ru {
235562Sigor@sysoev.ru     nxt_conn_t               *c;
235688Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
235753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
235853Sigor@sysoev.ru 
235953Sigor@sysoev.ru     c = obj;
236053Sigor@sysoev.ru 
236153Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
236253Sigor@sysoev.ru 
236388Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
236488Smax.romanov@nginx.com 
236588Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
236688Smax.romanov@nginx.com 
2367141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2368141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2369141Smax.romanov@nginx.com 
2370141Smax.romanov@nginx.com             rc->app_port = NULL;
2371141Smax.romanov@nginx.com         }
2372141Smax.romanov@nginx.com 
237388Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
237488Smax.romanov@nginx.com 
237588Smax.romanov@nginx.com     } nxt_queue_loop;
237688Smax.romanov@nginx.com 
2377122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
2378122Smax.romanov@nginx.com 
2379131Smax.romanov@nginx.com     joint = c->listen->socket.data;
2380131Smax.romanov@nginx.com 
2381131Smax.romanov@nginx.com     task = &task->thread->engine->task;
2382131Smax.romanov@nginx.com 
2383141Smax.romanov@nginx.com     if (nxt_mp_release(c->mem_pool, c) == 0) {
2384141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
2385141Smax.romanov@nginx.com     }
238653Sigor@sysoev.ru }
238753Sigor@sysoev.ru 
238853Sigor@sysoev.ru 
238953Sigor@sysoev.ru static void
239053Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
239153Sigor@sysoev.ru {
239262Sigor@sysoev.ru     nxt_conn_t  *c;
239353Sigor@sysoev.ru 
239453Sigor@sysoev.ru     c = obj;
239553Sigor@sysoev.ru 
239653Sigor@sysoev.ru     nxt_debug(task, "router conn error");
239753Sigor@sysoev.ru 
239853Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
239953Sigor@sysoev.ru 
240062Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
240153Sigor@sysoev.ru }
240253Sigor@sysoev.ru 
240353Sigor@sysoev.ru 
240453Sigor@sysoev.ru static void
240553Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
240653Sigor@sysoev.ru {
240762Sigor@sysoev.ru     nxt_conn_t   *c;
240862Sigor@sysoev.ru     nxt_timer_t  *timer;
240953Sigor@sysoev.ru 
241053Sigor@sysoev.ru     timer = obj;
241153Sigor@sysoev.ru 
241253Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
241353Sigor@sysoev.ru 
241462Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
241553Sigor@sysoev.ru 
241653Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
241753Sigor@sysoev.ru 
241862Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
241953Sigor@sysoev.ru }
242053Sigor@sysoev.ru 
242153Sigor@sysoev.ru 
242253Sigor@sysoev.ru static nxt_msec_t
242362Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
242453Sigor@sysoev.ru {
242553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
242653Sigor@sysoev.ru 
242753Sigor@sysoev.ru     joint = c->listen->socket.data;
242853Sigor@sysoev.ru 
242953Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
243053Sigor@sysoev.ru }
2431141Smax.romanov@nginx.com 
2432141Smax.romanov@nginx.com 
2433141Smax.romanov@nginx.com static nxt_int_t
2434141Smax.romanov@nginx.com nxt_sw_test(nxt_lvlhsh_query_t *lhq, void *data)
2435141Smax.romanov@nginx.com {
2436141Smax.romanov@nginx.com     return NXT_OK;
2437141Smax.romanov@nginx.com }
2438141Smax.romanov@nginx.com 
2439141Smax.romanov@nginx.com 
2440141Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_sw_proto  nxt_aligned(64) = {
2441141Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
2442141Smax.romanov@nginx.com     nxt_sw_test,
2443141Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
2444141Smax.romanov@nginx.com     nxt_lvlhsh_free,
2445141Smax.romanov@nginx.com };
2446141Smax.romanov@nginx.com 
2447141Smax.romanov@nginx.com 
2448141Smax.romanov@nginx.com static void
2449141Smax.romanov@nginx.com nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
2450141Smax.romanov@nginx.com     nxt_start_worker_t *sw)
2451141Smax.romanov@nginx.com {
2452141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2453141Smax.romanov@nginx.com 
2454141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&sw->stream, sizeof(sw->stream));
2455141Smax.romanov@nginx.com     lhq.key.length = sizeof(sw->stream);
2456141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &sw->stream;
2457141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2458141Smax.romanov@nginx.com     lhq.replace = 0;
2459141Smax.romanov@nginx.com     lhq.value = sw;
2460141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2461141Smax.romanov@nginx.com 
2462141Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&router->start_workers, &lhq)) {
2463141Smax.romanov@nginx.com 
2464141Smax.romanov@nginx.com     case NXT_OK:
2465141Smax.romanov@nginx.com         break;
2466141Smax.romanov@nginx.com 
2467141Smax.romanov@nginx.com     default:
2468141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw add failed",
2469141Smax.romanov@nginx.com                       sw->stream);
2470141Smax.romanov@nginx.com         break;
2471141Smax.romanov@nginx.com     }
2472141Smax.romanov@nginx.com }
2473141Smax.romanov@nginx.com 
2474141Smax.romanov@nginx.com 
2475141Smax.romanov@nginx.com static nxt_start_worker_t *
2476141Smax.romanov@nginx.com nxt_router_sw_find_remove(nxt_task_t *task, nxt_router_t *router, uint32_t id)
2477141Smax.romanov@nginx.com {
2478141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2479141Smax.romanov@nginx.com 
2480141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&id, sizeof(id));
2481141Smax.romanov@nginx.com     lhq.key.length = sizeof(id);
2482141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &id;
2483141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2484141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2485141Smax.romanov@nginx.com 
2486141Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&router->start_workers, &lhq)) {
2487141Smax.romanov@nginx.com 
2488141Smax.romanov@nginx.com     case NXT_OK:
2489141Smax.romanov@nginx.com         return lhq.value;
2490141Smax.romanov@nginx.com 
2491141Smax.romanov@nginx.com     default:
2492141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw remove failed",
2493141Smax.romanov@nginx.com                       id);
2494141Smax.romanov@nginx.com         break;
2495141Smax.romanov@nginx.com     }
2496141Smax.romanov@nginx.com 
2497141Smax.romanov@nginx.com     return NULL;
2498141Smax.romanov@nginx.com }
2499