xref: /unit/src/nxt_router.c (revision 141)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
1020Sigor@sysoev.ru 
1120Sigor@sysoev.ru 
12115Sigor@sysoev.ru typedef struct {
13133Sigor@sysoev.ru     nxt_str_t  type;
14133Sigor@sysoev.ru     uint32_t   workers;
15133Sigor@sysoev.ru } nxt_router_app_conf_t;
16133Sigor@sysoev.ru 
17133Sigor@sysoev.ru 
18133Sigor@sysoev.ru typedef struct {
19133Sigor@sysoev.ru     nxt_str_t  application;
20115Sigor@sysoev.ru } nxt_router_listener_conf_t;
21115Sigor@sysoev.ru 
22115Sigor@sysoev.ru 
23*141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
24*141Smax.romanov@nginx.com 
25*141Smax.romanov@nginx.com struct nxt_start_worker_s {
26*141Smax.romanov@nginx.com     uint32_t               stream;
27*141Smax.romanov@nginx.com     nxt_app_t              *app;
28*141Smax.romanov@nginx.com     nxt_req_conn_link_t    *rc;
29*141Smax.romanov@nginx.com     nxt_mp_t               *mem_pool;
30*141Smax.romanov@nginx.com     void                   *joint;
31*141Smax.romanov@nginx.com 
32*141Smax.romanov@nginx.com     nxt_work_t             work;
33*141Smax.romanov@nginx.com };
34*141Smax.romanov@nginx.com 
35*141Smax.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 
103*141Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app);
104*141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
105*141Smax.romanov@nginx.com     void *data);
106*141Smax.romanov@nginx.com 
107*141Smax.romanov@nginx.com static void nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
108*141Smax.romanov@nginx.com     nxt_start_worker_t *sw);
109*141Smax.romanov@nginx.com static nxt_start_worker_t *nxt_router_sw_find_remove(nxt_task_t *task,
110*141Smax.romanov@nginx.com     nxt_router_t *router, uint32_t id);
111*141Smax.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);
117*141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
118*141Smax.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 
126*141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
127*141Smax.romanov@nginx.com     const char* fmt, ...);
128*141Smax.romanov@nginx.com 
129119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
13020Sigor@sysoev.ru 
13120Sigor@sysoev.ru nxt_int_t
132*141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
13320Sigor@sysoev.ru {
134*141Smax.romanov@nginx.com     nxt_int_t      ret;
135*141Smax.romanov@nginx.com     nxt_router_t   *router;
136*141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
137*141Smax.romanov@nginx.com 
138*141Smax.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 
160*141Smax.romanov@nginx.com static void
161*141Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, void *obj, void *data)
162*141Smax.romanov@nginx.com {
163*141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
164*141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
165*141Smax.romanov@nginx.com 
166*141Smax.romanov@nginx.com     sw = obj;
167*141Smax.romanov@nginx.com     joint = sw->joint;
168*141Smax.romanov@nginx.com 
169*141Smax.romanov@nginx.com     nxt_debug(task, "sw #%uxD release", sw->stream);
170*141Smax.romanov@nginx.com 
171*141Smax.romanov@nginx.com     if (nxt_mp_release(sw->mem_pool, sw) == 0) {
172*141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
173*141Smax.romanov@nginx.com     }
174*141Smax.romanov@nginx.com }
175*141Smax.romanov@nginx.com 
176*141Smax.romanov@nginx.com 
177*141Smax.romanov@nginx.com void
178*141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
179*141Smax.romanov@nginx.com {
180*141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
181*141Smax.romanov@nginx.com 
182*141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
183*141Smax.romanov@nginx.com 
184*141Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
185*141Smax.romanov@nginx.com         return;
186*141Smax.romanov@nginx.com     }
187*141Smax.romanov@nginx.com 
188*141Smax.romanov@nginx.com     sw = nxt_router_sw_find_remove(task, nxt_router, msg->port_msg.stream);
189*141Smax.romanov@nginx.com 
190*141Smax.romanov@nginx.com     if (nxt_fast_path(sw != NULL)) {
191*141Smax.romanov@nginx.com         msg->new_port->app = sw->app;
192*141Smax.romanov@nginx.com 
193*141Smax.romanov@nginx.com         nxt_router_app_release_port(task, msg->new_port, sw->app);
194*141Smax.romanov@nginx.com 
195*141Smax.romanov@nginx.com         sw->work.handler = nxt_router_sw_release;
196*141Smax.romanov@nginx.com 
197*141Smax.romanov@nginx.com         nxt_debug(task, "post sw #%uxD release to %p", sw->stream,
198*141Smax.romanov@nginx.com                   sw->work.data);
199*141Smax.romanov@nginx.com 
200*141Smax.romanov@nginx.com         nxt_event_engine_post(sw->work.data, &sw->work);
201*141Smax.romanov@nginx.com     }
202*141Smax.romanov@nginx.com }
203*141Smax.romanov@nginx.com 
204*141Smax.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 {
384139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
385139Sigor@sysoev.ru 
386139Sigor@sysoev.ru     nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5);
387139Sigor@sysoev.ru }
388139Sigor@sysoev.ru 
389139Sigor@sysoev.ru 
390139Sigor@sysoev.ru static void
391139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
392139Sigor@sysoev.ru     u_char *start, size_t size)
393139Sigor@sysoev.ru {
394139Sigor@sysoev.ru     nxt_buf_t  *b;
395139Sigor@sysoev.ru 
396139Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
397139Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
398139Sigor@sysoev.ru         return;
399139Sigor@sysoev.ru     }
400139Sigor@sysoev.ru 
401140Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, start, size);
402140Svbart@nginx.com 
403139Sigor@sysoev.ru     b->parent = tmcf->mem_pool;
404139Sigor@sysoev.ru     b->completion_handler = nxt_router_conf_buf_completion;
405139Sigor@sysoev.ru 
406139Sigor@sysoev.ru     nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1,
407139Sigor@sysoev.ru                           tmcf->stream, 0, b);
408139Sigor@sysoev.ru }
409139Sigor@sysoev.ru 
410139Sigor@sysoev.ru 
411139Sigor@sysoev.ru static void
412139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data)
413139Sigor@sysoev.ru {
414139Sigor@sysoev.ru     nxt_mp_t  *mp;
415139Sigor@sysoev.ru 
416139Sigor@sysoev.ru     /* nxt_router_temp_conf_t mem pool. */
417139Sigor@sysoev.ru     mp = data;
418139Sigor@sysoev.ru 
419139Sigor@sysoev.ru     nxt_mp_destroy(mp);
420139Sigor@sysoev.ru }
421139Sigor@sysoev.ru 
422139Sigor@sysoev.ru 
423115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
424115Sigor@sysoev.ru     {
425133Sigor@sysoev.ru         nxt_string("listeners_threads"),
426115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
427115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
428115Sigor@sysoev.ru     },
429115Sigor@sysoev.ru };
430115Sigor@sysoev.ru 
431115Sigor@sysoev.ru 
432133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
433115Sigor@sysoev.ru     {
434133Sigor@sysoev.ru         nxt_string("type"),
435115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
436133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
437115Sigor@sysoev.ru     },
438115Sigor@sysoev.ru 
439115Sigor@sysoev.ru     {
440133Sigor@sysoev.ru         nxt_string("workers"),
441115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
442133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
443133Sigor@sysoev.ru     },
444133Sigor@sysoev.ru };
445133Sigor@sysoev.ru 
446133Sigor@sysoev.ru 
447133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
448133Sigor@sysoev.ru     {
449133Sigor@sysoev.ru         nxt_string("application"),
450133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
451133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
452115Sigor@sysoev.ru     },
453115Sigor@sysoev.ru };
454115Sigor@sysoev.ru 
455115Sigor@sysoev.ru 
456115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
457115Sigor@sysoev.ru     {
458115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
459115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
460115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
461115Sigor@sysoev.ru     },
462115Sigor@sysoev.ru 
463115Sigor@sysoev.ru     {
464115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
465115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
466115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
467115Sigor@sysoev.ru     },
468115Sigor@sysoev.ru 
469115Sigor@sysoev.ru     {
470115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
471115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
472115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
473115Sigor@sysoev.ru     },
474115Sigor@sysoev.ru };
475115Sigor@sysoev.ru 
476115Sigor@sysoev.ru 
47753Sigor@sysoev.ru static nxt_int_t
478115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
479115Sigor@sysoev.ru     u_char *start, u_char *end)
48053Sigor@sysoev.ru {
481133Sigor@sysoev.ru     u_char                      *p;
482133Sigor@sysoev.ru     size_t                      size;
483115Sigor@sysoev.ru     nxt_mp_t                    *mp;
484115Sigor@sysoev.ru     uint32_t                    next;
485115Sigor@sysoev.ru     nxt_int_t                   ret;
486115Sigor@sysoev.ru     nxt_str_t                   name;
487133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
488133Sigor@sysoev.ru     nxt_app_type_t              type;
489115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
490133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
491133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
492133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
493115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
494133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
495115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
496115Sigor@sysoev.ru 
497115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
498133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
499115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
500115Sigor@sysoev.ru 
501115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
502115Sigor@sysoev.ru     if (conf == NULL) {
503115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
504115Sigor@sysoev.ru         return NXT_ERROR;
505115Sigor@sysoev.ru     }
506115Sigor@sysoev.ru 
507136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
508136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
509115Sigor@sysoev.ru     if (ret != NXT_OK) {
510133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
511115Sigor@sysoev.ru         return NXT_ERROR;
512115Sigor@sysoev.ru     }
513115Sigor@sysoev.ru 
514117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
515117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
516117Sigor@sysoev.ru     }
517117Sigor@sysoev.ru 
518133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
519133Sigor@sysoev.ru     if (applications == NULL) {
520133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
521115Sigor@sysoev.ru         return NXT_ERROR;
522115Sigor@sysoev.ru     }
523115Sigor@sysoev.ru 
524133Sigor@sysoev.ru     next = 0;
525133Sigor@sysoev.ru 
526133Sigor@sysoev.ru     for ( ;; ) {
527133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
528133Sigor@sysoev.ru         if (application == NULL) {
529133Sigor@sysoev.ru             break;
530133Sigor@sysoev.ru         }
531133Sigor@sysoev.ru 
532133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
533133Sigor@sysoev.ru 
534133Sigor@sysoev.ru         app = nxt_zalloc(sizeof(nxt_app_t));
535133Sigor@sysoev.ru         if (app == NULL) {
536133Sigor@sysoev.ru             goto fail;
537133Sigor@sysoev.ru         }
538133Sigor@sysoev.ru 
539133Sigor@sysoev.ru         size = nxt_conf_json_length(application, NULL);
540133Sigor@sysoev.ru 
541133Sigor@sysoev.ru         app->conf.start = nxt_malloc(size);
542133Sigor@sysoev.ru         if (app->conf.start == NULL) {
543133Sigor@sysoev.ru             nxt_free(app);
544133Sigor@sysoev.ru             goto fail;
545133Sigor@sysoev.ru         }
546133Sigor@sysoev.ru 
547133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
548133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
549133Sigor@sysoev.ru 
550133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
551133Sigor@sysoev.ru 
552133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
553133Sigor@sysoev.ru 
554133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
555133Sigor@sysoev.ru             nxt_free(app->conf.start);
556133Sigor@sysoev.ru             nxt_free(app);
557133Sigor@sysoev.ru 
558133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
559133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
560133Sigor@sysoev.ru             continue;
561133Sigor@sysoev.ru         }
562133Sigor@sysoev.ru 
563136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
564136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
565133Sigor@sysoev.ru         if (ret != NXT_OK) {
566133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
567133Sigor@sysoev.ru             goto app_fail;
568133Sigor@sysoev.ru         }
569115Sigor@sysoev.ru 
570133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
571133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
572133Sigor@sysoev.ru 
573*141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
574*141Smax.romanov@nginx.com 
575*141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
576*141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
577*141Smax.romanov@nginx.com                     &apcf.type);
578*141Smax.romanov@nginx.com             goto app_fail;
579*141Smax.romanov@nginx.com         }
580*141Smax.romanov@nginx.com 
581*141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
582133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
583133Sigor@sysoev.ru                     &apcf.type);
584133Sigor@sysoev.ru             goto app_fail;
585133Sigor@sysoev.ru         }
586133Sigor@sysoev.ru 
587133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
588133Sigor@sysoev.ru         if (ret != NXT_OK) {
589133Sigor@sysoev.ru             goto app_fail;
590133Sigor@sysoev.ru         }
591133Sigor@sysoev.ru 
592*141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
593*141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
594*141Smax.romanov@nginx.com 
595133Sigor@sysoev.ru         app->name = name;
596133Sigor@sysoev.ru         app->type = type;
597133Sigor@sysoev.ru         app->max_workers = apcf.workers;
598133Sigor@sysoev.ru         app->live = 1;
599*141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
600133Sigor@sysoev.ru 
601133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
602133Sigor@sysoev.ru     }
603133Sigor@sysoev.ru 
604133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
605133Sigor@sysoev.ru #if 0
606133Sigor@sysoev.ru     if (http == NULL) {
607133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
608133Sigor@sysoev.ru         return NXT_ERROR;
609133Sigor@sysoev.ru     }
610133Sigor@sysoev.ru #endif
611133Sigor@sysoev.ru 
612133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
613115Sigor@sysoev.ru     if (listeners == NULL) {
614133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
615115Sigor@sysoev.ru         return NXT_ERROR;
616115Sigor@sysoev.ru     }
61753Sigor@sysoev.ru 
618133Sigor@sysoev.ru     next = 0;
61953Sigor@sysoev.ru 
620133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
621115Sigor@sysoev.ru 
622115Sigor@sysoev.ru     for ( ;; ) {
623115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
624115Sigor@sysoev.ru         if (listener == NULL) {
625115Sigor@sysoev.ru             break;
626115Sigor@sysoev.ru         }
62753Sigor@sysoev.ru 
628115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
629115Sigor@sysoev.ru         if (sa == NULL) {
630115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
631133Sigor@sysoev.ru             goto fail;
632115Sigor@sysoev.ru         }
633115Sigor@sysoev.ru 
634115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
635115Sigor@sysoev.ru 
636115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
637115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
63853Sigor@sysoev.ru 
639115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
640115Sigor@sysoev.ru         if (skcf == NULL) {
641133Sigor@sysoev.ru             goto fail;
642115Sigor@sysoev.ru         }
64353Sigor@sysoev.ru 
644136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
645136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
646115Sigor@sysoev.ru         if (ret != NXT_OK) {
647115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
648133Sigor@sysoev.ru             goto fail;
649115Sigor@sysoev.ru         }
65053Sigor@sysoev.ru 
651133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
652133Sigor@sysoev.ru 
653133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
654133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
655133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
656133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
65753Sigor@sysoev.ru 
658133Sigor@sysoev.ru         if (http != NULL) {
659136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
660136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
661133Sigor@sysoev.ru             if (ret != NXT_OK) {
662133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
663133Sigor@sysoev.ru                 goto fail;
664133Sigor@sysoev.ru             }
665115Sigor@sysoev.ru         }
666115Sigor@sysoev.ru 
667115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
668115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
669133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
670133Sigor@sysoev.ru                                                             &lscf.application);
671115Sigor@sysoev.ru 
672115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
673115Sigor@sysoev.ru     }
67453Sigor@sysoev.ru 
67553Sigor@sysoev.ru     return NXT_OK;
676133Sigor@sysoev.ru 
677133Sigor@sysoev.ru app_fail:
678133Sigor@sysoev.ru 
679133Sigor@sysoev.ru     nxt_free(app->conf.start);
680133Sigor@sysoev.ru     nxt_free(app);
681133Sigor@sysoev.ru 
682133Sigor@sysoev.ru fail:
683133Sigor@sysoev.ru 
684*141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
685*141Smax.romanov@nginx.com 
686*141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
687133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
688133Sigor@sysoev.ru         nxt_free(app);
689*141Smax.romanov@nginx.com 
690*141Smax.romanov@nginx.com     } nxt_queue_loop;
691133Sigor@sysoev.ru 
692133Sigor@sysoev.ru     return NXT_ERROR;
693133Sigor@sysoev.ru }
694133Sigor@sysoev.ru 
695133Sigor@sysoev.ru 
696133Sigor@sysoev.ru static nxt_app_t *
697133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
698133Sigor@sysoev.ru {
699*141Smax.romanov@nginx.com     nxt_app_t  *app;
700*141Smax.romanov@nginx.com 
701*141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
702133Sigor@sysoev.ru 
703133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
704133Sigor@sysoev.ru             return app;
705133Sigor@sysoev.ru         }
706*141Smax.romanov@nginx.com 
707*141Smax.romanov@nginx.com     } nxt_queue_loop;
708133Sigor@sysoev.ru 
709133Sigor@sysoev.ru     return NULL;
710133Sigor@sysoev.ru }
711133Sigor@sysoev.ru 
712133Sigor@sysoev.ru 
713133Sigor@sysoev.ru static nxt_app_t *
714133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
715133Sigor@sysoev.ru {
716133Sigor@sysoev.ru     nxt_app_t  *app;
717133Sigor@sysoev.ru 
718133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
719133Sigor@sysoev.ru 
720133Sigor@sysoev.ru     if (app == NULL) {
721134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
722133Sigor@sysoev.ru     }
723133Sigor@sysoev.ru 
724133Sigor@sysoev.ru     return app;
72553Sigor@sysoev.ru }
72653Sigor@sysoev.ru 
72753Sigor@sysoev.ru 
72853Sigor@sysoev.ru static nxt_socket_conf_t *
72965Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
73053Sigor@sysoev.ru {
73153Sigor@sysoev.ru     nxt_socket_conf_t  *conf;
73253Sigor@sysoev.ru 
73365Sigor@sysoev.ru     conf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
73453Sigor@sysoev.ru     if (nxt_slow_path(conf == NULL)) {
73553Sigor@sysoev.ru         return NULL;
73653Sigor@sysoev.ru     }
73753Sigor@sysoev.ru 
738115Sigor@sysoev.ru     conf->sockaddr = sa;
739115Sigor@sysoev.ru 
74053Sigor@sysoev.ru     conf->listen.sockaddr = sa;
741103Sigor@sysoev.ru     conf->listen.socklen = sa->socklen;
742103Sigor@sysoev.ru     conf->listen.address_length = sa->length;
74353Sigor@sysoev.ru 
74453Sigor@sysoev.ru     conf->listen.socket = -1;
74553Sigor@sysoev.ru     conf->listen.backlog = NXT_LISTEN_BACKLOG;
74653Sigor@sysoev.ru     conf->listen.flags = NXT_NONBLOCK;
74753Sigor@sysoev.ru     conf->listen.read_after_accept = 1;
74853Sigor@sysoev.ru 
74953Sigor@sysoev.ru     return conf;
75053Sigor@sysoev.ru }
75153Sigor@sysoev.ru 
75253Sigor@sysoev.ru 
75353Sigor@sysoev.ru static void
75453Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
75553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
75653Sigor@sysoev.ru {
75753Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
75853Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
75953Sigor@sysoev.ru 
76053Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
76153Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
76253Sigor@sysoev.ru          nqlk = next)
76353Sigor@sysoev.ru     {
76453Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
76553Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
76653Sigor@sysoev.ru 
76753Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
76853Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
76953Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
77053Sigor@sysoev.ru         {
77153Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
77253Sigor@sysoev.ru 
773115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
774115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
775115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
776115Sigor@sysoev.ru 
77753Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
77853Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
77953Sigor@sysoev.ru 
78053Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
78153Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
78253Sigor@sysoev.ru 
78353Sigor@sysoev.ru                 break;
78453Sigor@sysoev.ru             }
78553Sigor@sysoev.ru         }
78653Sigor@sysoev.ru     }
78753Sigor@sysoev.ru 
78853Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
789115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
79053Sigor@sysoev.ru }
79153Sigor@sysoev.ru 
79253Sigor@sysoev.ru 
79353Sigor@sysoev.ru static nxt_int_t
79453Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
79553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
79653Sigor@sysoev.ru {
797115Sigor@sysoev.ru     nxt_int_t            ret;
798115Sigor@sysoev.ru     nxt_socket_t         s;
799115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
800115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
801115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
80253Sigor@sysoev.ru 
80353Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
80453Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
80553Sigor@sysoev.ru          qlk = nqlk)
80653Sigor@sysoev.ru     {
807115Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
808115Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
80953Sigor@sysoev.ru             return NXT_ERROR;
81053Sigor@sysoev.ru         }
81153Sigor@sysoev.ru 
812115Sigor@sysoev.ru         rtsk->count = 0;
813115Sigor@sysoev.ru 
814115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
815115Sigor@sysoev.ru         skcf->socket = rtsk;
816115Sigor@sysoev.ru 
817115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
818115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
819115Sigor@sysoev.ru             return NXT_ERROR;
820115Sigor@sysoev.ru         }
821115Sigor@sysoev.ru 
822115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
823115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
824115Sigor@sysoev.ru             return NXT_ERROR;
825115Sigor@sysoev.ru         }
826115Sigor@sysoev.ru 
827115Sigor@sysoev.ru         skcf->listen.socket = s;
828115Sigor@sysoev.ru 
829115Sigor@sysoev.ru         rtsk->fd = s;
830115Sigor@sysoev.ru 
83153Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
83253Sigor@sysoev.ru         nxt_queue_remove(qlk);
83353Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
83453Sigor@sysoev.ru     }
83553Sigor@sysoev.ru 
83653Sigor@sysoev.ru     return NXT_OK;
83753Sigor@sysoev.ru }
83853Sigor@sysoev.ru 
83953Sigor@sysoev.ru 
84053Sigor@sysoev.ru static nxt_int_t
84153Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
84253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
84353Sigor@sysoev.ru {
84453Sigor@sysoev.ru     nxt_int_t                 ret;
84553Sigor@sysoev.ru     nxt_uint_t                n, threads;
84653Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
84753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
84853Sigor@sysoev.ru 
84953Sigor@sysoev.ru     threads = tmcf->conf->threads;
85053Sigor@sysoev.ru 
85153Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
85253Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
85353Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
85453Sigor@sysoev.ru         return NXT_ERROR;
85553Sigor@sysoev.ru     }
85653Sigor@sysoev.ru 
85753Sigor@sysoev.ru     n = 0;
85853Sigor@sysoev.ru 
85953Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
86053Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
86153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
86253Sigor@sysoev.ru     {
86353Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
86453Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
86553Sigor@sysoev.ru             return NXT_ERROR;
86653Sigor@sysoev.ru         }
86753Sigor@sysoev.ru 
868115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
86953Sigor@sysoev.ru 
87053Sigor@sysoev.ru         if (n < threads) {
871115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
87253Sigor@sysoev.ru 
87353Sigor@sysoev.ru         } else {
874115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
87553Sigor@sysoev.ru         }
87653Sigor@sysoev.ru 
87753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
87853Sigor@sysoev.ru             return ret;
87953Sigor@sysoev.ru         }
88053Sigor@sysoev.ru 
88153Sigor@sysoev.ru         n++;
88253Sigor@sysoev.ru     }
88353Sigor@sysoev.ru 
88453Sigor@sysoev.ru     tmcf->new_threads = n;
88553Sigor@sysoev.ru 
88653Sigor@sysoev.ru     while (n < threads) {
88753Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
88853Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
88953Sigor@sysoev.ru             return NXT_ERROR;
89053Sigor@sysoev.ru         }
89153Sigor@sysoev.ru 
89253Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
89353Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
89453Sigor@sysoev.ru             return NXT_ERROR;
89553Sigor@sysoev.ru         }
89653Sigor@sysoev.ru 
897115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
89853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
89953Sigor@sysoev.ru             return ret;
90053Sigor@sysoev.ru         }
90153Sigor@sysoev.ru 
902115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
903115Sigor@sysoev.ru 
90453Sigor@sysoev.ru         n++;
90553Sigor@sysoev.ru     }
90653Sigor@sysoev.ru 
90753Sigor@sysoev.ru     return NXT_OK;
90853Sigor@sysoev.ru }
90953Sigor@sysoev.ru 
91053Sigor@sysoev.ru 
91153Sigor@sysoev.ru static nxt_int_t
912115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
913115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
91453Sigor@sysoev.ru {
915115Sigor@sysoev.ru     nxt_mp_t               *mp;
916115Sigor@sysoev.ru     nxt_int_t              ret;
917115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
91853Sigor@sysoev.ru 
91953Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
92053Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
92153Sigor@sysoev.ru         return NXT_ERROR;
92253Sigor@sysoev.ru     }
92353Sigor@sysoev.ru 
924115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
925115Sigor@sysoev.ru 
926139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
927115Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
928115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
929115Sigor@sysoev.ru         return ret;
930115Sigor@sysoev.ru     }
931115Sigor@sysoev.ru 
932139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
93353Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
93453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
93553Sigor@sysoev.ru         return ret;
93653Sigor@sysoev.ru     }
93753Sigor@sysoev.ru 
938115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
939115Sigor@sysoev.ru 
940115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
941115Sigor@sysoev.ru 
942115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
943115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
944115Sigor@sysoev.ru 
945115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
946115Sigor@sysoev.ru 
947115Sigor@sysoev.ru     return ret;
94853Sigor@sysoev.ru }
94953Sigor@sysoev.ru 
95053Sigor@sysoev.ru 
95153Sigor@sysoev.ru static nxt_int_t
952115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
953115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
95453Sigor@sysoev.ru {
955115Sigor@sysoev.ru     nxt_mp_t               *mp;
956115Sigor@sysoev.ru     nxt_int_t              ret;
957115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
95853Sigor@sysoev.ru 
95953Sigor@sysoev.ru     recf->creating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
96053Sigor@sysoev.ru     if (nxt_slow_path(recf->creating == NULL)) {
96153Sigor@sysoev.ru         return NXT_ERROR;
96253Sigor@sysoev.ru     }
96353Sigor@sysoev.ru 
964115Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
965115Sigor@sysoev.ru 
966139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->creating,
96753Sigor@sysoev.ru                             recf->creating, nxt_router_listen_socket_create);
96853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
96953Sigor@sysoev.ru         return ret;
97053Sigor@sysoev.ru     }
97153Sigor@sysoev.ru 
97253Sigor@sysoev.ru     recf->updating = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
97353Sigor@sysoev.ru     if (nxt_slow_path(recf->updating == NULL)) {
97453Sigor@sysoev.ru         return NXT_ERROR;
97553Sigor@sysoev.ru     }
97653Sigor@sysoev.ru 
977139Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(mp, tmcf, recf, &tmcf->updating,
97853Sigor@sysoev.ru                             recf->updating, nxt_router_listen_socket_update);
97953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
98053Sigor@sysoev.ru         return ret;
98153Sigor@sysoev.ru     }
98253Sigor@sysoev.ru 
98353Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
98453Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
98553Sigor@sysoev.ru         return NXT_ERROR;
98653Sigor@sysoev.ru     }
98753Sigor@sysoev.ru 
988139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
989115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
990115Sigor@sysoev.ru         return ret;
991115Sigor@sysoev.ru     }
992115Sigor@sysoev.ru 
993115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
994115Sigor@sysoev.ru 
995115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
996115Sigor@sysoev.ru 
997115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
998115Sigor@sysoev.ru 
999115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1000115Sigor@sysoev.ru 
1001115Sigor@sysoev.ru     return ret;
100253Sigor@sysoev.ru }
100353Sigor@sysoev.ru 
100453Sigor@sysoev.ru 
100553Sigor@sysoev.ru static nxt_int_t
1006115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1007115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
100853Sigor@sysoev.ru {
100953Sigor@sysoev.ru     nxt_int_t  ret;
101053Sigor@sysoev.ru 
101153Sigor@sysoev.ru     recf->deleting = nxt_array_create(tmcf->mem_pool, 4, sizeof(nxt_work_t));
101253Sigor@sysoev.ru     if (nxt_slow_path(recf->deleting == NULL)) {
101353Sigor@sysoev.ru         return NXT_ERROR;
101453Sigor@sysoev.ru     }
101553Sigor@sysoev.ru 
1016139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
101753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
101853Sigor@sysoev.ru         return ret;
101953Sigor@sysoev.ru     }
102053Sigor@sysoev.ru 
1021139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
102253Sigor@sysoev.ru }
102353Sigor@sysoev.ru 
102453Sigor@sysoev.ru 
102553Sigor@sysoev.ru static nxt_int_t
1026139Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_mp_t *mp, nxt_router_temp_conf_t *tmcf,
1027139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, nxt_array_t *array,
102853Sigor@sysoev.ru     nxt_work_handler_t handler)
102953Sigor@sysoev.ru {
1030139Sigor@sysoev.ru     nxt_work_t               *work, *back;
103153Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
103253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
103353Sigor@sysoev.ru 
103453Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
103553Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
103653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
103753Sigor@sysoev.ru     {
1038139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
1039139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
1040139Sigor@sysoev.ru             return NXT_ERROR;
1041139Sigor@sysoev.ru         }
1042139Sigor@sysoev.ru 
1043139Sigor@sysoev.ru         back->next = NULL;
1044139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
1045139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
1046139Sigor@sysoev.ru         back->obj = tmcf;
1047139Sigor@sysoev.ru         back->data = NULL;
1048139Sigor@sysoev.ru 
104953Sigor@sysoev.ru         work = nxt_array_add(array);
105053Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
105153Sigor@sysoev.ru             return NXT_ERROR;
105253Sigor@sysoev.ru         }
105353Sigor@sysoev.ru 
105453Sigor@sysoev.ru         work->next = NULL;
105553Sigor@sysoev.ru         work->handler = handler;
1056139Sigor@sysoev.ru         work->task = &recf->engine->task;
1057139Sigor@sysoev.ru         work->obj = back;
105853Sigor@sysoev.ru 
105965Sigor@sysoev.ru         joint = nxt_mp_alloc(mp, sizeof(nxt_socket_conf_joint_t));
106053Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
106153Sigor@sysoev.ru             return NXT_ERROR;
106253Sigor@sysoev.ru         }
106353Sigor@sysoev.ru 
106453Sigor@sysoev.ru         work->data = joint;
106553Sigor@sysoev.ru 
106653Sigor@sysoev.ru         joint->count = 1;
106753Sigor@sysoev.ru         joint->socket_conf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
106888Smax.romanov@nginx.com         joint->engine = recf->engine;
1069115Sigor@sysoev.ru 
1070115Sigor@sysoev.ru         nxt_queue_insert_tail(&joint->engine->joints, &joint->link);
107153Sigor@sysoev.ru     }
107253Sigor@sysoev.ru 
107320Sigor@sysoev.ru     return NXT_OK;
107420Sigor@sysoev.ru }
107520Sigor@sysoev.ru 
107620Sigor@sysoev.ru 
1077115Sigor@sysoev.ru static void
1078115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1079115Sigor@sysoev.ru {
1080115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1081115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1082115Sigor@sysoev.ru 
1083115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1084115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1085115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1086115Sigor@sysoev.ru     {
1087115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1088115Sigor@sysoev.ru         skcf->socket->count++;
1089115Sigor@sysoev.ru     }
1090115Sigor@sysoev.ru }
1091115Sigor@sysoev.ru 
1092115Sigor@sysoev.ru 
109320Sigor@sysoev.ru static nxt_int_t
1094139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1095139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
109620Sigor@sysoev.ru {
1097139Sigor@sysoev.ru     nxt_work_t        *work, *back;
109853Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
109920Sigor@sysoev.ru 
110053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
110153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
110253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
110353Sigor@sysoev.ru     {
1104139Sigor@sysoev.ru         back = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_work_t));
1105139Sigor@sysoev.ru         if (nxt_slow_path(back == NULL)) {
1106139Sigor@sysoev.ru             return NXT_ERROR;
1107139Sigor@sysoev.ru         }
1108139Sigor@sysoev.ru 
1109139Sigor@sysoev.ru         back->next = NULL;
1110139Sigor@sysoev.ru         back->handler = nxt_router_conf_wait;
1111139Sigor@sysoev.ru         back->task = &tmcf->engine->task;
1112139Sigor@sysoev.ru         back->obj = tmcf;
1113139Sigor@sysoev.ru         back->data = NULL;
1114139Sigor@sysoev.ru 
1115115Sigor@sysoev.ru         work = nxt_array_add(recf->deleting);
111653Sigor@sysoev.ru         if (nxt_slow_path(work == NULL)) {
111753Sigor@sysoev.ru             return NXT_ERROR;
111853Sigor@sysoev.ru         }
111920Sigor@sysoev.ru 
112053Sigor@sysoev.ru         work->next = NULL;
112153Sigor@sysoev.ru         work->handler = nxt_router_listen_socket_delete;
1122139Sigor@sysoev.ru         work->task = &recf->engine->task;
1123139Sigor@sysoev.ru         work->obj = back;
112453Sigor@sysoev.ru         work->data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
112520Sigor@sysoev.ru     }
112620Sigor@sysoev.ru 
112753Sigor@sysoev.ru     return NXT_OK;
112853Sigor@sysoev.ru }
112920Sigor@sysoev.ru 
113020Sigor@sysoev.ru 
113153Sigor@sysoev.ru static nxt_int_t
113253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
113353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
113453Sigor@sysoev.ru {
113553Sigor@sysoev.ru     nxt_int_t                 ret;
113653Sigor@sysoev.ru     nxt_uint_t                i, threads;
113753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
113820Sigor@sysoev.ru 
113953Sigor@sysoev.ru     recf = tmcf->engines->elts;
114053Sigor@sysoev.ru     threads = tmcf->conf->threads;
114120Sigor@sysoev.ru 
114253Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
114353Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
114453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
114553Sigor@sysoev.ru             return ret;
114653Sigor@sysoev.ru         }
114720Sigor@sysoev.ru     }
114820Sigor@sysoev.ru 
114920Sigor@sysoev.ru     return NXT_OK;
115020Sigor@sysoev.ru }
115153Sigor@sysoev.ru 
115253Sigor@sysoev.ru 
115353Sigor@sysoev.ru static nxt_int_t
115453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
115553Sigor@sysoev.ru     nxt_event_engine_t *engine)
115653Sigor@sysoev.ru {
115753Sigor@sysoev.ru     nxt_int_t            ret;
115853Sigor@sysoev.ru     nxt_thread_link_t    *link;
115953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
116053Sigor@sysoev.ru 
116153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
116253Sigor@sysoev.ru 
116353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
116453Sigor@sysoev.ru         return NXT_ERROR;
116553Sigor@sysoev.ru     }
116653Sigor@sysoev.ru 
116753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
116853Sigor@sysoev.ru     link->engine = engine;
116953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
117053Sigor@sysoev.ru     link->work.task = task;
117153Sigor@sysoev.ru     link->work.data = link;
117253Sigor@sysoev.ru 
117353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
117453Sigor@sysoev.ru 
117553Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
117653Sigor@sysoev.ru 
117753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
117853Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
117953Sigor@sysoev.ru     }
118053Sigor@sysoev.ru 
118153Sigor@sysoev.ru     return ret;
118253Sigor@sysoev.ru }
118353Sigor@sysoev.ru 
118453Sigor@sysoev.ru 
118553Sigor@sysoev.ru static void
1186133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1187133Sigor@sysoev.ru {
1188*141Smax.romanov@nginx.com     nxt_app_t  *app;
1189*141Smax.romanov@nginx.com 
1190*141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1191133Sigor@sysoev.ru 
1192133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1193133Sigor@sysoev.ru 
1194*141Smax.romanov@nginx.com         // TODO RELEASE APP
1195*141Smax.romanov@nginx.com     } nxt_queue_loop;
1196133Sigor@sysoev.ru 
1197133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1198133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1199133Sigor@sysoev.ru }
1200133Sigor@sysoev.ru 
1201133Sigor@sysoev.ru 
1202133Sigor@sysoev.ru static void
120353Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
120453Sigor@sysoev.ru {
120553Sigor@sysoev.ru     nxt_uint_t                n;
120653Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
120753Sigor@sysoev.ru 
120853Sigor@sysoev.ru     recf = tmcf->engines->elts;
120953Sigor@sysoev.ru 
121053Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1211139Sigor@sysoev.ru         nxt_router_engine_post(tmcf, recf);
121253Sigor@sysoev.ru         recf++;
121353Sigor@sysoev.ru     }
121453Sigor@sysoev.ru }
121553Sigor@sysoev.ru 
121653Sigor@sysoev.ru 
121753Sigor@sysoev.ru static void
1218139Sigor@sysoev.ru nxt_router_engine_post(nxt_router_temp_conf_t *tmcf,
1219139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
122053Sigor@sysoev.ru {
122153Sigor@sysoev.ru     nxt_uint_t  n;
122253Sigor@sysoev.ru     nxt_work_t  *work;
122353Sigor@sysoev.ru 
1224115Sigor@sysoev.ru     if (recf->creating != NULL) {
1225115Sigor@sysoev.ru         work = recf->creating->elts;
1226115Sigor@sysoev.ru 
1227115Sigor@sysoev.ru         for (n = recf->creating->nelts; n != 0; n--) {
1228115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1229115Sigor@sysoev.ru             work++;
1230139Sigor@sysoev.ru             tmcf->count++;
1231115Sigor@sysoev.ru         }
1232115Sigor@sysoev.ru     }
1233115Sigor@sysoev.ru 
1234115Sigor@sysoev.ru     if (recf->updating != NULL) {
1235115Sigor@sysoev.ru         work = recf->updating->elts;
123653Sigor@sysoev.ru 
1237115Sigor@sysoev.ru         for (n = recf->updating->nelts; n != 0; n--) {
1238115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1239115Sigor@sysoev.ru             work++;
1240139Sigor@sysoev.ru             tmcf->count++;
1241115Sigor@sysoev.ru         }
1242115Sigor@sysoev.ru     }
1243115Sigor@sysoev.ru 
1244115Sigor@sysoev.ru     if (recf->deleting != NULL) {
1245115Sigor@sysoev.ru         work = recf->deleting->elts;
1246115Sigor@sysoev.ru 
1247115Sigor@sysoev.ru         for (n = recf->deleting->nelts; n != 0; n--) {
1248115Sigor@sysoev.ru             nxt_event_engine_post(recf->engine, work);
1249115Sigor@sysoev.ru             work++;
1250139Sigor@sysoev.ru             tmcf->count++;
1251115Sigor@sysoev.ru         }
125253Sigor@sysoev.ru     }
125353Sigor@sysoev.ru }
125453Sigor@sysoev.ru 
125553Sigor@sysoev.ru 
125653Sigor@sysoev.ru static void
1257119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
125888Smax.romanov@nginx.com 
1259119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
126088Smax.romanov@nginx.com     NULL,
126188Smax.romanov@nginx.com     nxt_port_new_port_handler,
126288Smax.romanov@nginx.com     nxt_port_change_log_file_handler,
126388Smax.romanov@nginx.com     nxt_port_mmap_handler,
1264119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1265125Smax.romanov@nginx.com     nxt_port_remove_pid_handler,
126688Smax.romanov@nginx.com };
126788Smax.romanov@nginx.com 
126888Smax.romanov@nginx.com 
126988Smax.romanov@nginx.com static void
127053Sigor@sysoev.ru nxt_router_thread_start(void *data)
127153Sigor@sysoev.ru {
1272*141Smax.romanov@nginx.com     nxt_int_t           ret;
1273*141Smax.romanov@nginx.com     nxt_port_t          *port;
127488Smax.romanov@nginx.com     nxt_task_t          *task;
127553Sigor@sysoev.ru     nxt_thread_t        *thread;
127653Sigor@sysoev.ru     nxt_thread_link_t   *link;
127753Sigor@sysoev.ru     nxt_event_engine_t  *engine;
127853Sigor@sysoev.ru 
127953Sigor@sysoev.ru     link = data;
128053Sigor@sysoev.ru     engine = link->engine;
128188Smax.romanov@nginx.com     task = &engine->task;
128253Sigor@sysoev.ru 
128353Sigor@sysoev.ru     thread = nxt_thread();
128453Sigor@sysoev.ru 
128553Sigor@sysoev.ru     /* STUB */
128653Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
128753Sigor@sysoev.ru 
128853Sigor@sysoev.ru     engine->task.thread = thread;
128953Sigor@sysoev.ru     engine->task.log = thread->log;
129053Sigor@sysoev.ru     thread->engine = engine;
129163Sigor@sysoev.ru     thread->task = &engine->task;
129253Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
129353Sigor@sysoev.ru 
129463Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
129553Sigor@sysoev.ru 
1296*141Smax.romanov@nginx.com     port = nxt_mp_zalloc(engine->mem_pool, sizeof(nxt_port_t));
1297*141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1298*141Smax.romanov@nginx.com         return;
1299*141Smax.romanov@nginx.com     }
1300*141Smax.romanov@nginx.com 
1301*141Smax.romanov@nginx.com     port->id = nxt_port_get_next_id();
1302*141Smax.romanov@nginx.com     port->pid = nxt_pid;
1303*141Smax.romanov@nginx.com 
1304*141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1305*141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1306*141Smax.romanov@nginx.com         return;
1307*141Smax.romanov@nginx.com     }
1308*141Smax.romanov@nginx.com 
1309*141Smax.romanov@nginx.com     port->type = NXT_PROCESS_ROUTER;
1310*141Smax.romanov@nginx.com 
1311*141Smax.romanov@nginx.com     engine->port = port;
1312*141Smax.romanov@nginx.com 
1313*141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1314*141Smax.romanov@nginx.com 
131553Sigor@sysoev.ru     nxt_event_engine_start(engine);
131653Sigor@sysoev.ru }
131753Sigor@sysoev.ru 
131853Sigor@sysoev.ru 
131953Sigor@sysoev.ru static void
132053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
132153Sigor@sysoev.ru {
1322139Sigor@sysoev.ru     nxt_work_t               *work;
132353Sigor@sysoev.ru     nxt_listen_event_t       *listen;
132453Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
1325139Sigor@sysoev.ru     nxt_router_temp_conf_t   *tmcf;
132653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
132753Sigor@sysoev.ru 
1328139Sigor@sysoev.ru     work = obj;
132953Sigor@sysoev.ru     joint = data;
133053Sigor@sysoev.ru 
133153Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
133253Sigor@sysoev.ru 
133353Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
133453Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
133553Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
133653Sigor@sysoev.ru         return;
133753Sigor@sysoev.ru     }
133853Sigor@sysoev.ru 
133953Sigor@sysoev.ru     listen->socket.data = joint;
1340139Sigor@sysoev.ru 
1341139Sigor@sysoev.ru     tmcf = work->obj;
1342139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
134353Sigor@sysoev.ru }
134453Sigor@sysoev.ru 
134553Sigor@sysoev.ru 
134653Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
134753Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
134853Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
134953Sigor@sysoev.ru {
1350115Sigor@sysoev.ru     nxt_socket_t        fd;
1351115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
135253Sigor@sysoev.ru     nxt_listen_event_t  *listen;
135353Sigor@sysoev.ru 
1354115Sigor@sysoev.ru     fd = skcf->socket->fd;
135553Sigor@sysoev.ru 
1356115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1357115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1358115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
135953Sigor@sysoev.ru     {
1360115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
136153Sigor@sysoev.ru 
1362115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
136353Sigor@sysoev.ru             return listen;
136453Sigor@sysoev.ru         }
136553Sigor@sysoev.ru     }
136653Sigor@sysoev.ru 
136753Sigor@sysoev.ru     return NULL;
136853Sigor@sysoev.ru }
136953Sigor@sysoev.ru 
137053Sigor@sysoev.ru 
137153Sigor@sysoev.ru static void
137253Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
137353Sigor@sysoev.ru {
1374139Sigor@sysoev.ru     nxt_work_t               *work;
137553Sigor@sysoev.ru     nxt_event_engine_t       *engine;
137653Sigor@sysoev.ru     nxt_listen_event_t       *listen;
1377139Sigor@sysoev.ru     nxt_router_temp_conf_t   *tmcf;
137853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
137953Sigor@sysoev.ru 
1380139Sigor@sysoev.ru     work = obj;
138153Sigor@sysoev.ru     joint = data;
138253Sigor@sysoev.ru 
1383139Sigor@sysoev.ru     engine = task->thread->engine;
1384139Sigor@sysoev.ru 
138553Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
138653Sigor@sysoev.ru                                      joint->socket_conf);
138753Sigor@sysoev.ru 
138853Sigor@sysoev.ru     old = listen->socket.data;
138953Sigor@sysoev.ru     listen->socket.data = joint;
139053Sigor@sysoev.ru 
1391139Sigor@sysoev.ru     tmcf = work->obj;
1392139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
1393139Sigor@sysoev.ru 
139453Sigor@sysoev.ru     nxt_router_conf_release(task, old);
139553Sigor@sysoev.ru }
139653Sigor@sysoev.ru 
139753Sigor@sysoev.ru 
139853Sigor@sysoev.ru static void
139953Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
140053Sigor@sysoev.ru {
1401139Sigor@sysoev.ru     nxt_work_t              *work;
1402139Sigor@sysoev.ru     nxt_socket_conf_t       *skcf;
1403139Sigor@sysoev.ru     nxt_listen_event_t      *listen;
1404139Sigor@sysoev.ru     nxt_event_engine_t      *engine;
1405139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1406139Sigor@sysoev.ru 
1407139Sigor@sysoev.ru     work = obj;
140853Sigor@sysoev.ru     skcf = data;
140953Sigor@sysoev.ru 
1410139Sigor@sysoev.ru     engine = task->thread->engine;
1411139Sigor@sysoev.ru 
141253Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
141353Sigor@sysoev.ru 
141453Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
141553Sigor@sysoev.ru 
141653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
141753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
141853Sigor@sysoev.ru 
141953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1420139Sigor@sysoev.ru 
1421139Sigor@sysoev.ru     tmcf = work->obj;
1422139Sigor@sysoev.ru     nxt_event_engine_post(tmcf->engine, work);
142353Sigor@sysoev.ru }
142453Sigor@sysoev.ru 
142553Sigor@sysoev.ru 
142653Sigor@sysoev.ru static void
142753Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
142853Sigor@sysoev.ru {
142953Sigor@sysoev.ru     nxt_timer_t              *timer;
143053Sigor@sysoev.ru     nxt_listen_event_t       *listen;
143153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
143253Sigor@sysoev.ru 
143353Sigor@sysoev.ru     timer = obj;
143453Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
143553Sigor@sysoev.ru     joint = listen->socket.data;
143653Sigor@sysoev.ru 
143753Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1438123Smax.romanov@nginx.com 
1439123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1440123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1441123Smax.romanov@nginx.com 
144253Sigor@sysoev.ru     nxt_free(listen);
144353Sigor@sysoev.ru 
144453Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
144553Sigor@sysoev.ru }
144653Sigor@sysoev.ru 
144753Sigor@sysoev.ru 
144853Sigor@sysoev.ru static void
144953Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
145053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
145153Sigor@sysoev.ru {
1452118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1453115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
145453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
145553Sigor@sysoev.ru 
1456118Sigor@sysoev.ru     skcf = joint->socket_conf;
1457118Sigor@sysoev.ru     rtsk = skcf->socket;
1458118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
145953Sigor@sysoev.ru 
146053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
146153Sigor@sysoev.ru 
1462115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1463115Sigor@sysoev.ru         rtsk = NULL;
146453Sigor@sysoev.ru     }
146553Sigor@sysoev.ru 
146653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
146753Sigor@sysoev.ru 
1468115Sigor@sysoev.ru     if (rtsk != NULL) {
1469115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1470115Sigor@sysoev.ru         nxt_free(rtsk);
1471118Sigor@sysoev.ru         skcf->socket = NULL;
147253Sigor@sysoev.ru     }
147353Sigor@sysoev.ru 
147453Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
147553Sigor@sysoev.ru }
147653Sigor@sysoev.ru 
147753Sigor@sysoev.ru 
147853Sigor@sysoev.ru static void
147953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
148053Sigor@sysoev.ru {
148153Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
148253Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
148353Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
148453Sigor@sysoev.ru 
148553Sigor@sysoev.ru     nxt_debug(task, "conf joint count: %D", joint->count);
148653Sigor@sysoev.ru 
148753Sigor@sysoev.ru     if (--joint->count != 0) {
148853Sigor@sysoev.ru         return;
148953Sigor@sysoev.ru     }
149053Sigor@sysoev.ru 
149153Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
149253Sigor@sysoev.ru 
149353Sigor@sysoev.ru     skcf = joint->socket_conf;
149453Sigor@sysoev.ru     rtcf = skcf->router_conf;
149553Sigor@sysoev.ru     lock = &rtcf->router->lock;
149653Sigor@sysoev.ru 
149753Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
149853Sigor@sysoev.ru 
149953Sigor@sysoev.ru     if (--skcf->count != 0) {
150053Sigor@sysoev.ru         rtcf = NULL;
150153Sigor@sysoev.ru 
150253Sigor@sysoev.ru     } else {
150353Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
150453Sigor@sysoev.ru 
150553Sigor@sysoev.ru         if (--rtcf->count != 0) {
150653Sigor@sysoev.ru             rtcf = NULL;
150753Sigor@sysoev.ru         }
150853Sigor@sysoev.ru     }
150953Sigor@sysoev.ru 
151053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
151153Sigor@sysoev.ru 
1512*141Smax.romanov@nginx.com     /* TODO remove engine->port */
1513*141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1514*141Smax.romanov@nginx.com 
151553Sigor@sysoev.ru     if (rtcf != NULL) {
1516115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1517131Smax.romanov@nginx.com 
1518131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1519131Smax.romanov@nginx.com 
152065Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
152153Sigor@sysoev.ru     }
152253Sigor@sysoev.ru 
152353Sigor@sysoev.ru     if (nxt_queue_is_empty(&joint->engine->joints)) {
152453Sigor@sysoev.ru         nxt_thread_exit(task->thread);
152553Sigor@sysoev.ru     }
152653Sigor@sysoev.ru }
152753Sigor@sysoev.ru 
152853Sigor@sysoev.ru 
152953Sigor@sysoev.ru static void
153053Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
153153Sigor@sysoev.ru {
1532*141Smax.romanov@nginx.com     nxt_port_t           *port;
153353Sigor@sysoev.ru     nxt_thread_link_t    *link;
153453Sigor@sysoev.ru     nxt_event_engine_t   *engine;
153553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
153653Sigor@sysoev.ru 
153758Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
153853Sigor@sysoev.ru     link = data;
153953Sigor@sysoev.ru 
154053Sigor@sysoev.ru     nxt_thread_wait(handle);
154153Sigor@sysoev.ru 
154253Sigor@sysoev.ru     engine = link->engine;
154353Sigor@sysoev.ru 
154453Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
154553Sigor@sysoev.ru 
1546*141Smax.romanov@nginx.com     port = engine->port;
1547*141Smax.romanov@nginx.com 
1548*141Smax.romanov@nginx.com     // TODO notify all apps
1549*141Smax.romanov@nginx.com 
1550*141Smax.romanov@nginx.com     if (port->pair[0] != -1) {
1551*141Smax.romanov@nginx.com         nxt_fd_close(port->pair[0]);
1552*141Smax.romanov@nginx.com     }
1553*141Smax.romanov@nginx.com 
1554*141Smax.romanov@nginx.com     if (port->pair[1] != -1) {
1555*141Smax.romanov@nginx.com         nxt_fd_close(port->pair[1]);
1556*141Smax.romanov@nginx.com     }
1557*141Smax.romanov@nginx.com 
1558*141Smax.romanov@nginx.com     if (port->mem_pool) {
1559*141Smax.romanov@nginx.com         nxt_mp_destroy(port->mem_pool);
1560*141Smax.romanov@nginx.com     }
1561*141Smax.romanov@nginx.com 
156263Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
156353Sigor@sysoev.ru 
156453Sigor@sysoev.ru     nxt_event_engine_free(engine);
156553Sigor@sysoev.ru 
156653Sigor@sysoev.ru     nxt_free(link);
156753Sigor@sysoev.ru }
156853Sigor@sysoev.ru 
156953Sigor@sysoev.ru 
157062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_read_state
157153Sigor@sysoev.ru     nxt_aligned(64) =
157253Sigor@sysoev.ru {
157353Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
157453Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
157553Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
157653Sigor@sysoev.ru 
157753Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
157853Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
157953Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
158053Sigor@sysoev.ru };
158153Sigor@sysoev.ru 
158253Sigor@sysoev.ru 
158353Sigor@sysoev.ru static void
158453Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
158553Sigor@sysoev.ru {
158653Sigor@sysoev.ru     size_t                   size;
158762Sigor@sysoev.ru     nxt_conn_t               *c;
158853Sigor@sysoev.ru     nxt_event_engine_t       *engine;
158953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
159053Sigor@sysoev.ru 
159153Sigor@sysoev.ru     c = obj;
159253Sigor@sysoev.ru     joint = data;
159353Sigor@sysoev.ru 
159453Sigor@sysoev.ru     nxt_debug(task, "router conn init");
159553Sigor@sysoev.ru 
159653Sigor@sysoev.ru     joint->count++;
159753Sigor@sysoev.ru 
159853Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
159953Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
160053Sigor@sysoev.ru 
160153Sigor@sysoev.ru     c->socket.data = NULL;
160253Sigor@sysoev.ru 
160353Sigor@sysoev.ru     engine = task->thread->engine;
160453Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
160553Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
160653Sigor@sysoev.ru 
160753Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
160853Sigor@sysoev.ru 
160962Sigor@sysoev.ru     nxt_conn_read(engine, c);
161053Sigor@sysoev.ru }
161153Sigor@sysoev.ru 
161253Sigor@sysoev.ru 
161362Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
161453Sigor@sysoev.ru     nxt_aligned(64) =
161553Sigor@sysoev.ru {
161688Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
161753Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
161853Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
161953Sigor@sysoev.ru };
162053Sigor@sysoev.ru 
162153Sigor@sysoev.ru 
162253Sigor@sysoev.ru static void
1623119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
162488Smax.romanov@nginx.com {
162588Smax.romanov@nginx.com     size_t               dump_size;
162688Smax.romanov@nginx.com     nxt_buf_t            *b, *i, *last;
162788Smax.romanov@nginx.com     nxt_conn_t           *c;
162888Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
162988Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
163088Smax.romanov@nginx.com 
163188Smax.romanov@nginx.com     b = msg->buf;
163288Smax.romanov@nginx.com     engine = task->thread->engine;
163388Smax.romanov@nginx.com 
163488Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
163588Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
163688Smax.romanov@nginx.com 
163788Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
163888Smax.romanov@nginx.com 
163995Smax.romanov@nginx.com         /* Mark buffers as read. */
164088Smax.romanov@nginx.com         for (i = b; i != NULL; i = i->next) {
164188Smax.romanov@nginx.com             i->mem.pos = i->mem.free;
164288Smax.romanov@nginx.com         }
164388Smax.romanov@nginx.com 
164488Smax.romanov@nginx.com         return;
164588Smax.romanov@nginx.com     }
164688Smax.romanov@nginx.com 
164788Smax.romanov@nginx.com     c = rc->conn;
164888Smax.romanov@nginx.com 
164988Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
165088Smax.romanov@nginx.com 
165188Smax.romanov@nginx.com     if (dump_size > 300) {
165288Smax.romanov@nginx.com         dump_size = 300;
165388Smax.romanov@nginx.com     }
165488Smax.romanov@nginx.com 
1655119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
165688Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
165788Smax.romanov@nginx.com               b->mem.pos);
165888Smax.romanov@nginx.com 
165988Smax.romanov@nginx.com     if (msg->size == 0) {
166088Smax.romanov@nginx.com         b = NULL;
166188Smax.romanov@nginx.com     }
166288Smax.romanov@nginx.com 
166388Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
166488Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
166588Smax.romanov@nginx.com 
166688Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
166788Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
166888Smax.romanov@nginx.com             /* TODO pogorevaTb */
166988Smax.romanov@nginx.com         }
167088Smax.romanov@nginx.com 
167188Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
167288Smax.romanov@nginx.com     }
167388Smax.romanov@nginx.com 
167488Smax.romanov@nginx.com     if (b == NULL) {
167588Smax.romanov@nginx.com         return;
167688Smax.romanov@nginx.com     }
167788Smax.romanov@nginx.com 
167888Smax.romanov@nginx.com     if (c->write == NULL) {
167988Smax.romanov@nginx.com         c->write = b;
168088Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
168188Smax.romanov@nginx.com 
168288Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
168388Smax.romanov@nginx.com     } else {
168488Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
168588Smax.romanov@nginx.com 
168688Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
168788Smax.romanov@nginx.com     }
168888Smax.romanov@nginx.com }
168988Smax.romanov@nginx.com 
1690*141Smax.romanov@nginx.com nxt_inline const char *
1691*141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
1692*141Smax.romanov@nginx.com {
1693*141Smax.romanov@nginx.com     switch (code) {
1694*141Smax.romanov@nginx.com     case 400: return "Bad request";
1695*141Smax.romanov@nginx.com     case 404: return "Not found";
1696*141Smax.romanov@nginx.com     case 403: return "Forbidden";
1697*141Smax.romanov@nginx.com     case 500:
1698*141Smax.romanov@nginx.com     default:  return "Internal server error";
1699*141Smax.romanov@nginx.com     }
1700*141Smax.romanov@nginx.com }
1701*141Smax.romanov@nginx.com 
1702*141Smax.romanov@nginx.com static void
1703*141Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
1704*141Smax.romanov@nginx.com     const char* fmt, ...)
170588Smax.romanov@nginx.com {
1706*141Smax.romanov@nginx.com     va_list             args;
1707*141Smax.romanov@nginx.com     nxt_buf_t           *b, *last;
1708*141Smax.romanov@nginx.com     const char          *msg;
1709*141Smax.romanov@nginx.com 
1710*141Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(c->mem_pool, 16384, 0);
1711*141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1712*141Smax.romanov@nginx.com         /* TODO pogorevaTb */
1713*141Smax.romanov@nginx.com     }
1714*141Smax.romanov@nginx.com 
1715*141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
1716*141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
1717*141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
1718*141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
1719*141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
1720*141Smax.romanov@nginx.com 
1721*141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
1722*141Smax.romanov@nginx.com 
1723*141Smax.romanov@nginx.com     va_start(args, fmt);
1724*141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
1725*141Smax.romanov@nginx.com     va_end(args);
1726*141Smax.romanov@nginx.com 
1727*141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
1728*141Smax.romanov@nginx.com 
1729*141Smax.romanov@nginx.com     last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
1730*141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
1731*141Smax.romanov@nginx.com         /* TODO pogorevaTb */
1732*141Smax.romanov@nginx.com     }
1733*141Smax.romanov@nginx.com 
1734*141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
1735*141Smax.romanov@nginx.com 
1736*141Smax.romanov@nginx.com     if (c->write == NULL) {
1737*141Smax.romanov@nginx.com         c->write = b;
1738*141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
1739*141Smax.romanov@nginx.com 
1740*141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
1741*141Smax.romanov@nginx.com     } else {
1742*141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
1743*141Smax.romanov@nginx.com 
1744*141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
1745*141Smax.romanov@nginx.com     }
1746*141Smax.romanov@nginx.com }
1747*141Smax.romanov@nginx.com 
1748*141Smax.romanov@nginx.com 
1749*141Smax.romanov@nginx.com static void
1750*141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
1751*141Smax.romanov@nginx.com {
1752*141Smax.romanov@nginx.com     nxt_buf_t           *b;
1753*141Smax.romanov@nginx.com     nxt_app_t           *app;
1754*141Smax.romanov@nginx.com     nxt_port_t          *port;
1755*141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
1756*141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1757*141Smax.romanov@nginx.com 
1758*141Smax.romanov@nginx.com     sw = obj;
1759*141Smax.romanov@nginx.com     app = sw->app;
1760*141Smax.romanov@nginx.com 
1761*141Smax.romanov@nginx.com     nxt_debug(task, "send sw #%uD", sw->stream);
1762*141Smax.romanov@nginx.com 
1763*141Smax.romanov@nginx.com     nxt_router_sw_add(task, nxt_router, sw);
1764*141Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->rc->app_link);
176588Smax.romanov@nginx.com 
1766119Smax.romanov@nginx.com     rt = task->thread->runtime;
1767*141Smax.romanov@nginx.com     port = rt->port_by_type[NXT_PROCESS_MASTER];
1768*141Smax.romanov@nginx.com 
1769*141Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(port->mem_pool, app->conf.length, 0);
1770*141Smax.romanov@nginx.com 
1771*141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1772*141Smax.romanov@nginx.com 
1773*141Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_DATA, -1, sw->stream, 0, b);
1774*141Smax.romanov@nginx.com }
1775*141Smax.romanov@nginx.com 
1776*141Smax.romanov@nginx.com 
1777*141Smax.romanov@nginx.com static nxt_port_t *
1778*141Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app)
1779*141Smax.romanov@nginx.com {
1780*141Smax.romanov@nginx.com     nxt_port_t        *port;
1781*141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
1782*141Smax.romanov@nginx.com 
1783*141Smax.romanov@nginx.com     port = NULL;
1784*141Smax.romanov@nginx.com 
1785*141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1786*141Smax.romanov@nginx.com 
1787*141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
1788*141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
1789*141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1790*141Smax.romanov@nginx.com 
1791*141Smax.romanov@nginx.com         lnk->next = NULL;
1792*141Smax.romanov@nginx.com 
1793*141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
1794*141Smax.romanov@nginx.com     }
1795*141Smax.romanov@nginx.com 
1796*141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1797*141Smax.romanov@nginx.com 
1798*141Smax.romanov@nginx.com     return port;
1799*141Smax.romanov@nginx.com }
1800*141Smax.romanov@nginx.com 
1801*141Smax.romanov@nginx.com 
1802*141Smax.romanov@nginx.com static void
1803*141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
1804*141Smax.romanov@nginx.com {
1805*141Smax.romanov@nginx.com     nxt_app_t            *app;
1806*141Smax.romanov@nginx.com     nxt_port_t           *port;
1807*141Smax.romanov@nginx.com     nxt_work_t           *work;
1808*141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
1809*141Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
1810*141Smax.romanov@nginx.com 
1811*141Smax.romanov@nginx.com     port = obj;
1812*141Smax.romanov@nginx.com     app = data;
1813*141Smax.romanov@nginx.com 
1814*141Smax.romanov@nginx.com     nxt_assert(app != NULL);
1815*141Smax.romanov@nginx.com     nxt_assert(app == port->app);
1816*141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
1817*141Smax.romanov@nginx.com 
1818*141Smax.romanov@nginx.com 
1819*141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
1820*141Smax.romanov@nginx.com         work = (nxt_work_t *) (port + 1);
1821*141Smax.romanov@nginx.com 
1822*141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
1823*141Smax.romanov@nginx.com 
1824*141Smax.romanov@nginx.com         work->next = NULL;
1825*141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
1826*141Smax.romanov@nginx.com         work->task = port->socket.task;
1827*141Smax.romanov@nginx.com         work->obj = port;
1828*141Smax.romanov@nginx.com         work->data = app;
1829*141Smax.romanov@nginx.com 
1830*141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
1831*141Smax.romanov@nginx.com 
1832*141Smax.romanov@nginx.com         return;
1833*141Smax.romanov@nginx.com     }
1834*141Smax.romanov@nginx.com 
1835*141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
1836*141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
1837*141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
1838*141Smax.romanov@nginx.com 
1839*141Smax.romanov@nginx.com         rc = nxt_queue_link_data(lnk, nxt_req_conn_link_t, app_link);
1840*141Smax.romanov@nginx.com 
1841*141Smax.romanov@nginx.com         nxt_debug(task, "process request #%uxD", rc->req_id);
1842*141Smax.romanov@nginx.com 
1843*141Smax.romanov@nginx.com         rc->app_port = port;
1844*141Smax.romanov@nginx.com 
1845*141Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, rc, rc->app_port->mem_pool);
1846*141Smax.romanov@nginx.com 
1847*141Smax.romanov@nginx.com         return;
1848*141Smax.romanov@nginx.com     }
1849*141Smax.romanov@nginx.com 
1850*141Smax.romanov@nginx.com     nxt_debug(task, "app requests queue is empty");
1851*141Smax.romanov@nginx.com 
1852*141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1853*141Smax.romanov@nginx.com 
1854*141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
1855*141Smax.romanov@nginx.com 
1856*141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1857*141Smax.romanov@nginx.com }
1858*141Smax.romanov@nginx.com 
1859*141Smax.romanov@nginx.com 
1860*141Smax.romanov@nginx.com void
1861*141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
1862*141Smax.romanov@nginx.com {
1863*141Smax.romanov@nginx.com     nxt_app_t  *app;
1864*141Smax.romanov@nginx.com 
1865*141Smax.romanov@nginx.com     if (port->app_link.next == NULL) {
1866*141Smax.romanov@nginx.com         return;
1867*141Smax.romanov@nginx.com     }
1868*141Smax.romanov@nginx.com 
1869*141Smax.romanov@nginx.com     app = port->app;
1870*141Smax.romanov@nginx.com 
1871*141Smax.romanov@nginx.com #if (NXT_DEBUG)
1872*141Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
1873*141Smax.romanov@nginx.com         nxt_abort();
1874*141Smax.romanov@nginx.com     }
1875*141Smax.romanov@nginx.com #endif
1876*141Smax.romanov@nginx.com 
1877*141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
1878*141Smax.romanov@nginx.com 
1879*141Smax.romanov@nginx.com     nxt_queue_remove(&port->app_link);
1880*141Smax.romanov@nginx.com     port->app_link.next = NULL;
1881*141Smax.romanov@nginx.com 
1882*141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
1883*141Smax.romanov@nginx.com }
1884*141Smax.romanov@nginx.com 
1885*141Smax.romanov@nginx.com 
1886*141Smax.romanov@nginx.com nxt_inline nxt_int_t
1887*141Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_conn_link_t *rc)
1888*141Smax.romanov@nginx.com {
1889*141Smax.romanov@nginx.com     nxt_app_t                *app;
1890*141Smax.romanov@nginx.com     nxt_conn_t               *c;
1891*141Smax.romanov@nginx.com     nxt_port_t               *port, *master_port;
1892*141Smax.romanov@nginx.com     nxt_runtime_t            *rt;
1893*141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
1894*141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
1895*141Smax.romanov@nginx.com 
1896*141Smax.romanov@nginx.com     port = NULL;
1897*141Smax.romanov@nginx.com     c = rc->conn;
1898*141Smax.romanov@nginx.com 
1899*141Smax.romanov@nginx.com     joint = c->listen->socket.data;
1900*141Smax.romanov@nginx.com     app = joint->socket_conf->application;
1901*141Smax.romanov@nginx.com 
1902*141Smax.romanov@nginx.com 
1903*141Smax.romanov@nginx.com     if (app == NULL) {
1904*141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
1905*141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
1906*141Smax.romanov@nginx.com         return NXT_ERROR;
1907*141Smax.romanov@nginx.com     }
1908*141Smax.romanov@nginx.com 
1909*141Smax.romanov@nginx.com 
1910*141Smax.romanov@nginx.com     port = nxt_router_app_get_port(app);
1911*141Smax.romanov@nginx.com 
1912*141Smax.romanov@nginx.com     if (port != NULL) {
1913*141Smax.romanov@nginx.com         rc->app_port = port;
1914*141Smax.romanov@nginx.com         return NXT_OK;
1915*141Smax.romanov@nginx.com     }
1916*141Smax.romanov@nginx.com 
1917*141Smax.romanov@nginx.com 
1918*141Smax.romanov@nginx.com     sw = nxt_mp_retain(c->mem_pool, sizeof(nxt_start_worker_t));
1919*141Smax.romanov@nginx.com 
1920*141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
1921*141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
1922*141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
1923*141Smax.romanov@nginx.com         return NXT_ERROR;
1924*141Smax.romanov@nginx.com     }
1925*141Smax.romanov@nginx.com 
1926*141Smax.romanov@nginx.com     nxt_memzero(sw, sizeof(nxt_start_worker_t));
1927*141Smax.romanov@nginx.com 
1928*141Smax.romanov@nginx.com     sw->stream = nxt_random(&task->thread->random);
1929*141Smax.romanov@nginx.com     sw->app = app;
1930*141Smax.romanov@nginx.com     sw->rc = rc;
1931*141Smax.romanov@nginx.com     sw->mem_pool = c->mem_pool;
1932*141Smax.romanov@nginx.com     sw->joint = c->listen->socket.data;
1933*141Smax.romanov@nginx.com 
1934*141Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
1935*141Smax.romanov@nginx.com     sw->work.task = task;
1936*141Smax.romanov@nginx.com     sw->work.obj = sw;
1937*141Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
1938*141Smax.romanov@nginx.com 
1939*141Smax.romanov@nginx.com     rt = task->thread->runtime;
1940*141Smax.romanov@nginx.com 
1941*141Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
1942*141Smax.romanov@nginx.com 
1943*141Smax.romanov@nginx.com     nxt_debug(task, "post send sw %uxD to master engine %p", sw->stream,
1944*141Smax.romanov@nginx.com               master_port->engine);
1945*141Smax.romanov@nginx.com 
1946*141Smax.romanov@nginx.com     nxt_event_engine_post(master_port->engine, &sw->work);
1947*141Smax.romanov@nginx.com 
1948*141Smax.romanov@nginx.com     return NXT_AGAIN;
194988Smax.romanov@nginx.com }
195088Smax.romanov@nginx.com 
195188Smax.romanov@nginx.com 
195288Smax.romanov@nginx.com static void
195353Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
195453Sigor@sysoev.ru {
195588Smax.romanov@nginx.com     size_t                    size, preread;
195653Sigor@sysoev.ru     nxt_int_t                 ret;
195753Sigor@sysoev.ru     nxt_buf_t                 *b;
195862Sigor@sysoev.ru     nxt_conn_t                *c;
195988Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
196053Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
196188Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
196253Sigor@sysoev.ru 
196353Sigor@sysoev.ru     c = obj;
196488Smax.romanov@nginx.com     ap = data;
196588Smax.romanov@nginx.com     b = c->read;
196653Sigor@sysoev.ru 
196753Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
196853Sigor@sysoev.ru 
196988Smax.romanov@nginx.com     if (ap == NULL) {
197088Smax.romanov@nginx.com         ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
197188Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
197253Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
197353Sigor@sysoev.ru             return;
197453Sigor@sysoev.ru         }
197553Sigor@sysoev.ru 
197688Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
197761Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
197861Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
197961Sigor@sysoev.ru             return;
198061Sigor@sysoev.ru         }
198188Smax.romanov@nginx.com 
198288Smax.romanov@nginx.com         c->socket.data = ap;
1983113Smax.romanov@nginx.com 
1984113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
1985113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
198653Sigor@sysoev.ru     }
198753Sigor@sysoev.ru 
198888Smax.romanov@nginx.com     h = &ap->r.header;
198988Smax.romanov@nginx.com 
199088Smax.romanov@nginx.com     ret = nxt_app_http_req_parse(task, ap, b);
199153Sigor@sysoev.ru 
199253Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
199353Sigor@sysoev.ru 
199453Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
199553Sigor@sysoev.ru 
199653Sigor@sysoev.ru     case NXT_DONE:
199788Smax.romanov@nginx.com         preread = nxt_buf_mem_used_size(&b->mem);
199888Smax.romanov@nginx.com 
199988Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
200088Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
200188Smax.romanov@nginx.com                   h->parsed_content_length, preread);
200288Smax.romanov@nginx.com 
200388Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
200488Smax.romanov@nginx.com         return;
200553Sigor@sysoev.ru 
200653Sigor@sysoev.ru     case NXT_ERROR:
200753Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
200853Sigor@sysoev.ru         return;
200953Sigor@sysoev.ru 
201053Sigor@sysoev.ru     default:  /* NXT_AGAIN */
201153Sigor@sysoev.ru 
201288Smax.romanov@nginx.com         if (h->done == 0) {
201388Smax.romanov@nginx.com 
201488Smax.romanov@nginx.com             if (c->read->mem.free == c->read->mem.end) {
201588Smax.romanov@nginx.com                 joint = c->listen->socket.data;
201688Smax.romanov@nginx.com                 size = joint->socket_conf->large_header_buffer_size;
201788Smax.romanov@nginx.com 
201888Smax.romanov@nginx.com                 if (size > (size_t) nxt_buf_mem_size(&b->mem)) {
201988Smax.romanov@nginx.com                     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
202088Smax.romanov@nginx.com                     if (nxt_slow_path(b == NULL)) {
202188Smax.romanov@nginx.com                         nxt_router_conn_close(task, c, data);
202288Smax.romanov@nginx.com                         return;
202388Smax.romanov@nginx.com                     }
202488Smax.romanov@nginx.com 
202588Smax.romanov@nginx.com                     size = c->read->mem.free - c->read->mem.pos;
2026*141Smax.romanov@nginx.com 
2027*141Smax.romanov@nginx.com                     c->read = nxt_buf_cpy(b, c->read->mem.pos, size);
202888Smax.romanov@nginx.com                 } else {
2029*141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 400,
2030*141Smax.romanov@nginx.com                                          "Too long request headers");
2031*141Smax.romanov@nginx.com                     return;
203288Smax.romanov@nginx.com                 }
203388Smax.romanov@nginx.com             }
203488Smax.romanov@nginx.com         }
203588Smax.romanov@nginx.com 
203688Smax.romanov@nginx.com         if (ap->r.body.done == 0) {
203788Smax.romanov@nginx.com 
203888Smax.romanov@nginx.com             preread = nxt_buf_mem_used_size(&b->mem);
203988Smax.romanov@nginx.com 
204088Smax.romanov@nginx.com             if (h->parsed_content_length - preread >
204188Smax.romanov@nginx.com                 (size_t) nxt_buf_mem_free_size(&b->mem)) {
204288Smax.romanov@nginx.com 
204388Smax.romanov@nginx.com                 b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0);
204488Smax.romanov@nginx.com                 if (nxt_slow_path(b == NULL)) {
2045*141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 500, "Failed to allocate "
2046*141Smax.romanov@nginx.com                                          "buffer for request body");
2047*141Smax.romanov@nginx.com                     return;
204888Smax.romanov@nginx.com                 }
204988Smax.romanov@nginx.com 
2050*141Smax.romanov@nginx.com                 c->read = nxt_buf_cpy(b, c->read->mem.pos, preread);
205153Sigor@sysoev.ru             }
205253Sigor@sysoev.ru 
205388Smax.romanov@nginx.com             nxt_debug(task, "router request body read again, rest: %uz",
205488Smax.romanov@nginx.com                       h->parsed_content_length - preread);
205553Sigor@sysoev.ru 
205653Sigor@sysoev.ru         }
205753Sigor@sysoev.ru 
205888Smax.romanov@nginx.com     }
205988Smax.romanov@nginx.com 
206088Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
206188Smax.romanov@nginx.com }
206288Smax.romanov@nginx.com 
206388Smax.romanov@nginx.com 
206488Smax.romanov@nginx.com static void
206588Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
206688Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
206788Smax.romanov@nginx.com {
2068122Smax.romanov@nginx.com     nxt_int_t            res;
206988Smax.romanov@nginx.com     nxt_req_id_t         req_id;
207088Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
207188Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
207288Smax.romanov@nginx.com 
207388Smax.romanov@nginx.com     engine = task->thread->engine;
207488Smax.romanov@nginx.com 
207588Smax.romanov@nginx.com     do {
2076138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
207788Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
207888Smax.romanov@nginx.com 
207988Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2080122Smax.romanov@nginx.com 
208188Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2082*141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2083*141Smax.romanov@nginx.com                              "req->conn link");
2084*141Smax.romanov@nginx.com 
2085*141Smax.romanov@nginx.com         return;
208688Smax.romanov@nginx.com     }
208788Smax.romanov@nginx.com 
208888Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
208988Smax.romanov@nginx.com 
209088Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
209188Smax.romanov@nginx.com               req_id, c, engine);
209253Sigor@sysoev.ru 
2093*141Smax.romanov@nginx.com     rc->reply_port = engine->port;
2094*141Smax.romanov@nginx.com 
2095*141Smax.romanov@nginx.com     res = nxt_router_app_port(task, rc);
2096*141Smax.romanov@nginx.com 
2097*141Smax.romanov@nginx.com     if (res != NXT_OK) {
2098*141Smax.romanov@nginx.com         return;
2099*141Smax.romanov@nginx.com     }
2100*141Smax.romanov@nginx.com 
2101*141Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, rc, c->mem_pool);
2102*141Smax.romanov@nginx.com }
2103*141Smax.romanov@nginx.com 
2104*141Smax.romanov@nginx.com 
2105*141Smax.romanov@nginx.com static void
2106*141Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_conn_link_t *rc,
2107*141Smax.romanov@nginx.com     nxt_mp_t *mp)
2108*141Smax.romanov@nginx.com {
2109*141Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2110*141Smax.romanov@nginx.com     nxt_int_t            res;
2111*141Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
2112*141Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2113*141Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2114*141Smax.romanov@nginx.com 
2115*141Smax.romanov@nginx.com     port = rc->app_port;
2116*141Smax.romanov@nginx.com 
2117*141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2118*141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2119*141Smax.romanov@nginx.com         return;
2120*141Smax.romanov@nginx.com     }
2121*141Smax.romanov@nginx.com 
2122*141Smax.romanov@nginx.com     reply_port = rc->reply_port;
2123*141Smax.romanov@nginx.com     ap = rc->conn->socket.data;
2124*141Smax.romanov@nginx.com 
2125122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2126*141Smax.romanov@nginx.com     port->mem_pool = mp;
2127*141Smax.romanov@nginx.com 
2128*141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2129*141Smax.romanov@nginx.com                                              reply_port->id);
2130*141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2131*141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2132122Smax.romanov@nginx.com 
2133122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2134*141Smax.romanov@nginx.com             nxt_router_gen_error(task, rc->conn, 500,
2135*141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2136*141Smax.romanov@nginx.com             goto fail;
2137122Smax.romanov@nginx.com         }
2138122Smax.romanov@nginx.com 
2139*141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
214088Smax.romanov@nginx.com     }
214188Smax.romanov@nginx.com 
214288Smax.romanov@nginx.com     wmsg.port = port;
214388Smax.romanov@nginx.com     wmsg.write = NULL;
214488Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2145*141Smax.romanov@nginx.com     wmsg.stream = rc->req_id;
2146*141Smax.romanov@nginx.com 
2147*141Smax.romanov@nginx.com     res = rc->app_port->app->module->prepare_msg(task, &ap->r, &wmsg);
2148122Smax.romanov@nginx.com 
2149122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2150*141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2151*141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2152*141Smax.romanov@nginx.com         goto fail;
2153122Smax.romanov@nginx.com     }
215488Smax.romanov@nginx.com 
215588Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
215688Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
215788Smax.romanov@nginx.com                     wmsg.port->socket.fd);
215888Smax.romanov@nginx.com 
2159122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2160*141Smax.romanov@nginx.com                                  -1, rc->req_id, reply_port->id, wmsg.write);
2161122Smax.romanov@nginx.com 
2162122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2163*141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500,
2164*141Smax.romanov@nginx.com                              "Failed to send message to application");
2165*141Smax.romanov@nginx.com         goto fail;
2166122Smax.romanov@nginx.com     }
2167122Smax.romanov@nginx.com 
2168*141Smax.romanov@nginx.com fail:
2169122Smax.romanov@nginx.com     port->mem_pool = port_mp;
217053Sigor@sysoev.ru }
217153Sigor@sysoev.ru 
217253Sigor@sysoev.ru 
217362Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
217453Sigor@sysoev.ru     nxt_aligned(64) =
217553Sigor@sysoev.ru {
217653Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
217753Sigor@sysoev.ru };
217853Sigor@sysoev.ru 
217953Sigor@sysoev.ru 
218053Sigor@sysoev.ru static void
218188Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
218288Smax.romanov@nginx.com {
218388Smax.romanov@nginx.com     nxt_buf_t         *b;
218488Smax.romanov@nginx.com     nxt_bool_t        last;
218588Smax.romanov@nginx.com     nxt_conn_t        *c;
218688Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
218788Smax.romanov@nginx.com 
218888Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
218988Smax.romanov@nginx.com 
219088Smax.romanov@nginx.com     c = obj;
219188Smax.romanov@nginx.com     b = c->write;
219288Smax.romanov@nginx.com 
219388Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
219488Smax.romanov@nginx.com 
219588Smax.romanov@nginx.com     last = 0;
219688Smax.romanov@nginx.com 
219788Smax.romanov@nginx.com     while (b != NULL) {
219888Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
219988Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
220088Smax.romanov@nginx.com                 break;
220188Smax.romanov@nginx.com             }
220288Smax.romanov@nginx.com         }
220388Smax.romanov@nginx.com 
220488Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
220588Smax.romanov@nginx.com             last = 1;
220688Smax.romanov@nginx.com         }
220788Smax.romanov@nginx.com 
220888Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
220988Smax.romanov@nginx.com 
221088Smax.romanov@nginx.com         b = b->next;
221188Smax.romanov@nginx.com     }
221288Smax.romanov@nginx.com 
221388Smax.romanov@nginx.com     c->write = b;
221488Smax.romanov@nginx.com 
221588Smax.romanov@nginx.com     if (b != NULL) {
221688Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
221788Smax.romanov@nginx.com 
221888Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
221988Smax.romanov@nginx.com     } else {
222088Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
222188Smax.romanov@nginx.com                   last);
222288Smax.romanov@nginx.com 
222388Smax.romanov@nginx.com         if (last != 0) {
222488Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
222588Smax.romanov@nginx.com 
222688Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
222788Smax.romanov@nginx.com                                c->socket.data);
222888Smax.romanov@nginx.com         }
222988Smax.romanov@nginx.com     }
223088Smax.romanov@nginx.com }
223188Smax.romanov@nginx.com 
223288Smax.romanov@nginx.com 
223388Smax.romanov@nginx.com static void
223453Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
223553Sigor@sysoev.ru {
223662Sigor@sysoev.ru     nxt_conn_t  *c;
223753Sigor@sysoev.ru 
223853Sigor@sysoev.ru     c = obj;
223953Sigor@sysoev.ru 
224053Sigor@sysoev.ru     nxt_debug(task, "router conn close");
224153Sigor@sysoev.ru 
224253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
224353Sigor@sysoev.ru 
224462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
224553Sigor@sysoev.ru }
224653Sigor@sysoev.ru 
224753Sigor@sysoev.ru 
224853Sigor@sysoev.ru static void
224953Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
225053Sigor@sysoev.ru {
225162Sigor@sysoev.ru     nxt_conn_t               *c;
225288Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
225353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
225453Sigor@sysoev.ru 
225553Sigor@sysoev.ru     c = obj;
225653Sigor@sysoev.ru 
225753Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
225853Sigor@sysoev.ru 
225988Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
226088Smax.romanov@nginx.com 
226188Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
226288Smax.romanov@nginx.com 
2263*141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2264*141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2265*141Smax.romanov@nginx.com 
2266*141Smax.romanov@nginx.com             rc->app_port = NULL;
2267*141Smax.romanov@nginx.com         }
2268*141Smax.romanov@nginx.com 
226988Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
227088Smax.romanov@nginx.com 
227188Smax.romanov@nginx.com     } nxt_queue_loop;
227288Smax.romanov@nginx.com 
2273122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
2274122Smax.romanov@nginx.com 
2275131Smax.romanov@nginx.com     joint = c->listen->socket.data;
2276131Smax.romanov@nginx.com 
2277131Smax.romanov@nginx.com     task = &task->thread->engine->task;
2278131Smax.romanov@nginx.com 
2279*141Smax.romanov@nginx.com     if (nxt_mp_release(c->mem_pool, c) == 0) {
2280*141Smax.romanov@nginx.com         nxt_router_conf_release(task, joint);
2281*141Smax.romanov@nginx.com     }
228253Sigor@sysoev.ru }
228353Sigor@sysoev.ru 
228453Sigor@sysoev.ru 
228553Sigor@sysoev.ru static void
228653Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
228753Sigor@sysoev.ru {
228862Sigor@sysoev.ru     nxt_conn_t  *c;
228953Sigor@sysoev.ru 
229053Sigor@sysoev.ru     c = obj;
229153Sigor@sysoev.ru 
229253Sigor@sysoev.ru     nxt_debug(task, "router conn error");
229353Sigor@sysoev.ru 
229453Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
229553Sigor@sysoev.ru 
229662Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
229753Sigor@sysoev.ru }
229853Sigor@sysoev.ru 
229953Sigor@sysoev.ru 
230053Sigor@sysoev.ru static void
230153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
230253Sigor@sysoev.ru {
230362Sigor@sysoev.ru     nxt_conn_t   *c;
230462Sigor@sysoev.ru     nxt_timer_t  *timer;
230553Sigor@sysoev.ru 
230653Sigor@sysoev.ru     timer = obj;
230753Sigor@sysoev.ru 
230853Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
230953Sigor@sysoev.ru 
231062Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
231153Sigor@sysoev.ru 
231253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
231353Sigor@sysoev.ru 
231462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
231553Sigor@sysoev.ru }
231653Sigor@sysoev.ru 
231753Sigor@sysoev.ru 
231853Sigor@sysoev.ru static nxt_msec_t
231962Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
232053Sigor@sysoev.ru {
232153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
232253Sigor@sysoev.ru 
232353Sigor@sysoev.ru     joint = c->listen->socket.data;
232453Sigor@sysoev.ru 
232553Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
232653Sigor@sysoev.ru }
2327*141Smax.romanov@nginx.com 
2328*141Smax.romanov@nginx.com 
2329*141Smax.romanov@nginx.com static nxt_int_t
2330*141Smax.romanov@nginx.com nxt_sw_test(nxt_lvlhsh_query_t *lhq, void *data)
2331*141Smax.romanov@nginx.com {
2332*141Smax.romanov@nginx.com     return NXT_OK;
2333*141Smax.romanov@nginx.com }
2334*141Smax.romanov@nginx.com 
2335*141Smax.romanov@nginx.com 
2336*141Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t  lvlhsh_sw_proto  nxt_aligned(64) = {
2337*141Smax.romanov@nginx.com     NXT_LVLHSH_DEFAULT,
2338*141Smax.romanov@nginx.com     nxt_sw_test,
2339*141Smax.romanov@nginx.com     nxt_lvlhsh_alloc,
2340*141Smax.romanov@nginx.com     nxt_lvlhsh_free,
2341*141Smax.romanov@nginx.com };
2342*141Smax.romanov@nginx.com 
2343*141Smax.romanov@nginx.com 
2344*141Smax.romanov@nginx.com static void
2345*141Smax.romanov@nginx.com nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router,
2346*141Smax.romanov@nginx.com     nxt_start_worker_t *sw)
2347*141Smax.romanov@nginx.com {
2348*141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2349*141Smax.romanov@nginx.com 
2350*141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&sw->stream, sizeof(sw->stream));
2351*141Smax.romanov@nginx.com     lhq.key.length = sizeof(sw->stream);
2352*141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &sw->stream;
2353*141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2354*141Smax.romanov@nginx.com     lhq.replace = 0;
2355*141Smax.romanov@nginx.com     lhq.value = sw;
2356*141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2357*141Smax.romanov@nginx.com 
2358*141Smax.romanov@nginx.com     switch (nxt_lvlhsh_insert(&router->start_workers, &lhq)) {
2359*141Smax.romanov@nginx.com 
2360*141Smax.romanov@nginx.com     case NXT_OK:
2361*141Smax.romanov@nginx.com         break;
2362*141Smax.romanov@nginx.com 
2363*141Smax.romanov@nginx.com     default:
2364*141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw add failed",
2365*141Smax.romanov@nginx.com                       sw->stream);
2366*141Smax.romanov@nginx.com         break;
2367*141Smax.romanov@nginx.com     }
2368*141Smax.romanov@nginx.com }
2369*141Smax.romanov@nginx.com 
2370*141Smax.romanov@nginx.com 
2371*141Smax.romanov@nginx.com static nxt_start_worker_t *
2372*141Smax.romanov@nginx.com nxt_router_sw_find_remove(nxt_task_t *task, nxt_router_t *router, uint32_t id)
2373*141Smax.romanov@nginx.com {
2374*141Smax.romanov@nginx.com     nxt_lvlhsh_query_t  lhq;
2375*141Smax.romanov@nginx.com 
2376*141Smax.romanov@nginx.com     lhq.key_hash = nxt_murmur_hash2(&id, sizeof(id));
2377*141Smax.romanov@nginx.com     lhq.key.length = sizeof(id);
2378*141Smax.romanov@nginx.com     lhq.key.start = (u_char *) &id;
2379*141Smax.romanov@nginx.com     lhq.proto = &lvlhsh_sw_proto;
2380*141Smax.romanov@nginx.com     lhq.pool = task->thread->runtime->mem_pool;
2381*141Smax.romanov@nginx.com 
2382*141Smax.romanov@nginx.com     switch (nxt_lvlhsh_delete(&router->start_workers, &lhq)) {
2383*141Smax.romanov@nginx.com 
2384*141Smax.romanov@nginx.com     case NXT_OK:
2385*141Smax.romanov@nginx.com         return lhq.value;
2386*141Smax.romanov@nginx.com 
2387*141Smax.romanov@nginx.com     default:
2388*141Smax.romanov@nginx.com         nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw remove failed",
2389*141Smax.romanov@nginx.com                       id);
2390*141Smax.romanov@nginx.com         break;
2391*141Smax.romanov@nginx.com     }
2392*141Smax.romanov@nginx.com 
2393*141Smax.romanov@nginx.com     return NULL;
2394*141Smax.romanov@nginx.com }
2395