xref: /unit/src/nxt_router.c (revision 148)
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);
70115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_mp_t *mp,
71139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_router_engine_conf_t *recf,
72139Sigor@sysoev.ru     nxt_queue_t *sockets, nxt_array_t *array, 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);
84139Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_temp_conf_t *tmcf,
85139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
8653Sigor@sysoev.ru 
8753Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
8853Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
8953Sigor@sysoev.ru     void *data);
9053Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
9153Sigor@sysoev.ru     void *data);
9253Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
9353Sigor@sysoev.ru     void *data);
9453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
9553Sigor@sysoev.ru     void *data);
9653Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
9753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
9853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
9953Sigor@sysoev.ru     void *data);
10053Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
10153Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
10253Sigor@sysoev.ru 
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 
193141Smax.romanov@nginx.com         nxt_router_app_release_port(task, msg->new_port, sw->app);
194141Smax.romanov@nginx.com 
195141Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
196141Smax.romanov@nginx.com 
197141Smax.romanov@nginx.com         nxt_debug(task, "post sw #%uxD release to %p", sw->stream,
198141Smax.romanov@nginx.com                   sw->work.data);
199141Smax.romanov@nginx.com 
200141Smax.romanov@nginx.com         nxt_event_engine_post(sw->work.data, &sw->work);
201141Smax.romanov@nginx.com     }
202141Smax.romanov@nginx.com }
203141Smax.romanov@nginx.com 
204141Smax.romanov@nginx.com 
205139Sigor@sysoev.ru void
206139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
207115Sigor@sysoev.ru {
208139Sigor@sysoev.ru     size_t                  dump_size;
209139Sigor@sysoev.ru     nxt_buf_t               *b;
210139Sigor@sysoev.ru     nxt_int_t               ret;
211139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
212139Sigor@sysoev.ru 
213139Sigor@sysoev.ru     b = msg->buf;
214139Sigor@sysoev.ru 
215139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
216139Sigor@sysoev.ru 
217139Sigor@sysoev.ru     if (dump_size > 300) {
218139Sigor@sysoev.ru         dump_size = 300;
21953Sigor@sysoev.ru     }
22053Sigor@sysoev.ru 
221139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
222139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
223139Sigor@sysoev.ru 
224139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
225139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
226139Sigor@sysoev.ru         return;
22753Sigor@sysoev.ru     }
22853Sigor@sysoev.ru 
229139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
230139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
231139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
232139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
233139Sigor@sysoev.ru 
234139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
235139Sigor@sysoev.ru 
236139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
237139Sigor@sysoev.ru 
238139Sigor@sysoev.ru     if (ret == NXT_OK) {
239139Sigor@sysoev.ru         return nxt_router_conf_success(task, tmcf);
240139Sigor@sysoev.ru     }
241139Sigor@sysoev.ru 
242139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
243139Sigor@sysoev.ru 
244139Sigor@sysoev.ru     return nxt_router_conf_error(task, tmcf);
24553Sigor@sysoev.ru }
24653Sigor@sysoev.ru 
24753Sigor@sysoev.ru 
24853Sigor@sysoev.ru static nxt_router_temp_conf_t *
249139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
25053Sigor@sysoev.ru {
25165Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
25253Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
25353Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
25453Sigor@sysoev.ru 
25565Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
25653Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
25753Sigor@sysoev.ru         return NULL;
25853Sigor@sysoev.ru     }
25953Sigor@sysoev.ru 
26065Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
26153Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
26253Sigor@sysoev.ru         goto fail;
26353Sigor@sysoev.ru     }
26453Sigor@sysoev.ru 
26553Sigor@sysoev.ru     rtcf->mem_pool = mp;
26653Sigor@sysoev.ru     rtcf->count = 1;
26753Sigor@sysoev.ru 
26865Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
26953Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
27053Sigor@sysoev.ru         goto fail;
27153Sigor@sysoev.ru     }
27253Sigor@sysoev.ru 
27365Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
27453Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
27553Sigor@sysoev.ru         goto temp_fail;
27653Sigor@sysoev.ru     }
27753Sigor@sysoev.ru 
27853Sigor@sysoev.ru     tmcf->mem_pool = tmp;
27953Sigor@sysoev.ru     tmcf->conf = rtcf;
280139Sigor@sysoev.ru     tmcf->count = 1;
281139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
28253Sigor@sysoev.ru 
28353Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
28453Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
28553Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
28653Sigor@sysoev.ru         goto temp_fail;
28753Sigor@sysoev.ru     }
28853Sigor@sysoev.ru 
28953Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
29053Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
29153Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
29253Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
29353Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
294133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
295133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
29653Sigor@sysoev.ru 
29753Sigor@sysoev.ru     return tmcf;
29853Sigor@sysoev.ru 
29953Sigor@sysoev.ru temp_fail:
30053Sigor@sysoev.ru 
30165Sigor@sysoev.ru     nxt_mp_destroy(tmp);
30253Sigor@sysoev.ru 
30353Sigor@sysoev.ru fail:
30453Sigor@sysoev.ru 
30565Sigor@sysoev.ru     nxt_mp_destroy(mp);
30653Sigor@sysoev.ru 
30753Sigor@sysoev.ru     return NULL;
30853Sigor@sysoev.ru }
30953Sigor@sysoev.ru 
31053Sigor@sysoev.ru 
311139Sigor@sysoev.ru static nxt_int_t
312139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
313139Sigor@sysoev.ru     u_char *start, u_char *end)
314139Sigor@sysoev.ru {
315139Sigor@sysoev.ru     nxt_int_t                    ret;
316139Sigor@sysoev.ru     nxt_router_t                 *router;
317139Sigor@sysoev.ru     nxt_runtime_t                *rt;
318139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
319139Sigor@sysoev.ru 
320139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
321139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
322139Sigor@sysoev.ru         return ret;
323139Sigor@sysoev.ru     }
324139Sigor@sysoev.ru 
325139Sigor@sysoev.ru     router = tmcf->conf->router;
326139Sigor@sysoev.ru 
327139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
328139Sigor@sysoev.ru 
329139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
330139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
331139Sigor@sysoev.ru         return ret;
332139Sigor@sysoev.ru     }
333139Sigor@sysoev.ru 
334139Sigor@sysoev.ru     rt = task->thread->runtime;
335139Sigor@sysoev.ru 
336139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
337139Sigor@sysoev.ru 
338139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
339139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
340139Sigor@sysoev.ru         return ret;
341139Sigor@sysoev.ru     }
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
344139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
345139Sigor@sysoev.ru         return ret;
346139Sigor@sysoev.ru     }
347139Sigor@sysoev.ru 
348139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
349139Sigor@sysoev.ru 
350139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
351139Sigor@sysoev.ru 
352139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
353139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
354139Sigor@sysoev.ru 
355139Sigor@sysoev.ru     return NXT_OK;
356139Sigor@sysoev.ru }
357139Sigor@sysoev.ru 
358139Sigor@sysoev.ru 
359139Sigor@sysoev.ru static void
360139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
361139Sigor@sysoev.ru {
362139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
363139Sigor@sysoev.ru 
364139Sigor@sysoev.ru     tmcf = obj;
365139Sigor@sysoev.ru 
366139Sigor@sysoev.ru     nxt_router_conf_success(task, tmcf);
367139Sigor@sysoev.ru }
368139Sigor@sysoev.ru 
369139Sigor@sysoev.ru 
370139Sigor@sysoev.ru static void
371139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
372139Sigor@sysoev.ru {
373139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
374139Sigor@sysoev.ru 
375139Sigor@sysoev.ru     if (--tmcf->count == 0) {
376139Sigor@sysoev.ru         nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2);
377139Sigor@sysoev.ru     }
378139Sigor@sysoev.ru }
379139Sigor@sysoev.ru 
380139Sigor@sysoev.ru 
381139Sigor@sysoev.ru static void
382139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
383139Sigor@sysoev.ru {
384*148Sigor@sysoev.ru     nxt_socket_t       s;
385*148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
386*148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
387*148Sigor@sysoev.ru 
388*148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
389*148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
390*148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
391*148Sigor@sysoev.ru     {
392*148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
393*148Sigor@sysoev.ru         s = skcf->listen.socket;
394*148Sigor@sysoev.ru 
395*148Sigor@sysoev.ru         if (s != -1) {
396*148Sigor@sysoev.ru             nxt_socket_close(task, s);
397*148Sigor@sysoev.ru         }
398*148Sigor@sysoev.ru 
399*148Sigor@sysoev.ru         nxt_free(skcf->socket);
400*148Sigor@sysoev.ru     }
401*148Sigor@sysoev.ru 
402*148Sigor@sysoev.ru     // TODO: new engines and threads
403*148Sigor@sysoev.ru 
404139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
405139Sigor@sysoev.ru 
406139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
407139Sigor@sysoev.ru }
408139Sigor@sysoev.ru 
409139Sigor@sysoev.ru 
410139Sigor@sysoev.ru static void
411139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
412139Sigor@sysoev.ru     u_char *start, size_t size)
413139Sigor@sysoev.ru {
414139Sigor@sysoev.ru     nxt_buf_t  *b;
415139Sigor@sysoev.ru 
416139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
417139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
418139Sigor@sysoev.ru         return;
419139Sigor@sysoev.ru     }
420139Sigor@sysoev.ru 
421140Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, start, size);
422140Svbart@nginx.com 
423139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
424139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
425139Sigor@sysoev.ru 
426139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
427139Sigor@sysoev.ru                           tmcf->stream, 0, b);
428139Sigor@sysoev.ru }
429139Sigor@sysoev.ru 
430139Sigor@sysoev.ru 
431139Sigor@sysoev.ru static void
432139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
433139Sigor@sysoev.ru {
434139Sigor@sysoev.ru     nxt_mp_t  *mp;
435139Sigor@sysoev.ru 
436139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
437139Sigor@sysoev.ru     mp = data;
438139Sigor@sysoev.ru 
439139Sigor@sysoev.ru     nxt_mp_destroy(mp);
440139Sigor@sysoev.ru }
441139Sigor@sysoev.ru 
442139Sigor@sysoev.ru 
443115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
444115Sigor@sysoev.ru     {
445133Sigor@sysoev.ru         nxt_string("listeners_threads"),
446115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
447115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
448115Sigor@sysoev.ru     },
449115Sigor@sysoev.ru };
450115Sigor@sysoev.ru 
451115Sigor@sysoev.ru 
452133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
453115Sigor@sysoev.ru     {
454133Sigor@sysoev.ru         nxt_string("type"),
455115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
456133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
457115Sigor@sysoev.ru     },
458115Sigor@sysoev.ru 
459115Sigor@sysoev.ru     {
460133Sigor@sysoev.ru         nxt_string("workers"),
461115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
462133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
463133Sigor@sysoev.ru     },
464133Sigor@sysoev.ru };
465133Sigor@sysoev.ru 
466133Sigor@sysoev.ru 
467133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
468133Sigor@sysoev.ru     {
469133Sigor@sysoev.ru         nxt_string("application"),
470133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
471133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
472115Sigor@sysoev.ru     },
473115Sigor@sysoev.ru };
474115Sigor@sysoev.ru 
475115Sigor@sysoev.ru 
476115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
477115Sigor@sysoev.ru     {
478115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
479115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
480115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
481115Sigor@sysoev.ru     },
482115Sigor@sysoev.ru 
483115Sigor@sysoev.ru     {
484115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
485115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
486115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
487115Sigor@sysoev.ru     },
488115Sigor@sysoev.ru 
489115Sigor@sysoev.ru     {
490115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
491115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
492115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
493115Sigor@sysoev.ru     },
494115Sigor@sysoev.ru };
495115Sigor@sysoev.ru 
496115Sigor@sysoev.ru 
49753Sigor@sysoev.ru static nxt_int_t
498115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
499115Sigor@sysoev.ru     u_char *start, u_char *end)
50053Sigor@sysoev.ru {
501133Sigor@sysoev.ru     u_char                      *p;
502133Sigor@sysoev.ru     size_t                      size;
503115Sigor@sysoev.ru     nxt_mp_t                    *mp;
504115Sigor@sysoev.ru     uint32_t                    next;
505115Sigor@sysoev.ru     nxt_int_t                   ret;
506115Sigor@sysoev.ru     nxt_str_t                   name;
507133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
508133Sigor@sysoev.ru     nxt_app_type_t              type;
509115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
510133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
511133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
512133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
513115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
514133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
515115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
516115Sigor@sysoev.ru 
517115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
518133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
519115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
520115Sigor@sysoev.ru 
521115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
522115Sigor@sysoev.ru     if (conf == NULL) {
523115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
524115Sigor@sysoev.ru         return NXT_ERROR;
525115Sigor@sysoev.ru     }
526115Sigor@sysoev.ru 
527136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
528136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
529115Sigor@sysoev.ru     if (ret != NXT_OK) {
530133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
531115Sigor@sysoev.ru         return NXT_ERROR;
532115Sigor@sysoev.ru     }
533115Sigor@sysoev.ru 
534117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
535117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
536117Sigor@sysoev.ru     }
537117Sigor@sysoev.ru 
538133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
539133Sigor@sysoev.ru     if (applications == NULL) {
540133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
541115Sigor@sysoev.ru         return NXT_ERROR;
542115Sigor@sysoev.ru     }
543115Sigor@sysoev.ru 
544133Sigor@sysoev.ru     next = 0;
545133Sigor@sysoev.ru 
546133Sigor@sysoev.ru     for ( ;; ) {
547133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
548133Sigor@sysoev.ru         if (application == NULL) {
549133Sigor@sysoev.ru             break;
550133Sigor@sysoev.ru         }
551133Sigor@sysoev.ru 
552133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
553133Sigor@sysoev.ru 
554144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
555144Smax.romanov@nginx.com 
556144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
557133Sigor@sysoev.ru         if (app == NULL) {
558133Sigor@sysoev.ru             goto fail;
559133Sigor@sysoev.ru         }
560133Sigor@sysoev.ru 
561144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
562144Smax.romanov@nginx.com 
563144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
564144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
565133Sigor@sysoev.ru 
566133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
567133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
568133Sigor@sysoev.ru 
569144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
570144Smax.romanov@nginx.com 
571133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
572133Sigor@sysoev.ru 
573133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
574133Sigor@sysoev.ru 
575133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
576133Sigor@sysoev.ru             nxt_free(app);
577133Sigor@sysoev.ru 
578133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
579133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
580133Sigor@sysoev.ru             continue;
581133Sigor@sysoev.ru         }
582133Sigor@sysoev.ru 
583136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
584136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
585133Sigor@sysoev.ru         if (ret != NXT_OK) {
586133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
587133Sigor@sysoev.ru             goto app_fail;
588133Sigor@sysoev.ru         }
589115Sigor@sysoev.ru 
590133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
591133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
592133Sigor@sysoev.ru 
593141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
594141Smax.romanov@nginx.com 
595141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
596141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
597141Smax.romanov@nginx.com                     &apcf.type);
598141Smax.romanov@nginx.com             goto app_fail;
599141Smax.romanov@nginx.com         }
600141Smax.romanov@nginx.com 
601141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
602133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
603133Sigor@sysoev.ru                     &apcf.type);
604133Sigor@sysoev.ru             goto app_fail;
605133Sigor@sysoev.ru         }
606133Sigor@sysoev.ru 
607133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
608133Sigor@sysoev.ru         if (ret != NXT_OK) {
609133Sigor@sysoev.ru             goto app_fail;
610133Sigor@sysoev.ru         }
611133Sigor@sysoev.ru 
612141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
613141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
614141Smax.romanov@nginx.com 
615144Smax.romanov@nginx.com         app->name.length = name.length;
616144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
617144Smax.romanov@nginx.com 
618133Sigor@sysoev.ru         app->type = type;
619133Sigor@sysoev.ru         app->max_workers = apcf.workers;
620133Sigor@sysoev.ru         app->live = 1;
621141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
622133Sigor@sysoev.ru 
623133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
624133Sigor@sysoev.ru     }
625133Sigor@sysoev.ru 
626133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
627133Sigor@sysoev.ru #if 0
628133Sigor@sysoev.ru     if (http == NULL) {
629133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
630133Sigor@sysoev.ru         return NXT_ERROR;
631133Sigor@sysoev.ru     }
632133Sigor@sysoev.ru #endif
633133Sigor@sysoev.ru 
634133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
635115Sigor@sysoev.ru     if (listeners == NULL) {
636133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
637115Sigor@sysoev.ru         return NXT_ERROR;
638115Sigor@sysoev.ru     }
63953Sigor@sysoev.ru 
640133Sigor@sysoev.ru     next = 0;
64153Sigor@sysoev.ru 
642133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
643115Sigor@sysoev.ru 
644115Sigor@sysoev.ru     for ( ;; ) {
645115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
646115Sigor@sysoev.ru         if (listener == NULL) {
647115Sigor@sysoev.ru             break;
648115Sigor@sysoev.ru         }
64953Sigor@sysoev.ru 
650115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
651115Sigor@sysoev.ru         if (sa == NULL) {
652115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
653133Sigor@sysoev.ru             goto fail;
654115Sigor@sysoev.ru         }
655115Sigor@sysoev.ru 
656115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
657115Sigor@sysoev.ru 
658115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
659115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
66053Sigor@sysoev.ru 
661115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
662115Sigor@sysoev.ru         if (skcf == NULL) {
663133Sigor@sysoev.ru             goto fail;
664115Sigor@sysoev.ru         }
66553Sigor@sysoev.ru 
666136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
667136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
668115Sigor@sysoev.ru         if (ret != NXT_OK) {
669115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
670133Sigor@sysoev.ru             goto fail;
671115Sigor@sysoev.ru         }
67253Sigor@sysoev.ru 
673133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
674133Sigor@sysoev.ru 
675133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
676133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
677133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
678133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
67953Sigor@sysoev.ru 
680133Sigor@sysoev.ru         if (http != NULL) {
681136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
682136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
683133Sigor@sysoev.ru             if (ret != NXT_OK) {
684133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
685133Sigor@sysoev.ru                 goto fail;
686133Sigor@sysoev.ru             }
687115Sigor@sysoev.ru         }
688115Sigor@sysoev.ru 
689115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
690115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
691133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
692133Sigor@sysoev.ru                                                             &lscf.application);
693115Sigor@sysoev.ru 
694115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
695115Sigor@sysoev.ru     }
69653Sigor@sysoev.ru 
69753Sigor@sysoev.ru     return NXT_OK;
698133Sigor@sysoev.ru 
699133Sigor@sysoev.ru app_fail:
700133Sigor@sysoev.ru 
701133Sigor@sysoev.ru     nxt_free(app);
702133Sigor@sysoev.ru 
703133Sigor@sysoev.ru fail:
704133Sigor@sysoev.ru 
705141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
706141Smax.romanov@nginx.com 
707141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
708133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
709133Sigor@sysoev.ru         nxt_free(app);
710141Smax.romanov@nginx.com 
711141Smax.romanov@nginx.com     } nxt_queue_loop;
712133Sigor@sysoev.ru 
713133Sigor@sysoev.ru     return NXT_ERROR;
714133Sigor@sysoev.ru }
715133Sigor@sysoev.ru 
716133Sigor@sysoev.ru 
717133Sigor@sysoev.ru static nxt_app_t *
718133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
719133Sigor@sysoev.ru {
720141Smax.romanov@nginx.com     nxt_app_t  *app;
721141Smax.romanov@nginx.com 
722141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
723133Sigor@sysoev.ru 
724133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
725133Sigor@sysoev.ru             return app;
726133Sigor@sysoev.ru         }
727141Smax.romanov@nginx.com 
728141Smax.romanov@nginx.com     } nxt_queue_loop;
729133Sigor@sysoev.ru 
730133Sigor@sysoev.ru     return NULL;
731133Sigor@sysoev.ru }
732133Sigor@sysoev.ru 
733133Sigor@sysoev.ru 
734133Sigor@sysoev.ru static nxt_app_t *
735133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
736133Sigor@sysoev.ru {
737133Sigor@sysoev.ru     nxt_app_t  *app;
738133Sigor@sysoev.ru 
739133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
740133Sigor@sysoev.ru 
741133Sigor@sysoev.ru     if (app == NULL) {
742134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
743133Sigor@sysoev.ru     }
744133Sigor@sysoev.ru 
745133Sigor@sysoev.ru     return app;
74653Sigor@sysoev.ru }
74753Sigor@sysoev.ru 
74853Sigor@sysoev.ru 
74953Sigor@sysoev.ru static nxt_socket_conf_t *
75065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
75153Sigor@sysoev.ru {
75253Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
75353Sigor@sysoev.ru 
75465Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
75553Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
75653Sigor@sysoev.ru         return NULL;
75753Sigor@sysoev.ru     }
75853Sigor@sysoev.ru 
759115Sigor@sysoev.ru     conf->sockaddr = sa;
760115Sigor@sysoev.ru 
76153Sigor@sysoev.ru     conf->listen.sockaddr = sa;
762103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
763103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
76453Sigor@sysoev.ru 
76553Sigor@sysoev.ru     conf->listen.socket = -1;
76653Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
76753Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
76853Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
76953Sigor@sysoev.ru 
77053Sigor@sysoev.ru     return conf;
77153Sigor@sysoev.ru }
77253Sigor@sysoev.ru 
77353Sigor@sysoev.ru 
77453Sigor@sysoev.ru static void
77553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
77653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
77753Sigor@sysoev.ru {
77853Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
77953Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
78053Sigor@sysoev.ru 
78153Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
78253Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
78353Sigor@sysoev.ru          nqlk = next)
78453Sigor@sysoev.ru     {
78553Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
78653Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
78753Sigor@sysoev.ru 
78853Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
78953Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
79053Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
79153Sigor@sysoev.ru         {
79253Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
79353Sigor@sysoev.ru 
794115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
795115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
796115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
797115Sigor@sysoev.ru 
79853Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
79953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
80053Sigor@sysoev.ru 
80153Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
80253Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
80353Sigor@sysoev.ru 
80453Sigor@sysoev.ru                 break;
80553Sigor@sysoev.ru             }
80653Sigor@sysoev.ru         }
80753Sigor@sysoev.ru     }
80853Sigor@sysoev.ru 
80953Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
810115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
81153Sigor@sysoev.ru }
81253Sigor@sysoev.ru 
81353Sigor@sysoev.ru 
81453Sigor@sysoev.ru static nxt_int_t
81553Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
81653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
81753Sigor@sysoev.ru {
818115Sigor@sysoev.ru     nxt_int_t            ret;
819115Sigor@sysoev.ru     nxt_socket_t         s;
820115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
821115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
822115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
82353Sigor@sysoev.ru 
82453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
82553Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
82653Sigor@sysoev.ru          qlk = nqlk)
82753Sigor@sysoev.ru     {
828115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
829115Sigor@sysoev.ru 
830115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
831115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
832115Sigor@sysoev.ru             return NXT_ERROR;
833115Sigor@sysoev.ru         }
834115Sigor@sysoev.ru 
835115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
836115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
837*148Sigor@sysoev.ru             goto fail;
838115Sigor@sysoev.ru         }
839115Sigor@sysoev.ru 
840115Sigor@sysoev.ru         skcf->listen.socket = s;
841115Sigor@sysoev.ru 
842*148Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
843*148Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
844*148Sigor@sysoev.ru             goto fail;
845*148Sigor@sysoev.ru         }
846*148Sigor@sysoev.ru 
847*148Sigor@sysoev.ru         rtsk->count = 0;
848*148Sigor@sysoev.ru         rtsk->fd = skcf->listen.socket;
849*148Sigor@sysoev.ru         skcf->socket = rtsk;
850115Sigor@sysoev.ru 
85153Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
85253Sigor@sysoev.ru         nxt_queue_remove(qlk);
85353Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
85453Sigor@sysoev.ru     }
85553Sigor@sysoev.ru 
85653Sigor@sysoev.ru     return NXT_OK;
857*148Sigor@sysoev.ru 
858*148Sigor@sysoev.ru fail:
859*148Sigor@sysoev.ru 
860*148Sigor@sysoev.ru     nxt_socket_close(task, s);
861*148Sigor@sysoev.ru 
862*148Sigor@sysoev.ru     return NXT_ERROR;
86353Sigor@sysoev.ru }
86453Sigor@sysoev.ru 
86553Sigor@sysoev.ru 
86653Sigor@sysoev.ru static nxt_int_t
86753Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
86853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
86953Sigor@sysoev.ru {
87053Sigor@sysoev.ru     nxt_int_t                 ret;
87153Sigor@sysoev.ru     nxt_uint_t                n, threads;
87253Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
87353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
87453Sigor@sysoev.ru 
87553Sigor@sysoev.ru     threads = tmcf->conf->threads;
87653Sigor@sysoev.ru 
87753Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
87853Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
87953Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
88053Sigor@sysoev.ru         return NXT_ERROR;
88153Sigor@sysoev.ru     }
88253Sigor@sysoev.ru 
88353Sigor@sysoev.ru     n = 0;
88453Sigor@sysoev.ru 
88553Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
88653Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
88753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
88853Sigor@sysoev.ru     {
88953Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
89053Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
89153Sigor@sysoev.ru             return NXT_ERROR;
89253Sigor@sysoev.ru         }
89353Sigor@sysoev.ru 
894115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
89553Sigor@sysoev.ru 
89653Sigor@sysoev.ru         if (n < threads) {
897115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
89853Sigor@sysoev.ru 
89953Sigor@sysoev.ru         } else {
900115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
90153Sigor@sysoev.ru         }
90253Sigor@sysoev.ru 
90353Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
90453Sigor@sysoev.ru             return ret;
90553Sigor@sysoev.ru         }
90653Sigor@sysoev.ru 
90753Sigor@sysoev.ru         n++;
90853Sigor@sysoev.ru     }
90953Sigor@sysoev.ru 
91053Sigor@sysoev.ru     tmcf->new_threads = n;
91153Sigor@sysoev.ru 
91253Sigor@sysoev.ru     while (n < threads) {
91353Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
91453Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
91553Sigor@sysoev.ru             return NXT_ERROR;
91653Sigor@sysoev.ru         }
91753Sigor@sysoev.ru 
91853Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
91953Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
92053Sigor@sysoev.ru             return NXT_ERROR;
92153Sigor@sysoev.ru         }
92253Sigor@sysoev.ru 
923115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
92453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
92553Sigor@sysoev.ru             return ret;
92653Sigor@sysoev.ru         }
92753Sigor@sysoev.ru 
928115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
929115Sigor@sysoev.ru 
93053Sigor@sysoev.ru         n++;
93153Sigor@sysoev.ru     }
93253Sigor@sysoev.ru 
93353Sigor@sysoev.ru     return NXT_OK;
93453Sigor@sysoev.ru }
93553Sigor@sysoev.ru 
93653Sigor@sysoev.ru 
93753Sigor@sysoev.ru static nxt_int_t
938115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
939115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
94053Sigor@sysoev.ru {
941115Sigor@sysoev.ru     nxt_mp_t               *mp;
942115Sigor@sysoev.ru     nxt_int_t              ret;
943115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
94453Sigor@sysoev.ru 
94553Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
94653Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
94753Sigor@sysoev.ru         return NXT_ERROR;
94853Sigor@sysoev.ru     }
94953Sigor@sysoev.ru 
950115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
951115Sigor@sysoev.ru 
952139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
953115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
954115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
955115Sigor@sysoev.ru         return ret;
956115Sigor@sysoev.ru     }
957115Sigor@sysoev.ru 
958139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
95953Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
96053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
96153Sigor@sysoev.ru         return ret;
96253Sigor@sysoev.ru     }
96353Sigor@sysoev.ru 
964115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
965115Sigor@sysoev.ru 
966115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
967115Sigor@sysoev.ru 
968115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
969115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
970115Sigor@sysoev.ru 
971115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
972115Sigor@sysoev.ru 
973115Sigor@sysoev.ru     return ret;
97453Sigor@sysoev.ru }
97553Sigor@sysoev.ru 
97653Sigor@sysoev.ru 
97753Sigor@sysoev.ru static nxt_int_t
978115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
979115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
98053Sigor@sysoev.ru {
981115Sigor@sysoev.ru     nxt_mp_t               *mp;
982115Sigor@sysoev.ru     nxt_int_t              ret;
983115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
98453Sigor@sysoev.ru 
98553Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
98653Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
98753Sigor@sysoev.ru         return NXT_ERROR;
98853Sigor@sysoev.ru     }
98953Sigor@sysoev.ru 
990115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
991115Sigor@sysoev.ru 
992139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
99353Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
99453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
99553Sigor@sysoev.ru         return ret;
99653Sigor@sysoev.ru     }
99753Sigor@sysoev.ru 
99853Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
99953Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
100053Sigor@sysoev.ru         return NXT_ERROR;
100153Sigor@sysoev.ru     }
100253Sigor@sysoev.ru 
1003139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
100453Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
100553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
100653Sigor@sysoev.ru         return ret;
100753Sigor@sysoev.ru     }
100853Sigor@sysoev.ru 
100953Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
101053Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
101153Sigor@sysoev.ru         return NXT_ERROR;
101253Sigor@sysoev.ru     }
101353Sigor@sysoev.ru 
1014139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1015115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1016115Sigor@sysoev.ru         return ret;
1017115Sigor@sysoev.ru     }
1018115Sigor@sysoev.ru 
1019115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1020115Sigor@sysoev.ru 
1021115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1022115Sigor@sysoev.ru 
1023115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1024115Sigor@sysoev.ru 
1025115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1026115Sigor@sysoev.ru 
1027115Sigor@sysoev.ru     return ret;
102853Sigor@sysoev.ru }
102953Sigor@sysoev.ru 
103053Sigor@sysoev.ru 
103153Sigor@sysoev.ru static nxt_int_t
1032115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1033115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
103453Sigor@sysoev.ru {
103553Sigor@sysoev.ru     nxt_int_t  ret;
103653Sigor@sysoev.ru 
103753Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
103853Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
103953Sigor@sysoev.ru         return NXT_ERROR;
104053Sigor@sysoev.ru     }
104153Sigor@sysoev.ru 
1042139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
104353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
104453Sigor@sysoev.ru         return ret;
104553Sigor@sysoev.ru     }
104653Sigor@sysoev.ru 
1047139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
104853Sigor@sysoev.ru }
104953Sigor@sysoev.ru 
105053Sigor@sysoev.ru 
105153Sigor@sysoev.ru static nxt_int_t
1052139Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_temp_conf_t *tmcf,
1053139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
105453Sigor@sysoev.ru     nxt_work_handler_t handler)
105553Sigor@sysoev.ru {
1056139Sigor@sysoev.ru     nxt_work_t               *work, *back;
105753Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
105853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
105953Sigor@sysoev.ru 
106053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
106153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
106253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
106353Sigor@sysoev.ru     {
1064139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
1065139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
1066139Sigor@sysoev.ru             return NXT_ERROR;
1067139Sigor@sysoev.ru         }
1068139Sigor@sysoev.ru 
1069139Sigor@sysoev.ru         back->next = NULL;
1070139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
1071139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
1072139Sigor@sysoev.ru         back->obj = tmcf;
1073139Sigor@sysoev.ru         back->data = NULL;
1074139Sigor@sysoev.ru 
107553Sigor@sysoev.ru         work = nxt_array_add(array);
107653Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
107753Sigor@sysoev.ru             return NXT_ERROR;
107853Sigor@sysoev.ru         }
107953Sigor@sysoev.ru 
108053Sigor@sysoev.ru         work->next = NULL;
108153Sigor@sysoev.ru         work->handler = handler;
1082139Sigor@sysoev.ru         work->task = &recf->engine->task;
1083139Sigor@sysoev.ru         work->obj = back;
108453Sigor@sysoev.ru 
108565Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
108653Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
108753Sigor@sysoev.ru             return NXT_ERROR;
108853Sigor@sysoev.ru         }
108953Sigor@sysoev.ru 
109053Sigor@sysoev.ru         work->data = joint;
109153Sigor@sysoev.ru 
109253Sigor@sysoev.ru         joint->count = 1;
109353Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
109488Smax.romanov@nginx.com         joint->engine = recf->engine;
1095115Sigor@sysoev.ru 
1096115Sigor@sysoev.ru         nxt_queue_insert_tail(&joint->engine->joints, &joint->link);
109753Sigor@sysoev.ru     }
109853Sigor@sysoev.ru 
109920Sigor@sysoev.ru     return NXT_OK;
110020Sigor@sysoev.ru }
110120Sigor@sysoev.ru 
110220Sigor@sysoev.ru 
1103115Sigor@sysoev.ru static void
1104115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1105115Sigor@sysoev.ru {
1106115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1107115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1108115Sigor@sysoev.ru 
1109115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1110115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1111115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1112115Sigor@sysoev.ru     {
1113115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1114115Sigor@sysoev.ru         skcf->socket->count++;
1115115Sigor@sysoev.ru     }
1116115Sigor@sysoev.ru }
1117115Sigor@sysoev.ru 
1118115Sigor@sysoev.ru 
111920Sigor@sysoev.ru static nxt_int_t
1120139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1121139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
112220Sigor@sysoev.ru {
1123139Sigor@sysoev.ru     nxt_work_t        *work, *back;
112453Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
112520Sigor@sysoev.ru 
112653Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
112753Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
112853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
112953Sigor@sysoev.ru     {
1130139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
1131139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
1132139Sigor@sysoev.ru             return NXT_ERROR;
1133139Sigor@sysoev.ru         }
1134139Sigor@sysoev.ru 
1135139Sigor@sysoev.ru         back->next = NULL;
1136139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
1137139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
1138139Sigor@sysoev.ru         back->obj = tmcf;
1139139Sigor@sysoev.ru         back->data = NULL;
1140139Sigor@sysoev.ru 
1141115Sigor@sysoev.ru         work = nxt_array_add(recf->deleting);
114253Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
114353Sigor@sysoev.ru             return NXT_ERROR;
114453Sigor@sysoev.ru         }
114520Sigor@sysoev.ru 
114653Sigor@sysoev.ru         work->next = NULL;
114753Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
1148139Sigor@sysoev.ru         work->task = &recf->engine->task;
1149139Sigor@sysoev.ru         work->obj = back;
115053Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
115120Sigor@sysoev.ru     }
115220Sigor@sysoev.ru 
115353Sigor@sysoev.ru     return NXT_OK;
115453Sigor@sysoev.ru }
115520Sigor@sysoev.ru 
115620Sigor@sysoev.ru 
115753Sigor@sysoev.ru static nxt_int_t
115853Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
115953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
116053Sigor@sysoev.ru {
116153Sigor@sysoev.ru     nxt_int_t                 ret;
116253Sigor@sysoev.ru     nxt_uint_t                i, threads;
116353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
116420Sigor@sysoev.ru 
116553Sigor@sysoev.ru     recf = tmcf->engines->elts;
116653Sigor@sysoev.ru     threads = tmcf->conf->threads;
116720Sigor@sysoev.ru 
116853Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
116953Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
117053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
117153Sigor@sysoev.ru             return ret;
117253Sigor@sysoev.ru         }
117320Sigor@sysoev.ru     }
117420Sigor@sysoev.ru 
117520Sigor@sysoev.ru     return NXT_OK;
117620Sigor@sysoev.ru }
117753Sigor@sysoev.ru 
117853Sigor@sysoev.ru 
117953Sigor@sysoev.ru static nxt_int_t
118053Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
118153Sigor@sysoev.ru     nxt_event_engine_t *engine)
118253Sigor@sysoev.ru {
118353Sigor@sysoev.ru     nxt_int_t            ret;
118453Sigor@sysoev.ru     nxt_thread_link_t    *link;
118553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
118653Sigor@sysoev.ru 
118753Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
118853Sigor@sysoev.ru 
118953Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
119053Sigor@sysoev.ru         return NXT_ERROR;
119153Sigor@sysoev.ru     }
119253Sigor@sysoev.ru 
119353Sigor@sysoev.ru     link->start = nxt_router_thread_start;
119453Sigor@sysoev.ru     link->engine = engine;
119553Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
119653Sigor@sysoev.ru     link->work.task = task;
119753Sigor@sysoev.ru     link->work.data = link;
119853Sigor@sysoev.ru 
119953Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
120053Sigor@sysoev.ru 
120153Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
120253Sigor@sysoev.ru 
120353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
120453Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
120553Sigor@sysoev.ru     }
120653Sigor@sysoev.ru 
120753Sigor@sysoev.ru     return ret;
120853Sigor@sysoev.ru }
120953Sigor@sysoev.ru 
121053Sigor@sysoev.ru 
121153Sigor@sysoev.ru static void
1212133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1213133Sigor@sysoev.ru {
1214141Smax.romanov@nginx.com     nxt_app_t  *app;
1215141Smax.romanov@nginx.com 
1216141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1217133Sigor@sysoev.ru 
1218133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1219133Sigor@sysoev.ru 
1220141Smax.romanov@nginx.com         // TODO RELEASE APP
1221144Smax.romanov@nginx.com #if 0
1222144Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
1223144Smax.romanov@nginx.com         nxt_free(app);
1224144Smax.romanov@nginx.com #endif
1225141Smax.romanov@nginx.com     } nxt_queue_loop;
1226133Sigor@sysoev.ru 
1227133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1228133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1229133Sigor@sysoev.ru }
1230133Sigor@sysoev.ru 
1231133Sigor@sysoev.ru 
1232133Sigor@sysoev.ru static void
123353Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
123453Sigor@sysoev.ru {
123553Sigor@sysoev.ru     nxt_uint_t                n;
123653Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
123753Sigor@sysoev.ru 
123853Sigor@sysoev.ru     recf = tmcf->engines->elts;
123953Sigor@sysoev.ru 
124053Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1241139Sigor@sysoev.ru         nxt_router_engine_post(tmcf, recf);
124253Sigor@sysoev.ru         recf++;
124353Sigor@sysoev.ru     }
124453Sigor@sysoev.ru }
124553Sigor@sysoev.ru 
124653Sigor@sysoev.ru 
124753Sigor@sysoev.ru static void
1248139Sigor@sysoev.ru nxt_router_engine_post(nxt_router_temp_conf_t *tmcf,
1249139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
125053Sigor@sysoev.ru {
125153Sigor@sysoev.ru     nxt_uint_t  n;
125253Sigor@sysoev.ru     nxt_work_t  *work;
125353Sigor@sysoev.ru 
1254115Sigor@sysoev.ru     if (recf->creating != NULL) {
1255115Sigor@sysoev.ru         work = recf->creating->elts;
1256115Sigor@sysoev.ru 
1257115Sigor@sysoev.ru         for (n = recf->creating->nelts; n != 0; n--) {
1258115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1259115Sigor@sysoev.ru             work++;
1260139Sigor@sysoev.ru             tmcf->count++;
1261115Sigor@sysoev.ru         }
1262115Sigor@sysoev.ru     }
1263115Sigor@sysoev.ru 
1264115Sigor@sysoev.ru     if (recf->updating != NULL) {
1265115Sigor@sysoev.ru         work = recf->updating->elts;
126653Sigor@sysoev.ru 
1267115Sigor@sysoev.ru         for (n = recf->updating->nelts; n != 0; n--) {
1268115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1269115Sigor@sysoev.ru             work++;
1270139Sigor@sysoev.ru             tmcf->count++;
1271115Sigor@sysoev.ru         }
1272115Sigor@sysoev.ru     }
1273115Sigor@sysoev.ru 
1274115Sigor@sysoev.ru     if (recf->deleting != NULL) {
1275115Sigor@sysoev.ru         work = recf->deleting->elts;
1276115Sigor@sysoev.ru 
1277115Sigor@sysoev.ru         for (n = recf->deleting->nelts; n != 0; n--) {
1278115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1279115Sigor@sysoev.ru             work++;
1280139Sigor@sysoev.ru             tmcf->count++;
1281115Sigor@sysoev.ru         }
128253Sigor@sysoev.ru     }
128353Sigor@sysoev.ru }
128453Sigor@sysoev.ru 
128553Sigor@sysoev.ru 
128653Sigor@sysoev.ru static void
1287119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
128888Smax.romanov@nginx.com 
1289119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
129088Smax.romanov@nginx.com     NULL,
129188Smax.romanov@nginx.com     nxt_port_new_port_handler,
129288Smax.romanov@nginx.com     nxt_port_change_log_file_handler,
129388Smax.romanov@nginx.com     nxt_port_mmap_handler,
1294119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1295125Smax.romanov@nginx.com     nxt_port_remove_pid_handler,
129688Smax.romanov@nginx.com };
129788Smax.romanov@nginx.com 
129888Smax.romanov@nginx.com 
129988Smax.romanov@nginx.com static void
130053Sigor@sysoev.ru nxt_router_thread_start(void *data)
130153Sigor@sysoev.ru {
1302141Smax.romanov@nginx.com     nxt_int_t           ret;
1303141Smax.romanov@nginx.com     nxt_port_t          *port;
130488Smax.romanov@nginx.com     nxt_task_t          *task;
130553Sigor@sysoev.ru     nxt_thread_t        *thread;
130653Sigor@sysoev.ru     nxt_thread_link_t   *link;
130753Sigor@sysoev.ru     nxt_event_engine_t  *engine;
130853Sigor@sysoev.ru 
130953Sigor@sysoev.ru     link = data;
131053Sigor@sysoev.ru     engine = link->engine;
131188Smax.romanov@nginx.com     task = &engine->task;
131253Sigor@sysoev.ru 
131353Sigor@sysoev.ru     thread = nxt_thread();
131453Sigor@sysoev.ru 
131553Sigor@sysoev.ru     /* STUB */
131653Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
131753Sigor@sysoev.ru 
131853Sigor@sysoev.ru     engine->task.thread = thread;
131953Sigor@sysoev.ru     engine->task.log = thread->log;
132053Sigor@sysoev.ru     thread->engine = engine;
132163Sigor@sysoev.ru     thread->task = &engine->task;
132253Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
132353Sigor@sysoev.ru 
132463Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
132553Sigor@sysoev.ru 
1326141Smax.romanov@nginx.com     port = nxt_mp_zalloc(engine->mem_pool, sizeof(nxt_port_t));
1327141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1328141Smax.romanov@nginx.com         return;
1329141Smax.romanov@nginx.com     }
1330141Smax.romanov@nginx.com 
1331141Smax.romanov@nginx.com     port->id = nxt_port_get_next_id();
1332141Smax.romanov@nginx.com     port->pid = nxt_pid;
1333141Smax.romanov@nginx.com 
1334141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1335141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1336141Smax.romanov@nginx.com         return;
1337141Smax.romanov@nginx.com     }
1338141Smax.romanov@nginx.com 
1339141Smax.romanov@nginx.com     port->type = NXT_PROCESS_ROUTER;
1340141Smax.romanov@nginx.com 
1341141Smax.romanov@nginx.com     engine->port = port;
1342141Smax.romanov@nginx.com 
1343141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1344141Smax.romanov@nginx.com 
134553Sigor@sysoev.ru     nxt_event_engine_start(engine);
134653Sigor@sysoev.ru }
134753Sigor@sysoev.ru 
134853Sigor@sysoev.ru 
134953Sigor@sysoev.ru static void
135053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
135153Sigor@sysoev.ru {
1352139Sigor@sysoev.ru     nxt_work_t               *work;
135353Sigor@sysoev.ru     nxt_listen_event_t       *listen;
135453Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
1355139Sigor@sysoev.ru     nxt_router_temp_conf_t   *tmcf;
135653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
135753Sigor@sysoev.ru 
1358139Sigor@sysoev.ru     work = obj;
135953Sigor@sysoev.ru     joint = data;
136053Sigor@sysoev.ru 
136153Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
136253Sigor@sysoev.ru 
136353Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
136453Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
136553Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
136653Sigor@sysoev.ru         return;
136753Sigor@sysoev.ru     }
136853Sigor@sysoev.ru 
136953Sigor@sysoev.ru     listen->socket.data = joint;
1370139Sigor@sysoev.ru 
1371139Sigor@sysoev.ru     tmcf = work->obj;
1372139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
137353Sigor@sysoev.ru }
137453Sigor@sysoev.ru 
137553Sigor@sysoev.ru 
137653Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
137753Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
137853Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
137953Sigor@sysoev.ru {
1380115Sigor@sysoev.ru     nxt_socket_t        fd;
1381115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
138253Sigor@sysoev.ru     nxt_listen_event_t  *listen;
138353Sigor@sysoev.ru 
1384115Sigor@sysoev.ru     fd = skcf->socket->fd;
138553Sigor@sysoev.ru 
1386115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1387115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1388115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
138953Sigor@sysoev.ru     {
1390115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
139153Sigor@sysoev.ru 
1392115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
139353Sigor@sysoev.ru             return listen;
139453Sigor@sysoev.ru         }
139553Sigor@sysoev.ru     }
139653Sigor@sysoev.ru 
139753Sigor@sysoev.ru     return NULL;
139853Sigor@sysoev.ru }
139953Sigor@sysoev.ru 
140053Sigor@sysoev.ru 
140153Sigor@sysoev.ru static void
140253Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
140353Sigor@sysoev.ru {
1404139Sigor@sysoev.ru     nxt_work_t               *work;
140553Sigor@sysoev.ru     nxt_event_engine_t       *engine;
140653Sigor@sysoev.ru     nxt_listen_event_t       *listen;
1407139Sigor@sysoev.ru     nxt_router_temp_conf_t   *tmcf;
140853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
140953Sigor@sysoev.ru 
1410139Sigor@sysoev.ru     work = obj;
141153Sigor@sysoev.ru     joint = data;
141253Sigor@sysoev.ru 
1413139Sigor@sysoev.ru     engine = task->thread->engine;
1414139Sigor@sysoev.ru 
141553Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
141653Sigor@sysoev.ru                                      joint->socket_conf);
141753Sigor@sysoev.ru 
141853Sigor@sysoev.ru     old = listen->socket.data;
141953Sigor@sysoev.ru     listen->socket.data = joint;
142053Sigor@sysoev.ru 
1421139Sigor@sysoev.ru     tmcf = work->obj;
1422139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
1423139Sigor@sysoev.ru 
142453Sigor@sysoev.ru     nxt_router_conf_release(task, old);
142553Sigor@sysoev.ru }
142653Sigor@sysoev.ru 
142753Sigor@sysoev.ru 
142853Sigor@sysoev.ru static void
142953Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
143053Sigor@sysoev.ru {
1431139Sigor@sysoev.ru     nxt_work_t              *work;
1432139Sigor@sysoev.ru     nxt_socket_conf_t       *skcf;
1433139Sigor@sysoev.ru     nxt_listen_event_t      *listen;
1434139Sigor@sysoev.ru     nxt_event_engine_t      *engine;
1435139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1436139Sigor@sysoev.ru 
1437139Sigor@sysoev.ru     work = obj;
143853Sigor@sysoev.ru     skcf = data;
143953Sigor@sysoev.ru 
1440139Sigor@sysoev.ru     engine = task->thread->engine;
1441139Sigor@sysoev.ru 
144253Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
144353Sigor@sysoev.ru 
144453Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
144553Sigor@sysoev.ru 
144653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
144753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
144853Sigor@sysoev.ru 
144953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1450139Sigor@sysoev.ru 
1451139Sigor@sysoev.ru     tmcf = work->obj;
1452139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
145353Sigor@sysoev.ru }
145453Sigor@sysoev.ru 
145553Sigor@sysoev.ru 
145653Sigor@sysoev.ru static void
145753Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
145853Sigor@sysoev.ru {
145953Sigor@sysoev.ru     nxt_timer_t              *timer;
146053Sigor@sysoev.ru     nxt_listen_event_t       *listen;
146153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
146253Sigor@sysoev.ru 
146353Sigor@sysoev.ru     timer = obj;
146453Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
146553Sigor@sysoev.ru     joint = listen->socket.data;
146653Sigor@sysoev.ru 
146753Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1468123Smax.romanov@nginx.com 
1469123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1470123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1471123Smax.romanov@nginx.com 
147253Sigor@sysoev.ru     nxt_free(listen);
147353Sigor@sysoev.ru 
147453Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
147553Sigor@sysoev.ru }
147653Sigor@sysoev.ru 
147753Sigor@sysoev.ru 
147853Sigor@sysoev.ru static void
147953Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
148053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
148153Sigor@sysoev.ru {
1482118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1483115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
148453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
148553Sigor@sysoev.ru 
1486118Sigor@sysoev.ru     skcf = joint->socket_conf;
1487118Sigor@sysoev.ru     rtsk = skcf->socket;
1488118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
148953Sigor@sysoev.ru 
149053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
149153Sigor@sysoev.ru 
1492115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1493115Sigor@sysoev.ru         rtsk = NULL;
149453Sigor@sysoev.ru     }
149553Sigor@sysoev.ru 
149653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
149753Sigor@sysoev.ru 
1498115Sigor@sysoev.ru     if (rtsk != NULL) {
1499115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1500115Sigor@sysoev.ru         nxt_free(rtsk);
1501118Sigor@sysoev.ru         skcf->socket = NULL;
150253Sigor@sysoev.ru     }
150353Sigor@sysoev.ru 
150453Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
150553Sigor@sysoev.ru }
150653Sigor@sysoev.ru 
150753Sigor@sysoev.ru 
150853Sigor@sysoev.ru static void
150953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
151053Sigor@sysoev.ru {
151153Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
151253Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
151353Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
151453Sigor@sysoev.ru 
151553Sigor@sysoev.ru     nxt_debug(task, "conf joint count: %D", joint->count);
151653Sigor@sysoev.ru 
151753Sigor@sysoev.ru     if (--joint->count != 0) {
151853Sigor@sysoev.ru         return;
151953Sigor@sysoev.ru     }
152053Sigor@sysoev.ru 
152153Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
152253Sigor@sysoev.ru 
152353Sigor@sysoev.ru     skcf = joint->socket_conf;
152453Sigor@sysoev.ru     rtcf = skcf->router_conf;
152553Sigor@sysoev.ru     lock = &rtcf->router->lock;
152653Sigor@sysoev.ru 
152753Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
152853Sigor@sysoev.ru 
152953Sigor@sysoev.ru     if (--skcf->count != 0) {
153053Sigor@sysoev.ru         rtcf = NULL;
153153Sigor@sysoev.ru 
153253Sigor@sysoev.ru     } else {
153353Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
153453Sigor@sysoev.ru 
153553Sigor@sysoev.ru         if (--rtcf->count != 0) {
153653Sigor@sysoev.ru             rtcf = NULL;
153753Sigor@sysoev.ru         }
153853Sigor@sysoev.ru     }
153953Sigor@sysoev.ru 
154053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
154153Sigor@sysoev.ru 
1542141Smax.romanov@nginx.com     /* TODO remove engine->port */
1543141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1544141Smax.romanov@nginx.com 
154553Sigor@sysoev.ru     if (rtcf != NULL) {
1546115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1547131Smax.romanov@nginx.com 
1548131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1549131Smax.romanov@nginx.com 
155065Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
155153Sigor@sysoev.ru     }
155253Sigor@sysoev.ru 
155353Sigor@sysoev.ru     if (nxt_queue_is_empty(&joint->engine->joints)) {
155453Sigor@sysoev.ru         nxt_thread_exit(task->thread);
155553Sigor@sysoev.ru     }
155653Sigor@sysoev.ru }
155753Sigor@sysoev.ru 
155853Sigor@sysoev.ru 
155953Sigor@sysoev.ru static void
156053Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
156153Sigor@sysoev.ru {
1562141Smax.romanov@nginx.com     nxt_port_t           *port;
156353Sigor@sysoev.ru     nxt_thread_link_t    *link;
156453Sigor@sysoev.ru     nxt_event_engine_t   *engine;
156553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
156653Sigor@sysoev.ru 
156758Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
156853Sigor@sysoev.ru     link = data;
156953Sigor@sysoev.ru 
157053Sigor@sysoev.ru     nxt_thread_wait(handle);
157153Sigor@sysoev.ru 
157253Sigor@sysoev.ru     engine = link->engine;
157353Sigor@sysoev.ru 
157453Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
157553Sigor@sysoev.ru 
1576141Smax.romanov@nginx.com     port = engine->port;
1577141Smax.romanov@nginx.com 
1578141Smax.romanov@nginx.com     // TODO notify all apps
1579141Smax.romanov@nginx.com 
1580141Smax.romanov@nginx.com     if (port->pair[0] != -1) {
1581141Smax.romanov@nginx.com         nxt_fd_close(port->pair[0]);
1582141Smax.romanov@nginx.com     }
1583141Smax.romanov@nginx.com 
1584141Smax.romanov@nginx.com     if (port->pair[1] != -1) {
1585141Smax.romanov@nginx.com         nxt_fd_close(port->pair[1]);
1586141Smax.romanov@nginx.com     }
1587141Smax.romanov@nginx.com 
1588141Smax.romanov@nginx.com     if (port->mem_pool) {
1589141Smax.romanov@nginx.com         nxt_mp_destroy(port->mem_pool);
1590141Smax.romanov@nginx.com     }
1591141Smax.romanov@nginx.com 
159263Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
159353Sigor@sysoev.ru 
159453Sigor@sysoev.ru     nxt_event_engine_free(engine);
159553Sigor@sysoev.ru 
159653Sigor@sysoev.ru     nxt_free(link);
159753Sigor@sysoev.ru }
159853Sigor@sysoev.ru 
159953Sigor@sysoev.ru 
160062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_read_state
160153Sigor@sysoev.ru     nxt_aligned(64) =
160253Sigor@sysoev.ru {
160353Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
160453Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
160553Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
160653Sigor@sysoev.ru 
160753Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
160853Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
160953Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
161053Sigor@sysoev.ru };
161153Sigor@sysoev.ru 
161253Sigor@sysoev.ru 
161353Sigor@sysoev.ru static void
161453Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
161553Sigor@sysoev.ru {
161653Sigor@sysoev.ru     size_t                   size;
161762Sigor@sysoev.ru     nxt_conn_t               *c;
161853Sigor@sysoev.ru     nxt_event_engine_t       *engine;
161953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
162053Sigor@sysoev.ru 
162153Sigor@sysoev.ru     c = obj;
162253Sigor@sysoev.ru     joint = data;
162353Sigor@sysoev.ru 
162453Sigor@sysoev.ru     nxt_debug(task, "router conn init");
162553Sigor@sysoev.ru 
162653Sigor@sysoev.ru     joint->count++;
162753Sigor@sysoev.ru 
162853Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
162953Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
163053Sigor@sysoev.ru 
163153Sigor@sysoev.ru     c->socket.data = NULL;
163253Sigor@sysoev.ru 
163353Sigor@sysoev.ru     engine = task->thread->engine;
163453Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
163553Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
163653Sigor@sysoev.ru 
163753Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
163853Sigor@sysoev.ru 
163962Sigor@sysoev.ru     nxt_conn_read(engine, c);
164053Sigor@sysoev.ru }
164153Sigor@sysoev.ru 
164253Sigor@sysoev.ru 
164362Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
164453Sigor@sysoev.ru     nxt_aligned(64) =
164553Sigor@sysoev.ru {
164688Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
164753Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
164853Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
164953Sigor@sysoev.ru };
165053Sigor@sysoev.ru 
165153Sigor@sysoev.ru 
165253Sigor@sysoev.ru static void
1653119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
165488Smax.romanov@nginx.com {
165588Smax.romanov@nginx.com     size_t               dump_size;
165688Smax.romanov@nginx.com     nxt_buf_t            *b, *i, *last;
165788Smax.romanov@nginx.com     nxt_conn_t           *c;
165888Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
165988Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
166088Smax.romanov@nginx.com 
166188Smax.romanov@nginx.com     b = msg->buf;
166288Smax.romanov@nginx.com     engine = task->thread->engine;
166388Smax.romanov@nginx.com 
166488Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
166588Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
166688Smax.romanov@nginx.com 
166788Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
166888Smax.romanov@nginx.com 
166995Smax.romanov@nginx.com         /* Mark buffers as read. */
167088Smax.romanov@nginx.com         for (i = b; i != NULL; i = i->next) {
167188Smax.romanov@nginx.com             i->mem.pos = i->mem.free;
167288Smax.romanov@nginx.com         }
167388Smax.romanov@nginx.com 
167488Smax.romanov@nginx.com         return;
167588Smax.romanov@nginx.com     }
167688Smax.romanov@nginx.com 
167788Smax.romanov@nginx.com     c = rc->conn;
167888Smax.romanov@nginx.com 
167988Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
168088Smax.romanov@nginx.com 
168188Smax.romanov@nginx.com     if (dump_size > 300) {
168288Smax.romanov@nginx.com         dump_size = 300;
168388Smax.romanov@nginx.com     }
168488Smax.romanov@nginx.com 
1685119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
168688Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
168788Smax.romanov@nginx.com               b->mem.pos);
168888Smax.romanov@nginx.com 
168988Smax.romanov@nginx.com     if (msg->size == 0) {
169088Smax.romanov@nginx.com         b = NULL;
169188Smax.romanov@nginx.com     }
169288Smax.romanov@nginx.com 
169388Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
169488Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
169588Smax.romanov@nginx.com 
169688Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
169788Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
169888Smax.romanov@nginx.com             /* TODO pogorevaTb */
169988Smax.romanov@nginx.com         }
170088Smax.romanov@nginx.com 
170188Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
170288Smax.romanov@nginx.com     }
170388Smax.romanov@nginx.com 
170488Smax.romanov@nginx.com     if (b == NULL) {
170588Smax.romanov@nginx.com         return;
170688Smax.romanov@nginx.com     }
170788Smax.romanov@nginx.com 
170888Smax.romanov@nginx.com     if (c->write == NULL) {
170988Smax.romanov@nginx.com         c->write = b;
171088Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
171188Smax.romanov@nginx.com 
171288Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
171388Smax.romanov@nginx.com     } else {
171488Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
171588Smax.romanov@nginx.com 
171688Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
171788Smax.romanov@nginx.com     }
171888Smax.romanov@nginx.com }
171988Smax.romanov@nginx.com 
1720141Smax.romanov@nginx.com nxt_inline const char *
1721141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
1722141Smax.romanov@nginx.com {
1723141Smax.romanov@nginx.com     switch (code) {
1724141Smax.romanov@nginx.com     case 400: return "Bad request";
1725141Smax.romanov@nginx.com     case 404: return "Not found";
1726141Smax.romanov@nginx.com     case 403: return "Forbidden";
1727141Smax.romanov@nginx.com     case 500:
1728141Smax.romanov@nginx.com     default:  return "Internal server error";
1729141Smax.romanov@nginx.com     }
1730141Smax.romanov@nginx.com }
1731141Smax.romanov@nginx.com 
1732141Smax.romanov@nginx.com static void
1733141Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
1734141Smax.romanov@nginx.com     const char* fmt, ...)
173588Smax.romanov@nginx.com {
1736141Smax.romanov@nginx.com     va_list             args;
1737141Smax.romanov@nginx.com     nxt_buf_t           *b, *last;
1738141Smax.romanov@nginx.com     const char          *msg;
1739141Smax.romanov@nginx.com 
1740141Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(c->mem_pool, 16384, 0);
1741141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1742141Smax.romanov@nginx.com         /* TODO pogorevaTb */
1743141Smax.romanov@nginx.com     }
1744141Smax.romanov@nginx.com 
1745141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
1746141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
1747141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
1748141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
1749141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
1750141Smax.romanov@nginx.com 
1751141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
1752141Smax.romanov@nginx.com 
1753141Smax.romanov@nginx.com     va_start(args, fmt);
1754141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
1755141Smax.romanov@nginx.com     va_end(args);
1756141Smax.romanov@nginx.com 
1757141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
1758141Smax.romanov@nginx.com 
1759141Smax.romanov@nginx.com     last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
1760141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
1761141Smax.romanov@nginx.com         /* TODO pogorevaTb */
1762141Smax.romanov@nginx.com     }
1763141Smax.romanov@nginx.com 
1764141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
1765141Smax.romanov@nginx.com 
1766141Smax.romanov@nginx.com     if (c->write == NULL) {
1767141Smax.romanov@nginx.com         c->write = b;
1768141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
1769141Smax.romanov@nginx.com 
1770141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
1771141Smax.romanov@nginx.com     } else {
1772141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
1773141Smax.romanov@nginx.com 
1774141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
1775141Smax.romanov@nginx.com     }
1776141Smax.romanov@nginx.com }
1777141Smax.romanov@nginx.com 
1778141Smax.romanov@nginx.com 
1779141Smax.romanov@nginx.com static void
1780141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
1781141Smax.romanov@nginx.com {
1782141Smax.romanov@nginx.com     nxt_buf_t           *b;
1783141Smax.romanov@nginx.com     nxt_app_t           *app;
1784141Smax.romanov@nginx.com     nxt_port_t          *port;
1785141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
1786141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1787141Smax.romanov@nginx.com 
1788141Smax.romanov@nginx.com     sw = obj;
1789141Smax.romanov@nginx.com     app = sw->app;
1790141Smax.romanov@nginx.com 
1791141Smax.romanov@nginx.com     nxt_debug(task, "send sw #%uD", sw->stream);
1792141Smax.romanov@nginx.com 
1793141Smax.romanov@nginx.com     nxt_router_sw_add(task, nxt_router, sw);
1794141Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->rc->app_link);
179588Smax.romanov@nginx.com 
1796119Smax.romanov@nginx.com     rt = task->thread->runtime;
1797141Smax.romanov@nginx.com     port = rt->port_by_type[NXT_PROCESS_MASTER];
1798141Smax.romanov@nginx.com 
1799141Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(port->mem_pool, app->conf.length, 0);
1800141Smax.romanov@nginx.com 
1801141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1802141Smax.romanov@nginx.com 
1803141Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_DATA, -1, sw->stream, 0, b);
1804141Smax.romanov@nginx.com }
1805141Smax.romanov@nginx.com 
1806141Smax.romanov@nginx.com 
1807141Smax.romanov@nginx.com static nxt_port_t *
1808141Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app)
1809141Smax.romanov@nginx.com {
1810141Smax.romanov@nginx.com     nxt_port_t        *port;
1811141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
1812141Smax.romanov@nginx.com 
1813141Smax.romanov@nginx.com     port = NULL;
1814141Smax.romanov@nginx.com 
1815141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1816141Smax.romanov@nginx.com 
1817141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
1818141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
1819141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1820141Smax.romanov@nginx.com 
1821141Smax.romanov@nginx.com         lnk->next = NULL;
1822141Smax.romanov@nginx.com 
1823141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
1824141Smax.romanov@nginx.com     }
1825141Smax.romanov@nginx.com 
1826141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1827141Smax.romanov@nginx.com 
1828141Smax.romanov@nginx.com     return port;
1829141Smax.romanov@nginx.com }
1830141Smax.romanov@nginx.com 
1831141Smax.romanov@nginx.com 
1832141Smax.romanov@nginx.com static void
1833141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
1834141Smax.romanov@nginx.com {
1835141Smax.romanov@nginx.com     nxt_app_t            *app;
1836141Smax.romanov@nginx.com     nxt_port_t           *port;
1837141Smax.romanov@nginx.com     nxt_work_t           *work;
1838141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
1839141Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
1840141Smax.romanov@nginx.com 
1841141Smax.romanov@nginx.com     port = obj;
1842141Smax.romanov@nginx.com     app = data;
1843141Smax.romanov@nginx.com 
1844141Smax.romanov@nginx.com     nxt_assert(app != NULL);
1845141Smax.romanov@nginx.com     nxt_assert(app == port->app);
1846141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
1847141Smax.romanov@nginx.com 
1848141Smax.romanov@nginx.com 
1849141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
1850141Smax.romanov@nginx.com         work = (nxt_work_t *) (port + 1);
1851141Smax.romanov@nginx.com 
1852141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
1853141Smax.romanov@nginx.com 
1854141Smax.romanov@nginx.com         work->next = NULL;
1855141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
1856141Smax.romanov@nginx.com         work->task = port->socket.task;
1857141Smax.romanov@nginx.com         work->obj = port;
1858141Smax.romanov@nginx.com         work->data = app;
1859141Smax.romanov@nginx.com 
1860141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
1861141Smax.romanov@nginx.com 
1862141Smax.romanov@nginx.com         return;
1863141Smax.romanov@nginx.com     }
1864141Smax.romanov@nginx.com 
1865141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
1866141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
1867141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1868141Smax.romanov@nginx.com 
1869141Smax.romanov@nginx.com         rc = nxt_queue_link_data(lnk, nxt_req_conn_link_t, app_link);
1870141Smax.romanov@nginx.com 
1871141Smax.romanov@nginx.com         nxt_debug(task, "process request #%uxD", rc->req_id);
1872141Smax.romanov@nginx.com 
1873141Smax.romanov@nginx.com         rc->app_port = port;
1874141Smax.romanov@nginx.com 
1875141Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, rc, rc->app_port->mem_pool);
1876141Smax.romanov@nginx.com 
1877141Smax.romanov@nginx.com         return;
1878141Smax.romanov@nginx.com     }
1879141Smax.romanov@nginx.com 
1880141Smax.romanov@nginx.com     nxt_debug(task, "app requests queue is empty");
1881141Smax.romanov@nginx.com 
1882141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1883141Smax.romanov@nginx.com 
1884141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
1885141Smax.romanov@nginx.com 
1886141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1887141Smax.romanov@nginx.com }
1888141Smax.romanov@nginx.com 
1889141Smax.romanov@nginx.com 
1890141Smax.romanov@nginx.com void
1891141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
1892141Smax.romanov@nginx.com {
1893141Smax.romanov@nginx.com     nxt_app_t  *app;
1894141Smax.romanov@nginx.com 
1895141Smax.romanov@nginx.com     if (port->app_link.next == NULL) {
1896141Smax.romanov@nginx.com         return;
1897141Smax.romanov@nginx.com     }
1898141Smax.romanov@nginx.com 
1899141Smax.romanov@nginx.com     app = port->app;
1900141Smax.romanov@nginx.com 
1901141Smax.romanov@nginx.com #if (NXT_DEBUG)
1902141Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
1903141Smax.romanov@nginx.com         nxt_abort();
1904141Smax.romanov@nginx.com     }
1905141Smax.romanov@nginx.com #endif
1906141Smax.romanov@nginx.com 
1907141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1908141Smax.romanov@nginx.com 
1909141Smax.romanov@nginx.com     nxt_queue_remove(&port->app_link);
1910141Smax.romanov@nginx.com     port->app_link.next = NULL;
1911141Smax.romanov@nginx.com 
1912141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1913141Smax.romanov@nginx.com }
1914141Smax.romanov@nginx.com 
1915141Smax.romanov@nginx.com 
1916141Smax.romanov@nginx.com nxt_inline nxt_int_t
1917141Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_conn_link_t *rc)
1918141Smax.romanov@nginx.com {
1919141Smax.romanov@nginx.com     nxt_app_t                *app;
1920141Smax.romanov@nginx.com     nxt_conn_t               *c;
1921141Smax.romanov@nginx.com     nxt_port_t               *port, *master_port;
1922141Smax.romanov@nginx.com     nxt_runtime_t            *rt;
1923141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
1924141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
1925141Smax.romanov@nginx.com 
1926141Smax.romanov@nginx.com     port = NULL;
1927141Smax.romanov@nginx.com     c = rc->conn;
1928141Smax.romanov@nginx.com 
1929141Smax.romanov@nginx.com     joint = c->listen->socket.data;
1930141Smax.romanov@nginx.com     app = joint->socket_conf->application;
1931141Smax.romanov@nginx.com 
1932141Smax.romanov@nginx.com 
1933141Smax.romanov@nginx.com     if (app == NULL) {
1934141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
1935141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
1936141Smax.romanov@nginx.com         return NXT_ERROR;
1937141Smax.romanov@nginx.com     }
1938141Smax.romanov@nginx.com 
1939141Smax.romanov@nginx.com 
1940141Smax.romanov@nginx.com     port = nxt_router_app_get_port(app);
1941141Smax.romanov@nginx.com 
1942141Smax.romanov@nginx.com     if (port != NULL) {
1943141Smax.romanov@nginx.com         rc->app_port = port;
1944141Smax.romanov@nginx.com         return NXT_OK;
1945141Smax.romanov@nginx.com     }
1946141Smax.romanov@nginx.com 
1947141Smax.romanov@nginx.com 
1948141Smax.romanov@nginx.com     sw = nxt_mp_retain(c->mem_pool, sizeof(nxt_start_worker_t));
1949141Smax.romanov@nginx.com 
1950141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
1951141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
1952141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
1953141Smax.romanov@nginx.com         return NXT_ERROR;
1954141Smax.romanov@nginx.com     }
1955141Smax.romanov@nginx.com 
1956141Smax.romanov@nginx.com     nxt_memzero(sw, sizeof(nxt_start_worker_t));
1957141Smax.romanov@nginx.com 
1958141Smax.romanov@nginx.com     sw->stream = nxt_random(&task->thread->random);
1959141Smax.romanov@nginx.com     sw->app = app;
1960141Smax.romanov@nginx.com     sw->rc = rc;
1961141Smax.romanov@nginx.com     sw->mem_pool = c->mem_pool;
1962141Smax.romanov@nginx.com     sw->joint = c->listen->socket.data;
1963141Smax.romanov@nginx.com 
1964141Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
1965141Smax.romanov@nginx.com     sw->work.task = task;
1966141Smax.romanov@nginx.com     sw->work.obj = sw;
1967141Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
1968141Smax.romanov@nginx.com 
1969141Smax.romanov@nginx.com     rt = task->thread->runtime;
1970141Smax.romanov@nginx.com 
1971141Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
1972141Smax.romanov@nginx.com 
1973141Smax.romanov@nginx.com     nxt_debug(task, "post send sw %uxD to master engine %p", sw->stream,
1974141Smax.romanov@nginx.com               master_port->engine);
1975141Smax.romanov@nginx.com 
1976141Smax.romanov@nginx.com     nxt_event_engine_post(master_port->engine, &sw->work);
1977141Smax.romanov@nginx.com 
1978141Smax.romanov@nginx.com     return NXT_AGAIN;
197988Smax.romanov@nginx.com }
198088Smax.romanov@nginx.com 
198188Smax.romanov@nginx.com 
198288Smax.romanov@nginx.com static void
198353Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
198453Sigor@sysoev.ru {
198588Smax.romanov@nginx.com     size_t                    size, preread;
198653Sigor@sysoev.ru     nxt_int_t                 ret;
198753Sigor@sysoev.ru     nxt_buf_t                 *b;
198862Sigor@sysoev.ru     nxt_conn_t                *c;
198988Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
199053Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
199188Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
199253Sigor@sysoev.ru 
199353Sigor@sysoev.ru     c = obj;
199488Smax.romanov@nginx.com     ap = data;
199588Smax.romanov@nginx.com     b = c->read;
199653Sigor@sysoev.ru 
199753Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
199853Sigor@sysoev.ru 
199988Smax.romanov@nginx.com     if (ap == NULL) {
200088Smax.romanov@nginx.com         ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
200188Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
200253Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
200353Sigor@sysoev.ru             return;
200453Sigor@sysoev.ru         }
200553Sigor@sysoev.ru 
200688Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
200761Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
200861Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
200961Sigor@sysoev.ru             return;
201061Sigor@sysoev.ru         }
201188Smax.romanov@nginx.com 
201288Smax.romanov@nginx.com         c->socket.data = ap;
2013113Smax.romanov@nginx.com 
2014113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2015113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
201653Sigor@sysoev.ru     }
201753Sigor@sysoev.ru 
201888Smax.romanov@nginx.com     h = &ap->r.header;
201988Smax.romanov@nginx.com 
202088Smax.romanov@nginx.com     ret = nxt_app_http_req_parse(task, ap, b);
202153Sigor@sysoev.ru 
202253Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
202353Sigor@sysoev.ru 
202453Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
202553Sigor@sysoev.ru 
202653Sigor@sysoev.ru     case NXT_DONE:
202788Smax.romanov@nginx.com         preread = nxt_buf_mem_used_size(&b->mem);
202888Smax.romanov@nginx.com 
202988Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
203088Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
203188Smax.romanov@nginx.com                   h->parsed_content_length, preread);
203288Smax.romanov@nginx.com 
203388Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
203488Smax.romanov@nginx.com         return;
203553Sigor@sysoev.ru 
203653Sigor@sysoev.ru     case NXT_ERROR:
203753Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
203853Sigor@sysoev.ru         return;
203953Sigor@sysoev.ru 
204053Sigor@sysoev.ru     default:  /* NXT_AGAIN */
204153Sigor@sysoev.ru 
204288Smax.romanov@nginx.com         if (h->done == 0) {
204388Smax.romanov@nginx.com 
204488Smax.romanov@nginx.com             if (c->read->mem.free == c->read->mem.end) {
204588Smax.romanov@nginx.com                 joint = c->listen->socket.data;
204688Smax.romanov@nginx.com                 size = joint->socket_conf->large_header_buffer_size;
204788Smax.romanov@nginx.com 
204888Smax.romanov@nginx.com                 if (size > (size_t) nxt_buf_mem_size(&b->mem)) {
204988Smax.romanov@nginx.com                     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
205088Smax.romanov@nginx.com                     if (nxt_slow_path(b == NULL)) {
205188Smax.romanov@nginx.com                         nxt_router_conn_close(task, c, data);
205288Smax.romanov@nginx.com                         return;
205388Smax.romanov@nginx.com                     }
205488Smax.romanov@nginx.com 
205588Smax.romanov@nginx.com                     size = c->read->mem.free - c->read->mem.pos;
2056141Smax.romanov@nginx.com 
2057141Smax.romanov@nginx.com                     c->read = nxt_buf_cpy(b, c->read->mem.pos, size);
205888Smax.romanov@nginx.com                 } else {
2059141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 400,
2060141Smax.romanov@nginx.com                                          "Too long request headers");
2061141Smax.romanov@nginx.com                     return;
206288Smax.romanov@nginx.com                 }
206388Smax.romanov@nginx.com             }
206488Smax.romanov@nginx.com         }
206588Smax.romanov@nginx.com 
206688Smax.romanov@nginx.com         if (ap->r.body.done == 0) {
206788Smax.romanov@nginx.com 
206888Smax.romanov@nginx.com             preread = nxt_buf_mem_used_size(&b->mem);
206988Smax.romanov@nginx.com 
207088Smax.romanov@nginx.com             if (h->parsed_content_length - preread >
207188Smax.romanov@nginx.com                 (size_t) nxt_buf_mem_free_size(&b->mem)) {
207288Smax.romanov@nginx.com 
207388Smax.romanov@nginx.com                 b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0);
207488Smax.romanov@nginx.com                 if (nxt_slow_path(b == NULL)) {
2075141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 500, "Failed to allocate "
2076141Smax.romanov@nginx.com                                          "buffer for request body");
2077141Smax.romanov@nginx.com                     return;
207888Smax.romanov@nginx.com                 }
207988Smax.romanov@nginx.com 
2080141Smax.romanov@nginx.com                 c->read = nxt_buf_cpy(b, c->read->mem.pos, preread);
208153Sigor@sysoev.ru             }
208253Sigor@sysoev.ru 
208388Smax.romanov@nginx.com             nxt_debug(task, "router request body read again, rest: %uz",
208488Smax.romanov@nginx.com                       h->parsed_content_length - preread);
208553Sigor@sysoev.ru 
208653Sigor@sysoev.ru         }
208753Sigor@sysoev.ru 
208888Smax.romanov@nginx.com     }
208988Smax.romanov@nginx.com 
209088Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
209188Smax.romanov@nginx.com }
209288Smax.romanov@nginx.com 
209388Smax.romanov@nginx.com 
209488Smax.romanov@nginx.com static void
209588Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
209688Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
209788Smax.romanov@nginx.com {
2098122Smax.romanov@nginx.com     nxt_int_t            res;
209988Smax.romanov@nginx.com     nxt_req_id_t         req_id;
210088Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
210188Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
210288Smax.romanov@nginx.com 
210388Smax.romanov@nginx.com     engine = task->thread->engine;
210488Smax.romanov@nginx.com 
210588Smax.romanov@nginx.com     do {
2106138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
210788Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
210888Smax.romanov@nginx.com 
210988Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2110122Smax.romanov@nginx.com 
211188Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2112141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2113141Smax.romanov@nginx.com                              "req->conn link");
2114141Smax.romanov@nginx.com 
2115141Smax.romanov@nginx.com         return;
211688Smax.romanov@nginx.com     }
211788Smax.romanov@nginx.com 
211888Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
211988Smax.romanov@nginx.com 
212088Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
212188Smax.romanov@nginx.com               req_id, c, engine);
212253Sigor@sysoev.ru 
2123141Smax.romanov@nginx.com     rc->reply_port = engine->port;
2124141Smax.romanov@nginx.com 
2125141Smax.romanov@nginx.com     res = nxt_router_app_port(task, rc);
2126141Smax.romanov@nginx.com 
2127141Smax.romanov@nginx.com     if (res != NXT_OK) {
2128141Smax.romanov@nginx.com         return;
2129141Smax.romanov@nginx.com     }
2130141Smax.romanov@nginx.com 
2131141Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, rc, c->mem_pool);
2132141Smax.romanov@nginx.com }
2133141Smax.romanov@nginx.com 
2134141Smax.romanov@nginx.com 
2135141Smax.romanov@nginx.com static void
2136141Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_conn_link_t *rc,
2137141Smax.romanov@nginx.com     nxt_mp_t *mp)
2138141Smax.romanov@nginx.com {
2139141Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2140141Smax.romanov@nginx.com     nxt_int_t            res;
2141141Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
2142141Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2143141Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2144141Smax.romanov@nginx.com 
2145141Smax.romanov@nginx.com     port = rc->app_port;
2146141Smax.romanov@nginx.com 
2147141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2148141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2149141Smax.romanov@nginx.com         return;
2150141Smax.romanov@nginx.com     }
2151141Smax.romanov@nginx.com 
2152141Smax.romanov@nginx.com     reply_port = rc->reply_port;
2153141Smax.romanov@nginx.com     ap = rc->conn->socket.data;
2154141Smax.romanov@nginx.com 
2155122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2156141Smax.romanov@nginx.com     port->mem_pool = mp;
2157141Smax.romanov@nginx.com 
2158141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2159141Smax.romanov@nginx.com                                              reply_port->id);
2160141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2161141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2162122Smax.romanov@nginx.com 
2163122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2164141Smax.romanov@nginx.com             nxt_router_gen_error(task, rc->conn, 500,
2165141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2166141Smax.romanov@nginx.com             goto fail;
2167122Smax.romanov@nginx.com         }
2168122Smax.romanov@nginx.com 
2169141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
217088Smax.romanov@nginx.com     }
217188Smax.romanov@nginx.com 
217288Smax.romanov@nginx.com     wmsg.port = port;
217388Smax.romanov@nginx.com     wmsg.write = NULL;
217488Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2175141Smax.romanov@nginx.com     wmsg.stream = rc->req_id;
2176141Smax.romanov@nginx.com 
2177141Smax.romanov@nginx.com     res = rc->app_port->app->module->prepare_msg(task, &ap->r, &wmsg);
2178122Smax.romanov@nginx.com 
2179122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2180141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2181141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2182141Smax.romanov@nginx.com         goto fail;
2183122Smax.romanov@nginx.com     }
218488Smax.romanov@nginx.com 
218588Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
218688Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
218788Smax.romanov@nginx.com                     wmsg.port->socket.fd);
218888Smax.romanov@nginx.com 
2189122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2190141Smax.romanov@nginx.com                                  -1, rc->req_id, reply_port->id, wmsg.write);
2191122Smax.romanov@nginx.com 
2192122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2193141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2194141Smax.romanov@nginx.com                              "Failed to send message to application");
2195141Smax.romanov@nginx.com         goto fail;
2196122Smax.romanov@nginx.com     }
2197122Smax.romanov@nginx.com 
2198141Smax.romanov@nginx.com fail:
2199122Smax.romanov@nginx.com     port->mem_pool = port_mp;
220053Sigor@sysoev.ru }
220153Sigor@sysoev.ru 
220253Sigor@sysoev.ru 
220362Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
220453Sigor@sysoev.ru     nxt_aligned(64) =
220553Sigor@sysoev.ru {
220653Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
220753Sigor@sysoev.ru };
220853Sigor@sysoev.ru 
220953Sigor@sysoev.ru 
221053Sigor@sysoev.ru static void
221188Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
221288Smax.romanov@nginx.com {
221388Smax.romanov@nginx.com     nxt_buf_t         *b;
221488Smax.romanov@nginx.com     nxt_bool_t        last;
221588Smax.romanov@nginx.com     nxt_conn_t        *c;
221688Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
221788Smax.romanov@nginx.com 
221888Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
221988Smax.romanov@nginx.com 
222088Smax.romanov@nginx.com     c = obj;
222188Smax.romanov@nginx.com     b = c->write;
222288Smax.romanov@nginx.com 
222388Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
222488Smax.romanov@nginx.com 
222588Smax.romanov@nginx.com     last = 0;
222688Smax.romanov@nginx.com 
222788Smax.romanov@nginx.com     while (b != NULL) {
222888Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
222988Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
223088Smax.romanov@nginx.com                 break;
223188Smax.romanov@nginx.com             }
223288Smax.romanov@nginx.com         }
223388Smax.romanov@nginx.com 
223488Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
223588Smax.romanov@nginx.com             last = 1;
223688Smax.romanov@nginx.com         }
223788Smax.romanov@nginx.com 
223888Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
223988Smax.romanov@nginx.com 
224088Smax.romanov@nginx.com         b = b->next;
224188Smax.romanov@nginx.com     }
224288Smax.romanov@nginx.com 
224388Smax.romanov@nginx.com     c->write = b;
224488Smax.romanov@nginx.com 
224588Smax.romanov@nginx.com     if (b != NULL) {
224688Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
224788Smax.romanov@nginx.com 
224888Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
224988Smax.romanov@nginx.com     } else {
225088Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
225188Smax.romanov@nginx.com                   last);
225288Smax.romanov@nginx.com 
225388Smax.romanov@nginx.com         if (last != 0) {
225488Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
225588Smax.romanov@nginx.com 
225688Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
225788Smax.romanov@nginx.com                                c->socket.data);
225888Smax.romanov@nginx.com         }
225988Smax.romanov@nginx.com     }
226088Smax.romanov@nginx.com }
226188Smax.romanov@nginx.com 
226288Smax.romanov@nginx.com 
226388Smax.romanov@nginx.com static void
226453Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
226553Sigor@sysoev.ru {
226662Sigor@sysoev.ru     nxt_conn_t  *c;
226753Sigor@sysoev.ru 
226853Sigor@sysoev.ru     c = obj;
226953Sigor@sysoev.ru 
227053Sigor@sysoev.ru     nxt_debug(task, "router conn close");
227153Sigor@sysoev.ru 
227253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
227353Sigor@sysoev.ru 
227462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
227553Sigor@sysoev.ru }
227653Sigor@sysoev.ru 
227753Sigor@sysoev.ru 
227853Sigor@sysoev.ru static void
227953Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
228053Sigor@sysoev.ru {
228162Sigor@sysoev.ru     nxt_conn_t               *c;
228288Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
228353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
228453Sigor@sysoev.ru 
228553Sigor@sysoev.ru     c = obj;
228653Sigor@sysoev.ru 
228753Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
228853Sigor@sysoev.ru 
228988Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
229088Smax.romanov@nginx.com 
229188Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
229288Smax.romanov@nginx.com 
2293141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2294141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2295141Smax.romanov@nginx.com 
2296141Smax.romanov@nginx.com             rc->app_port = NULL;
2297141Smax.romanov@nginx.com         }
2298141Smax.romanov@nginx.com 
229988Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
230088Smax.romanov@nginx.com 
230188Smax.romanov@nginx.com     } nxt_queue_loop;
230288Smax.romanov@nginx.com 
2303122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
2304122Smax.romanov@nginx.com 
2305131Smax.romanov@nginx.com     joint = c->listen->socket.data;
2306131Smax.romanov@nginx.com 
2307131Smax.romanov@nginx.com     task = &task->thread->engine->task;
2308131Smax.romanov@nginx.com 
2309141Smax.romanov@nginx.com     if (nxt_mp_release(c->mem_pool, c) == 0) {
2310141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
2311141Smax.romanov@nginx.com     }
231253Sigor@sysoev.ru }
231353Sigor@sysoev.ru 
231453Sigor@sysoev.ru 
231553Sigor@sysoev.ru static void
231653Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
231753Sigor@sysoev.ru {
231862Sigor@sysoev.ru     nxt_conn_t  *c;
231953Sigor@sysoev.ru 
232053Sigor@sysoev.ru     c = obj;
232153Sigor@sysoev.ru 
232253Sigor@sysoev.ru     nxt_debug(task, "router conn error");
232353Sigor@sysoev.ru 
232453Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
232553Sigor@sysoev.ru 
232662Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
232753Sigor@sysoev.ru }
232853Sigor@sysoev.ru 
232953Sigor@sysoev.ru 
233053Sigor@sysoev.ru static void
233153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
233253Sigor@sysoev.ru {
233362Sigor@sysoev.ru     nxt_conn_t   *c;
233462Sigor@sysoev.ru     nxt_timer_t  *timer;
233553Sigor@sysoev.ru 
233653Sigor@sysoev.ru     timer = obj;
233753Sigor@sysoev.ru 
233853Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
233953Sigor@sysoev.ru 
234062Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
234153Sigor@sysoev.ru 
234253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
234353Sigor@sysoev.ru 
234462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
234553Sigor@sysoev.ru }
234653Sigor@sysoev.ru 
234753Sigor@sysoev.ru 
234853Sigor@sysoev.ru static nxt_msec_t
234962Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
235053Sigor@sysoev.ru {
235153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
235253Sigor@sysoev.ru 
235353Sigor@sysoev.ru     joint = c->listen->socket.data;
235453Sigor@sysoev.ru 
235553Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
235653Sigor@sysoev.ru }
2357141Smax.romanov@nginx.com 
2358141Smax.romanov@nginx.com 
2359141Smax.romanov@nginx.com static nxt_int_t
2360141Smax.romanov@nginx.com nxt_sw_test(nxt_lvlhsh_query_t *lhq, void *data)
2361141Smax.romanov@nginx.com {
2362141Smax.romanov@nginx.com     return NXT_OK;
2363141Smax.romanov@nginx.com }
2364141Smax.romanov@nginx.com 
2365141Smax.romanov@nginx.com 
2366141Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_sw_proto  nxt_aligned(64) = {
2367141Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
2368141Smax.romanov@nginx.com     nxt_sw_test,
2369141Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
2370141Smax.romanov@nginx.com     nxt_lvlhsh_free,
2371141Smax.romanov@nginx.com };
2372141Smax.romanov@nginx.com 
2373141Smax.romanov@nginx.com 
2374141Smax.romanov@nginx.com static void
2375141Smax.romanov@nginx.com nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
2376141Smax.romanov@nginx.com     nxt_start_worker_t *sw)
2377141Smax.romanov@nginx.com {
2378141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2379141Smax.romanov@nginx.com 
2380141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&sw->stream, sizeof(sw->stream));
2381141Smax.romanov@nginx.com     lhq.key.length = sizeof(sw->stream);
2382141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &sw->stream;
2383141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2384141Smax.romanov@nginx.com     lhq.replace = 0;
2385141Smax.romanov@nginx.com     lhq.value = sw;
2386141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2387141Smax.romanov@nginx.com 
2388141Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&router->start_workers, &lhq)) {
2389141Smax.romanov@nginx.com 
2390141Smax.romanov@nginx.com     case NXT_OK:
2391141Smax.romanov@nginx.com         break;
2392141Smax.romanov@nginx.com 
2393141Smax.romanov@nginx.com     default:
2394141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw add failed",
2395141Smax.romanov@nginx.com                       sw->stream);
2396141Smax.romanov@nginx.com         break;
2397141Smax.romanov@nginx.com     }
2398141Smax.romanov@nginx.com }
2399141Smax.romanov@nginx.com 
2400141Smax.romanov@nginx.com 
2401141Smax.romanov@nginx.com static nxt_start_worker_t *
2402141Smax.romanov@nginx.com nxt_router_sw_find_remove(nxt_task_t *task, nxt_router_t *router, uint32_t id)
2403141Smax.romanov@nginx.com {
2404141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2405141Smax.romanov@nginx.com 
2406141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&id, sizeof(id));
2407141Smax.romanov@nginx.com     lhq.key.length = sizeof(id);
2408141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &id;
2409141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2410141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2411141Smax.romanov@nginx.com 
2412141Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&router->start_workers, &lhq)) {
2413141Smax.romanov@nginx.com 
2414141Smax.romanov@nginx.com     case NXT_OK:
2415141Smax.romanov@nginx.com         return lhq.value;
2416141Smax.romanov@nginx.com 
2417141Smax.romanov@nginx.com     default:
2418141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw remove failed",
2419141Smax.romanov@nginx.com                       id);
2420141Smax.romanov@nginx.com         break;
2421141Smax.romanov@nginx.com     }
2422141Smax.romanov@nginx.com 
2423141Smax.romanov@nginx.com     return NULL;
2424141Smax.romanov@nginx.com }
2425