xref: /unit/src/nxt_router.c (revision 193)
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 
23167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
24141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
25141Smax.romanov@nginx.com 
26141Smax.romanov@nginx.com struct nxt_start_worker_s {
27141Smax.romanov@nginx.com     nxt_app_t              *app;
28167Smax.romanov@nginx.com     nxt_req_app_link_t     *ra;
29141Smax.romanov@nginx.com 
30141Smax.romanov@nginx.com     nxt_work_t             work;
31141Smax.romanov@nginx.com };
32141Smax.romanov@nginx.com 
33141Smax.romanov@nginx.com 
34167Smax.romanov@nginx.com struct nxt_req_app_link_s {
35167Smax.romanov@nginx.com     nxt_req_id_t         req_id;
36167Smax.romanov@nginx.com     nxt_port_t           *app_port;
37167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
38167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
39167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
40167Smax.romanov@nginx.com 
41167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
42167Smax.romanov@nginx.com 
43167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
44167Smax.romanov@nginx.com     nxt_work_t           work;
45167Smax.romanov@nginx.com };
46167Smax.romanov@nginx.com 
47167Smax.romanov@nginx.com 
48139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
49139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task,
50139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
51139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task,
52139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
53139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
54139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
55139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
56*193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
5753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
5853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
5953Sigor@sysoev.ru 
60115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
61115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
62133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
63133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
64133Sigor@sysoev.ru     nxt_str_t *name);
6553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task,
6653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
6765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
6865Sigor@sysoev.ru     nxt_sockaddr_t *sa);
6953Sigor@sysoev.ru 
7053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
7153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
7253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
73115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
74115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
75115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
76115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
77115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
78115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
79115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
80154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
81154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
82154Sigor@sysoev.ru     nxt_work_handler_t handler);
83139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
84139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
8553Sigor@sysoev.ru 
8653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
8753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
8853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
8953Sigor@sysoev.ru     nxt_event_engine_t *engine);
90133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
91133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9253Sigor@sysoev.ru 
9353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf);
94154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf);
9553Sigor@sysoev.ru 
9653Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
9753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
9853Sigor@sysoev.ru     void *data);
9953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
10053Sigor@sysoev.ru     void *data);
10153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
10253Sigor@sysoev.ru     void *data);
10353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
10453Sigor@sysoev.ru     void *data);
10553Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
10653Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
10753Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
10853Sigor@sysoev.ru     void *data);
10953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
11053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
11153Sigor@sysoev.ru 
112167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
113167Smax.romanov@nginx.com     void *data);
114167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
115167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id);
116141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
117141Smax.romanov@nginx.com     void *data);
118141Smax.romanov@nginx.com 
11953Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
12053Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
12153Sigor@sysoev.ru     void *data);
12288Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
12388Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
124141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
125167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
12688Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
12753Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
12853Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
12953Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
13053Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
13162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
13220Sigor@sysoev.ru 
133141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
134141Smax.romanov@nginx.com     const char* fmt, ...);
135141Smax.romanov@nginx.com 
136119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
13720Sigor@sysoev.ru 
13820Sigor@sysoev.ru nxt_int_t
139141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
14020Sigor@sysoev.ru {
141141Smax.romanov@nginx.com     nxt_int_t      ret;
142141Smax.romanov@nginx.com     nxt_router_t   *router;
143141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
144141Smax.romanov@nginx.com 
145141Smax.romanov@nginx.com     rt = task->thread->runtime;
14653Sigor@sysoev.ru 
14788Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
14888Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14988Smax.romanov@nginx.com         return ret;
15088Smax.romanov@nginx.com     }
15188Smax.romanov@nginx.com 
15253Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
15353Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
15453Sigor@sysoev.ru         return NXT_ERROR;
15553Sigor@sysoev.ru     }
15653Sigor@sysoev.ru 
15753Sigor@sysoev.ru     nxt_queue_init(&router->engines);
15853Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
159133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
16053Sigor@sysoev.ru 
161119Smax.romanov@nginx.com     nxt_router = router;
162119Smax.romanov@nginx.com 
163115Sigor@sysoev.ru     return NXT_OK;
164115Sigor@sysoev.ru }
165115Sigor@sysoev.ru 
166115Sigor@sysoev.ru 
167167Smax.romanov@nginx.com static nxt_start_worker_t *
168192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
169167Smax.romanov@nginx.com {
170167Smax.romanov@nginx.com     nxt_port_t          *master_port;
171167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
172167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
173167Smax.romanov@nginx.com 
174192Smax.romanov@nginx.com     sw = nxt_zalloc(sizeof(nxt_start_worker_t));
175167Smax.romanov@nginx.com 
176167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
177167Smax.romanov@nginx.com         return NULL;
178167Smax.romanov@nginx.com     }
179167Smax.romanov@nginx.com 
180167Smax.romanov@nginx.com     sw->app = app;
181167Smax.romanov@nginx.com     sw->ra = ra;
182167Smax.romanov@nginx.com 
183192Smax.romanov@nginx.com     nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw,
184167Smax.romanov@nginx.com                     ra->req_id, &app->name, app);
185167Smax.romanov@nginx.com 
186167Smax.romanov@nginx.com     rt = task->thread->runtime;
187167Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
188167Smax.romanov@nginx.com 
189167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
190167Smax.romanov@nginx.com     sw->work.task = &master_port->engine->task;
191167Smax.romanov@nginx.com     sw->work.obj = sw;
192167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
193167Smax.romanov@nginx.com     sw->work.next = NULL;
194167Smax.romanov@nginx.com 
195167Smax.romanov@nginx.com     if (task->thread->engine != master_port->engine) {
196192Smax.romanov@nginx.com         nxt_debug(task, "sw %p post send to master engine %p", sw,
197167Smax.romanov@nginx.com                   master_port->engine);
198167Smax.romanov@nginx.com 
199167Smax.romanov@nginx.com         nxt_event_engine_post(master_port->engine, &sw->work);
200167Smax.romanov@nginx.com 
201167Smax.romanov@nginx.com     } else {
202167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
203167Smax.romanov@nginx.com     }
204167Smax.romanov@nginx.com 
205167Smax.romanov@nginx.com     return sw;
206167Smax.romanov@nginx.com }
207167Smax.romanov@nginx.com 
208167Smax.romanov@nginx.com 
209192Smax.romanov@nginx.com nxt_inline void
210192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw)
211141Smax.romanov@nginx.com {
212192Smax.romanov@nginx.com     nxt_debug(task, "sw %p release", sw);
213192Smax.romanov@nginx.com 
214192Smax.romanov@nginx.com     nxt_free(sw);
215141Smax.romanov@nginx.com }
216141Smax.romanov@nginx.com 
217141Smax.romanov@nginx.com 
218167Smax.romanov@nginx.com static nxt_req_app_link_t *
219167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
220167Smax.romanov@nginx.com {
221167Smax.romanov@nginx.com     nxt_mp_t            *mp;
222167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
223167Smax.romanov@nginx.com 
224167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
225167Smax.romanov@nginx.com 
226167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
227167Smax.romanov@nginx.com 
228167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
229167Smax.romanov@nginx.com         return NULL;
230167Smax.romanov@nginx.com     }
231167Smax.romanov@nginx.com 
232167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD create", ra->req_id);
233167Smax.romanov@nginx.com 
234167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
235167Smax.romanov@nginx.com 
236167Smax.romanov@nginx.com     ra->req_id = rc->req_id;
237167Smax.romanov@nginx.com     ra->app_port = NULL;
238167Smax.romanov@nginx.com     ra->rc = rc;
239167Smax.romanov@nginx.com 
240167Smax.romanov@nginx.com     ra->mem_pool = mp;
241167Smax.romanov@nginx.com 
242167Smax.romanov@nginx.com     ra->work.handler = NULL;
243167Smax.romanov@nginx.com     ra->work.task = &task->thread->engine->task;
244167Smax.romanov@nginx.com     ra->work.obj = ra;
245167Smax.romanov@nginx.com     ra->work.data = task->thread->engine;
246167Smax.romanov@nginx.com 
247167Smax.romanov@nginx.com     return ra;
248167Smax.romanov@nginx.com }
249167Smax.romanov@nginx.com 
250167Smax.romanov@nginx.com 
251167Smax.romanov@nginx.com static void
252167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
253167Smax.romanov@nginx.com {
254167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
255167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
256167Smax.romanov@nginx.com 
257167Smax.romanov@nginx.com     ra = obj;
258167Smax.romanov@nginx.com     engine = data;
259167Smax.romanov@nginx.com 
260167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
261167Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
262167Smax.romanov@nginx.com         ra->work.task = &engine->task;
263167Smax.romanov@nginx.com         ra->work.next = NULL;
264167Smax.romanov@nginx.com 
265167Smax.romanov@nginx.com         nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine);
266167Smax.romanov@nginx.com 
267167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
268167Smax.romanov@nginx.com 
269167Smax.romanov@nginx.com         return;
270167Smax.romanov@nginx.com     }
271167Smax.romanov@nginx.com 
272167Smax.romanov@nginx.com     nxt_debug(task, "ra #%uxD release", ra->req_id);
273167Smax.romanov@nginx.com 
274167Smax.romanov@nginx.com     if (ra->app_port != NULL) {
275167Smax.romanov@nginx.com 
276167Smax.romanov@nginx.com         if (ra->rc->conn != NULL) {
277167Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
278167Smax.romanov@nginx.com 
279167Smax.romanov@nginx.com         } else {
280167Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
281167Smax.romanov@nginx.com         }
282167Smax.romanov@nginx.com     }
283167Smax.romanov@nginx.com 
284167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
285167Smax.romanov@nginx.com }
286167Smax.romanov@nginx.com 
287167Smax.romanov@nginx.com 
288141Smax.romanov@nginx.com void
289141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
290141Smax.romanov@nginx.com {
291141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
292141Smax.romanov@nginx.com 
293192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
294141Smax.romanov@nginx.com         return;
295141Smax.romanov@nginx.com     }
296141Smax.romanov@nginx.com 
297192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
298192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
299141Smax.romanov@nginx.com     }
300192Smax.romanov@nginx.com 
301192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
302141Smax.romanov@nginx.com }
303141Smax.romanov@nginx.com 
304141Smax.romanov@nginx.com 
305139Sigor@sysoev.ru void
306139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
307115Sigor@sysoev.ru {
308139Sigor@sysoev.ru     size_t                  dump_size;
309139Sigor@sysoev.ru     nxt_buf_t               *b;
310139Sigor@sysoev.ru     nxt_int_t               ret;
311139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
312139Sigor@sysoev.ru 
313139Sigor@sysoev.ru     b = msg->buf;
314139Sigor@sysoev.ru 
315139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
316139Sigor@sysoev.ru 
317139Sigor@sysoev.ru     if (dump_size > 300) {
318139Sigor@sysoev.ru         dump_size = 300;
31953Sigor@sysoev.ru     }
32053Sigor@sysoev.ru 
321139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
322139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
323139Sigor@sysoev.ru 
324139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
325139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
326139Sigor@sysoev.ru         return;
32753Sigor@sysoev.ru     }
32853Sigor@sysoev.ru 
329139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
330139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
331139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
332139Sigor@sysoev.ru                                        msg->port_msg.pid, 0);
333139Sigor@sysoev.ru 
334139Sigor@sysoev.ru     ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free);
335139Sigor@sysoev.ru 
336139Sigor@sysoev.ru     b->mem.pos = b->mem.free;
337139Sigor@sysoev.ru 
338139Sigor@sysoev.ru     if (ret == NXT_OK) {
339180Smax.romanov@nginx.com         nxt_router_conf_success(task, tmcf);
340180Smax.romanov@nginx.com         return;
341139Sigor@sysoev.ru     }
342139Sigor@sysoev.ru 
343139Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
344139Sigor@sysoev.ru 
345180Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
34653Sigor@sysoev.ru }
34753Sigor@sysoev.ru 
34853Sigor@sysoev.ru 
349192Smax.romanov@nginx.com void
350192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
351192Smax.romanov@nginx.com {
352192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
353192Smax.romanov@nginx.com 
354192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
355192Smax.romanov@nginx.com         return;
356192Smax.romanov@nginx.com     }
357192Smax.romanov@nginx.com 
358192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
359192Smax.romanov@nginx.com 
360192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
361192Smax.romanov@nginx.com }
362192Smax.romanov@nginx.com 
363192Smax.romanov@nginx.com 
36453Sigor@sysoev.ru static nxt_router_temp_conf_t *
365139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
36653Sigor@sysoev.ru {
36765Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
36853Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
36953Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
37053Sigor@sysoev.ru 
37165Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
37253Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
37353Sigor@sysoev.ru         return NULL;
37453Sigor@sysoev.ru     }
37553Sigor@sysoev.ru 
37665Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
37753Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
37853Sigor@sysoev.ru         goto fail;
37953Sigor@sysoev.ru     }
38053Sigor@sysoev.ru 
38153Sigor@sysoev.ru     rtcf->mem_pool = mp;
38253Sigor@sysoev.ru 
38365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
38453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
38553Sigor@sysoev.ru         goto fail;
38653Sigor@sysoev.ru     }
38753Sigor@sysoev.ru 
38865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
38953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
39053Sigor@sysoev.ru         goto temp_fail;
39153Sigor@sysoev.ru     }
39253Sigor@sysoev.ru 
39353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
39453Sigor@sysoev.ru     tmcf->conf = rtcf;
395139Sigor@sysoev.ru     tmcf->count = 1;
396139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
39753Sigor@sysoev.ru 
39853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
39953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
40053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
40153Sigor@sysoev.ru         goto temp_fail;
40253Sigor@sysoev.ru     }
40353Sigor@sysoev.ru 
40453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
40553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
40653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
40753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
40853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
409133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
410133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
41153Sigor@sysoev.ru 
41253Sigor@sysoev.ru     return tmcf;
41353Sigor@sysoev.ru 
41453Sigor@sysoev.ru temp_fail:
41553Sigor@sysoev.ru 
41665Sigor@sysoev.ru     nxt_mp_destroy(tmp);
41753Sigor@sysoev.ru 
41853Sigor@sysoev.ru fail:
41953Sigor@sysoev.ru 
42065Sigor@sysoev.ru     nxt_mp_destroy(mp);
42153Sigor@sysoev.ru 
42253Sigor@sysoev.ru     return NULL;
42353Sigor@sysoev.ru }
42453Sigor@sysoev.ru 
42553Sigor@sysoev.ru 
426139Sigor@sysoev.ru static nxt_int_t
427139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
428139Sigor@sysoev.ru     u_char *start, u_char *end)
429139Sigor@sysoev.ru {
430139Sigor@sysoev.ru     nxt_int_t                    ret;
431139Sigor@sysoev.ru     nxt_router_t                 *router;
432139Sigor@sysoev.ru     nxt_runtime_t                *rt;
433139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
434139Sigor@sysoev.ru 
435139Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, start, end);
436139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
437139Sigor@sysoev.ru         return ret;
438139Sigor@sysoev.ru     }
439139Sigor@sysoev.ru 
440139Sigor@sysoev.ru     router = tmcf->conf->router;
441139Sigor@sysoev.ru 
442139Sigor@sysoev.ru     nxt_router_listen_sockets_sort(router, tmcf);
443139Sigor@sysoev.ru 
444139Sigor@sysoev.ru     ret = nxt_router_listen_sockets_stub_create(task, tmcf);
445139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
446139Sigor@sysoev.ru         return ret;
447139Sigor@sysoev.ru     }
448139Sigor@sysoev.ru 
449139Sigor@sysoev.ru     rt = task->thread->runtime;
450139Sigor@sysoev.ru 
451139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
452139Sigor@sysoev.ru 
453139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
454139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
455139Sigor@sysoev.ru         return ret;
456139Sigor@sysoev.ru     }
457139Sigor@sysoev.ru 
458139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
459139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
460139Sigor@sysoev.ru         return ret;
461139Sigor@sysoev.ru     }
462139Sigor@sysoev.ru 
463139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
464139Sigor@sysoev.ru 
465139Sigor@sysoev.ru     nxt_router_engines_post(tmcf);
466139Sigor@sysoev.ru 
467139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
468139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
469139Sigor@sysoev.ru 
470139Sigor@sysoev.ru     return NXT_OK;
471139Sigor@sysoev.ru }
472139Sigor@sysoev.ru 
473139Sigor@sysoev.ru 
474139Sigor@sysoev.ru static void
475139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
476139Sigor@sysoev.ru {
477153Sigor@sysoev.ru     nxt_joint_job_t  *job;
478153Sigor@sysoev.ru 
479153Sigor@sysoev.ru     job = obj;
480153Sigor@sysoev.ru 
481153Sigor@sysoev.ru     nxt_router_conf_success(task, job->tmcf);
482139Sigor@sysoev.ru }
483139Sigor@sysoev.ru 
484139Sigor@sysoev.ru 
485139Sigor@sysoev.ru static void
486139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
487139Sigor@sysoev.ru {
488139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
489139Sigor@sysoev.ru 
490139Sigor@sysoev.ru     if (--tmcf->count == 0) {
491*193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
492139Sigor@sysoev.ru     }
493139Sigor@sysoev.ru }
494139Sigor@sysoev.ru 
495139Sigor@sysoev.ru 
496139Sigor@sysoev.ru static void
497139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
498139Sigor@sysoev.ru {
499148Sigor@sysoev.ru     nxt_socket_t       s;
500149Sigor@sysoev.ru     nxt_router_t       *router;
501148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
502148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
503148Sigor@sysoev.ru 
504148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
505148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
506148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
507148Sigor@sysoev.ru     {
508148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
509148Sigor@sysoev.ru         s = skcf->listen.socket;
510148Sigor@sysoev.ru 
511148Sigor@sysoev.ru         if (s != -1) {
512148Sigor@sysoev.ru             nxt_socket_close(task, s);
513148Sigor@sysoev.ru         }
514148Sigor@sysoev.ru 
515148Sigor@sysoev.ru         nxt_free(skcf->socket);
516148Sigor@sysoev.ru     }
517148Sigor@sysoev.ru 
518149Sigor@sysoev.ru     router = tmcf->conf->router;
519149Sigor@sysoev.ru 
520149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
521149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
522149Sigor@sysoev.ru 
523148Sigor@sysoev.ru     // TODO: new engines and threads
524148Sigor@sysoev.ru 
525139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
526139Sigor@sysoev.ru 
527*193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
528139Sigor@sysoev.ru }
529139Sigor@sysoev.ru 
530139Sigor@sysoev.ru 
531139Sigor@sysoev.ru static void
532139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
533*193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
534139Sigor@sysoev.ru {
535*193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
536139Sigor@sysoev.ru }
537139Sigor@sysoev.ru 
538139Sigor@sysoev.ru 
539115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
540115Sigor@sysoev.ru     {
541133Sigor@sysoev.ru         nxt_string("listeners_threads"),
542115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
543115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
544115Sigor@sysoev.ru     },
545115Sigor@sysoev.ru };
546115Sigor@sysoev.ru 
547115Sigor@sysoev.ru 
548133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
549115Sigor@sysoev.ru     {
550133Sigor@sysoev.ru         nxt_string("type"),
551115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
552133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
553115Sigor@sysoev.ru     },
554115Sigor@sysoev.ru 
555115Sigor@sysoev.ru     {
556133Sigor@sysoev.ru         nxt_string("workers"),
557115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
558133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
559133Sigor@sysoev.ru     },
560133Sigor@sysoev.ru };
561133Sigor@sysoev.ru 
562133Sigor@sysoev.ru 
563133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
564133Sigor@sysoev.ru     {
565133Sigor@sysoev.ru         nxt_string("application"),
566133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
567133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
568115Sigor@sysoev.ru     },
569115Sigor@sysoev.ru };
570115Sigor@sysoev.ru 
571115Sigor@sysoev.ru 
572115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
573115Sigor@sysoev.ru     {
574115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
575115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
576115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
577115Sigor@sysoev.ru     },
578115Sigor@sysoev.ru 
579115Sigor@sysoev.ru     {
580115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
581115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
582115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
583115Sigor@sysoev.ru     },
584115Sigor@sysoev.ru 
585115Sigor@sysoev.ru     {
586115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
587115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
588115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
589115Sigor@sysoev.ru     },
590115Sigor@sysoev.ru };
591115Sigor@sysoev.ru 
592115Sigor@sysoev.ru 
59353Sigor@sysoev.ru static nxt_int_t
594115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
595115Sigor@sysoev.ru     u_char *start, u_char *end)
59653Sigor@sysoev.ru {
597133Sigor@sysoev.ru     u_char                      *p;
598133Sigor@sysoev.ru     size_t                      size;
599115Sigor@sysoev.ru     nxt_mp_t                    *mp;
600115Sigor@sysoev.ru     uint32_t                    next;
601115Sigor@sysoev.ru     nxt_int_t                   ret;
602115Sigor@sysoev.ru     nxt_str_t                   name;
603133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
604133Sigor@sysoev.ru     nxt_app_type_t              type;
605115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
606133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
607133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
608133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
609115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
610133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
611115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
612115Sigor@sysoev.ru 
613115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
614133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
615115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
616115Sigor@sysoev.ru 
617115Sigor@sysoev.ru     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
618115Sigor@sysoev.ru     if (conf == NULL) {
619115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
620115Sigor@sysoev.ru         return NXT_ERROR;
621115Sigor@sysoev.ru     }
622115Sigor@sysoev.ru 
623136Svbart@nginx.com     ret = nxt_conf_map_object(conf, nxt_router_conf,
624136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
625115Sigor@sysoev.ru     if (ret != NXT_OK) {
626133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
627115Sigor@sysoev.ru         return NXT_ERROR;
628115Sigor@sysoev.ru     }
629115Sigor@sysoev.ru 
630117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
631117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
632117Sigor@sysoev.ru     }
633117Sigor@sysoev.ru 
634133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
635133Sigor@sysoev.ru     if (applications == NULL) {
636133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
637115Sigor@sysoev.ru         return NXT_ERROR;
638115Sigor@sysoev.ru     }
639115Sigor@sysoev.ru 
640133Sigor@sysoev.ru     next = 0;
641133Sigor@sysoev.ru 
642133Sigor@sysoev.ru     for ( ;; ) {
643133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
644133Sigor@sysoev.ru         if (application == NULL) {
645133Sigor@sysoev.ru             break;
646133Sigor@sysoev.ru         }
647133Sigor@sysoev.ru 
648133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
649133Sigor@sysoev.ru 
650144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
651144Smax.romanov@nginx.com 
652144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
653133Sigor@sysoev.ru         if (app == NULL) {
654133Sigor@sysoev.ru             goto fail;
655133Sigor@sysoev.ru         }
656133Sigor@sysoev.ru 
657144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
658144Smax.romanov@nginx.com 
659144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
660144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
661133Sigor@sysoev.ru 
662133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
663133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
664133Sigor@sysoev.ru 
665144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
666144Smax.romanov@nginx.com 
667133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
668133Sigor@sysoev.ru 
669133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
670133Sigor@sysoev.ru 
671133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
672133Sigor@sysoev.ru             nxt_free(app);
673133Sigor@sysoev.ru 
674133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
675133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
676133Sigor@sysoev.ru             continue;
677133Sigor@sysoev.ru         }
678133Sigor@sysoev.ru 
679136Svbart@nginx.com         ret = nxt_conf_map_object(application, nxt_router_app_conf,
680136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
681133Sigor@sysoev.ru         if (ret != NXT_OK) {
682133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
683133Sigor@sysoev.ru             goto app_fail;
684133Sigor@sysoev.ru         }
685115Sigor@sysoev.ru 
686133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
687133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
688133Sigor@sysoev.ru 
689141Smax.romanov@nginx.com         type = nxt_app_parse_type(&apcf.type);
690141Smax.romanov@nginx.com 
691141Smax.romanov@nginx.com         if (type == NXT_APP_UNKNOWN) {
692141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
693141Smax.romanov@nginx.com                     &apcf.type);
694141Smax.romanov@nginx.com             goto app_fail;
695141Smax.romanov@nginx.com         }
696141Smax.romanov@nginx.com 
697141Smax.romanov@nginx.com         if (nxt_app_modules[type] == NULL) {
698133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
699133Sigor@sysoev.ru                     &apcf.type);
700133Sigor@sysoev.ru             goto app_fail;
701133Sigor@sysoev.ru         }
702133Sigor@sysoev.ru 
703133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
704133Sigor@sysoev.ru         if (ret != NXT_OK) {
705133Sigor@sysoev.ru             goto app_fail;
706133Sigor@sysoev.ru         }
707133Sigor@sysoev.ru 
708141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
709141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
710141Smax.romanov@nginx.com 
711144Smax.romanov@nginx.com         app->name.length = name.length;
712144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
713144Smax.romanov@nginx.com 
714133Sigor@sysoev.ru         app->type = type;
715133Sigor@sysoev.ru         app->max_workers = apcf.workers;
716133Sigor@sysoev.ru         app->live = 1;
717141Smax.romanov@nginx.com         app->module = nxt_app_modules[type];
718133Sigor@sysoev.ru 
719133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
720133Sigor@sysoev.ru     }
721133Sigor@sysoev.ru 
722133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
723133Sigor@sysoev.ru #if 0
724133Sigor@sysoev.ru     if (http == NULL) {
725133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
726133Sigor@sysoev.ru         return NXT_ERROR;
727133Sigor@sysoev.ru     }
728133Sigor@sysoev.ru #endif
729133Sigor@sysoev.ru 
730133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
731115Sigor@sysoev.ru     if (listeners == NULL) {
732133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
733115Sigor@sysoev.ru         return NXT_ERROR;
734115Sigor@sysoev.ru     }
73553Sigor@sysoev.ru 
736133Sigor@sysoev.ru     next = 0;
73753Sigor@sysoev.ru 
738133Sigor@sysoev.ru     mp = tmcf->conf->mem_pool;
739115Sigor@sysoev.ru 
740115Sigor@sysoev.ru     for ( ;; ) {
741115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
742115Sigor@sysoev.ru         if (listener == NULL) {
743115Sigor@sysoev.ru             break;
744115Sigor@sysoev.ru         }
74553Sigor@sysoev.ru 
746115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
747115Sigor@sysoev.ru         if (sa == NULL) {
748115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
749133Sigor@sysoev.ru             goto fail;
750115Sigor@sysoev.ru         }
751115Sigor@sysoev.ru 
752115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
753115Sigor@sysoev.ru 
754115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
755115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
75653Sigor@sysoev.ru 
757115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
758115Sigor@sysoev.ru         if (skcf == NULL) {
759133Sigor@sysoev.ru             goto fail;
760115Sigor@sysoev.ru         }
76153Sigor@sysoev.ru 
762136Svbart@nginx.com         ret = nxt_conf_map_object(listener, nxt_router_listener_conf,
763136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
764115Sigor@sysoev.ru         if (ret != NXT_OK) {
765115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
766133Sigor@sysoev.ru             goto fail;
767115Sigor@sysoev.ru         }
76853Sigor@sysoev.ru 
769133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
770133Sigor@sysoev.ru 
771133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
772133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
773133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
774133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
77553Sigor@sysoev.ru 
776133Sigor@sysoev.ru         if (http != NULL) {
777136Svbart@nginx.com             ret = nxt_conf_map_object(http, nxt_router_http_conf,
778136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
779133Sigor@sysoev.ru             if (ret != NXT_OK) {
780133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
781133Sigor@sysoev.ru                 goto fail;
782133Sigor@sysoev.ru             }
783115Sigor@sysoev.ru         }
784115Sigor@sysoev.ru 
785115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
786115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
787160Sigor@sysoev.ru         skcf->router_conf->count++;
788133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
789133Sigor@sysoev.ru                                                             &lscf.application);
790115Sigor@sysoev.ru 
791115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
792115Sigor@sysoev.ru     }
79353Sigor@sysoev.ru 
79453Sigor@sysoev.ru     return NXT_OK;
795133Sigor@sysoev.ru 
796133Sigor@sysoev.ru app_fail:
797133Sigor@sysoev.ru 
798133Sigor@sysoev.ru     nxt_free(app);
799133Sigor@sysoev.ru 
800133Sigor@sysoev.ru fail:
801133Sigor@sysoev.ru 
802141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
803141Smax.romanov@nginx.com 
804141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
805133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
806133Sigor@sysoev.ru         nxt_free(app);
807141Smax.romanov@nginx.com 
808141Smax.romanov@nginx.com     } nxt_queue_loop;
809133Sigor@sysoev.ru 
810133Sigor@sysoev.ru     return NXT_ERROR;
811133Sigor@sysoev.ru }
812133Sigor@sysoev.ru 
813133Sigor@sysoev.ru 
814133Sigor@sysoev.ru static nxt_app_t *
815133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
816133Sigor@sysoev.ru {
817141Smax.romanov@nginx.com     nxt_app_t  *app;
818141Smax.romanov@nginx.com 
819141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
820133Sigor@sysoev.ru 
821133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
822133Sigor@sysoev.ru             return app;
823133Sigor@sysoev.ru         }
824141Smax.romanov@nginx.com 
825141Smax.romanov@nginx.com     } nxt_queue_loop;
826133Sigor@sysoev.ru 
827133Sigor@sysoev.ru     return NULL;
828133Sigor@sysoev.ru }
829133Sigor@sysoev.ru 
830133Sigor@sysoev.ru 
831133Sigor@sysoev.ru static nxt_app_t *
832133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
833133Sigor@sysoev.ru {
834133Sigor@sysoev.ru     nxt_app_t  *app;
835133Sigor@sysoev.ru 
836133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
837133Sigor@sysoev.ru 
838133Sigor@sysoev.ru     if (app == NULL) {
839134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
840133Sigor@sysoev.ru     }
841133Sigor@sysoev.ru 
842133Sigor@sysoev.ru     return app;
84353Sigor@sysoev.ru }
84453Sigor@sysoev.ru 
84553Sigor@sysoev.ru 
84653Sigor@sysoev.ru static nxt_socket_conf_t *
84765Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
84853Sigor@sysoev.ru {
849163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
850163Smax.romanov@nginx.com 
851163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
852163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
85353Sigor@sysoev.ru         return NULL;
85453Sigor@sysoev.ru     }
85553Sigor@sysoev.ru 
856163Smax.romanov@nginx.com     skcf->sockaddr = sa;
857163Smax.romanov@nginx.com 
858163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
859163Smax.romanov@nginx.com     skcf->listen.socklen = sa->socklen;
860163Smax.romanov@nginx.com     skcf->listen.address_length = sa->length;
861163Smax.romanov@nginx.com 
862163Smax.romanov@nginx.com     skcf->listen.socket = -1;
863163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
864163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
865163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
866163Smax.romanov@nginx.com 
867163Smax.romanov@nginx.com     return skcf;
86853Sigor@sysoev.ru }
86953Sigor@sysoev.ru 
87053Sigor@sysoev.ru 
87153Sigor@sysoev.ru static void
87253Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
87353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
87453Sigor@sysoev.ru {
87553Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
87653Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
87753Sigor@sysoev.ru 
87853Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
87953Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
88053Sigor@sysoev.ru          nqlk = next)
88153Sigor@sysoev.ru     {
88253Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
88353Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
88453Sigor@sysoev.ru 
88553Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
88653Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
88753Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
88853Sigor@sysoev.ru         {
88953Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
89053Sigor@sysoev.ru 
891115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
892115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
893115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
894115Sigor@sysoev.ru 
89553Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
89653Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
89753Sigor@sysoev.ru 
89853Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
89953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
90053Sigor@sysoev.ru 
90153Sigor@sysoev.ru                 break;
90253Sigor@sysoev.ru             }
90353Sigor@sysoev.ru         }
90453Sigor@sysoev.ru     }
90553Sigor@sysoev.ru 
90653Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
907115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
90853Sigor@sysoev.ru }
90953Sigor@sysoev.ru 
91053Sigor@sysoev.ru 
91153Sigor@sysoev.ru static nxt_int_t
91253Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task,
91353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
91453Sigor@sysoev.ru {
915115Sigor@sysoev.ru     nxt_int_t            ret;
916115Sigor@sysoev.ru     nxt_socket_t         s;
917115Sigor@sysoev.ru     nxt_queue_link_t     *qlk, *nqlk;
918115Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
919115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
92053Sigor@sysoev.ru 
92153Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->pending);
92253Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->pending);
92353Sigor@sysoev.ru          qlk = nqlk)
92453Sigor@sysoev.ru     {
925115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
926115Sigor@sysoev.ru 
927115Sigor@sysoev.ru         s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK);
928115Sigor@sysoev.ru         if (nxt_slow_path(s == -1)) {
929115Sigor@sysoev.ru             return NXT_ERROR;
930115Sigor@sysoev.ru         }
931115Sigor@sysoev.ru 
932115Sigor@sysoev.ru         ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
933115Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
934148Sigor@sysoev.ru             goto fail;
935115Sigor@sysoev.ru         }
936115Sigor@sysoev.ru 
937115Sigor@sysoev.ru         skcf->listen.socket = s;
938115Sigor@sysoev.ru 
939148Sigor@sysoev.ru         rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
940148Sigor@sysoev.ru         if (nxt_slow_path(rtsk == NULL)) {
941148Sigor@sysoev.ru             goto fail;
942148Sigor@sysoev.ru         }
943148Sigor@sysoev.ru 
944148Sigor@sysoev.ru         rtsk->count = 0;
945148Sigor@sysoev.ru         rtsk->fd = skcf->listen.socket;
946148Sigor@sysoev.ru         skcf->socket = rtsk;
947115Sigor@sysoev.ru 
94853Sigor@sysoev.ru         nqlk = nxt_queue_next(qlk);
94953Sigor@sysoev.ru         nxt_queue_remove(qlk);
95053Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
95153Sigor@sysoev.ru     }
95253Sigor@sysoev.ru 
95353Sigor@sysoev.ru     return NXT_OK;
954148Sigor@sysoev.ru 
955148Sigor@sysoev.ru fail:
956148Sigor@sysoev.ru 
957148Sigor@sysoev.ru     nxt_socket_close(task, s);
958148Sigor@sysoev.ru 
959148Sigor@sysoev.ru     return NXT_ERROR;
96053Sigor@sysoev.ru }
96153Sigor@sysoev.ru 
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru static nxt_int_t
96453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
96553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
96653Sigor@sysoev.ru {
96753Sigor@sysoev.ru     nxt_int_t                 ret;
96853Sigor@sysoev.ru     nxt_uint_t                n, threads;
96953Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
97053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
97153Sigor@sysoev.ru 
97253Sigor@sysoev.ru     threads = tmcf->conf->threads;
97353Sigor@sysoev.ru 
97453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
97553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
97653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
97753Sigor@sysoev.ru         return NXT_ERROR;
97853Sigor@sysoev.ru     }
97953Sigor@sysoev.ru 
98053Sigor@sysoev.ru     n = 0;
98153Sigor@sysoev.ru 
98253Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
98353Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
98453Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
98553Sigor@sysoev.ru     {
98653Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
98753Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
98853Sigor@sysoev.ru             return NXT_ERROR;
98953Sigor@sysoev.ru         }
99053Sigor@sysoev.ru 
991115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
99253Sigor@sysoev.ru 
99353Sigor@sysoev.ru         if (n < threads) {
994115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
99553Sigor@sysoev.ru 
99653Sigor@sysoev.ru         } else {
997115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
99853Sigor@sysoev.ru         }
99953Sigor@sysoev.ru 
100053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
100153Sigor@sysoev.ru             return ret;
100253Sigor@sysoev.ru         }
100353Sigor@sysoev.ru 
100453Sigor@sysoev.ru         n++;
100553Sigor@sysoev.ru     }
100653Sigor@sysoev.ru 
100753Sigor@sysoev.ru     tmcf->new_threads = n;
100853Sigor@sysoev.ru 
100953Sigor@sysoev.ru     while (n < threads) {
101053Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
101153Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
101253Sigor@sysoev.ru             return NXT_ERROR;
101353Sigor@sysoev.ru         }
101453Sigor@sysoev.ru 
101553Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
101653Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
101753Sigor@sysoev.ru             return NXT_ERROR;
101853Sigor@sysoev.ru         }
101953Sigor@sysoev.ru 
1020115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
102153Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
102253Sigor@sysoev.ru             return ret;
102353Sigor@sysoev.ru         }
102453Sigor@sysoev.ru 
1025115Sigor@sysoev.ru         nxt_queue_insert_tail(&router->engines, &recf->engine->link0);
1026115Sigor@sysoev.ru 
102753Sigor@sysoev.ru         n++;
102853Sigor@sysoev.ru     }
102953Sigor@sysoev.ru 
103053Sigor@sysoev.ru     return NXT_OK;
103153Sigor@sysoev.ru }
103253Sigor@sysoev.ru 
103353Sigor@sysoev.ru 
103453Sigor@sysoev.ru static nxt_int_t
1035115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1036115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
103753Sigor@sysoev.ru {
1038115Sigor@sysoev.ru     nxt_int_t              ret;
1039115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
104053Sigor@sysoev.ru 
1041154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1042154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1043115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1044115Sigor@sysoev.ru         return ret;
1045115Sigor@sysoev.ru     }
1046115Sigor@sysoev.ru 
1047154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1048154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
104953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
105053Sigor@sysoev.ru         return ret;
105153Sigor@sysoev.ru     }
105253Sigor@sysoev.ru 
1053115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1054115Sigor@sysoev.ru 
1055115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1056115Sigor@sysoev.ru 
1057115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1058115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1059115Sigor@sysoev.ru 
1060115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1061115Sigor@sysoev.ru 
1062115Sigor@sysoev.ru     return ret;
106353Sigor@sysoev.ru }
106453Sigor@sysoev.ru 
106553Sigor@sysoev.ru 
106653Sigor@sysoev.ru static nxt_int_t
1067115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1068115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
106953Sigor@sysoev.ru {
1070115Sigor@sysoev.ru     nxt_int_t              ret;
1071115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
107253Sigor@sysoev.ru 
1073154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1074154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
107553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
107653Sigor@sysoev.ru         return ret;
107753Sigor@sysoev.ru     }
107853Sigor@sysoev.ru 
1079154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1080154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
108153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
108253Sigor@sysoev.ru         return ret;
108353Sigor@sysoev.ru     }
108453Sigor@sysoev.ru 
1085139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1086115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1087115Sigor@sysoev.ru         return ret;
1088115Sigor@sysoev.ru     }
1089115Sigor@sysoev.ru 
1090115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1091115Sigor@sysoev.ru 
1092115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1093115Sigor@sysoev.ru 
1094115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1095115Sigor@sysoev.ru 
1096115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1097115Sigor@sysoev.ru 
1098115Sigor@sysoev.ru     return ret;
109953Sigor@sysoev.ru }
110053Sigor@sysoev.ru 
110153Sigor@sysoev.ru 
110253Sigor@sysoev.ru static nxt_int_t
1103115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1104115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
110553Sigor@sysoev.ru {
110653Sigor@sysoev.ru     nxt_int_t  ret;
110753Sigor@sysoev.ru 
1108139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
110953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
111053Sigor@sysoev.ru         return ret;
111153Sigor@sysoev.ru     }
111253Sigor@sysoev.ru 
1113139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
111453Sigor@sysoev.ru }
111553Sigor@sysoev.ru 
111653Sigor@sysoev.ru 
111753Sigor@sysoev.ru static nxt_int_t
1118154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1119154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
112053Sigor@sysoev.ru     nxt_work_handler_t handler)
112153Sigor@sysoev.ru {
1122153Sigor@sysoev.ru     nxt_joint_job_t          *job;
112353Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1124155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
112553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
112653Sigor@sysoev.ru 
112753Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
112853Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
112953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
113053Sigor@sysoev.ru     {
1131154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1132153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1133139Sigor@sysoev.ru             return NXT_ERROR;
1134139Sigor@sysoev.ru         }
1135139Sigor@sysoev.ru 
1136154Sigor@sysoev.ru         job->work.next = recf->jobs;
1137154Sigor@sysoev.ru         recf->jobs = &job->work;
1138154Sigor@sysoev.ru 
1139153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1140153Sigor@sysoev.ru         job->work.handler = handler;
1141153Sigor@sysoev.ru         job->work.task = &job->task;
1142153Sigor@sysoev.ru         job->work.obj = job;
1143153Sigor@sysoev.ru         job->tmcf = tmcf;
114453Sigor@sysoev.ru 
1145154Sigor@sysoev.ru         tmcf->count++;
1146154Sigor@sysoev.ru 
1147154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1148154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
114953Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
115053Sigor@sysoev.ru             return NXT_ERROR;
115153Sigor@sysoev.ru         }
115253Sigor@sysoev.ru 
1153153Sigor@sysoev.ru         job->work.data = joint;
115453Sigor@sysoev.ru 
115553Sigor@sysoev.ru         joint->count = 1;
1156155Sigor@sysoev.ru 
1157155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1158155Sigor@sysoev.ru         skcf->count++;
1159155Sigor@sysoev.ru         joint->socket_conf = skcf;
1160155Sigor@sysoev.ru 
116188Smax.romanov@nginx.com         joint->engine = recf->engine;
116253Sigor@sysoev.ru     }
116353Sigor@sysoev.ru 
116420Sigor@sysoev.ru     return NXT_OK;
116520Sigor@sysoev.ru }
116620Sigor@sysoev.ru 
116720Sigor@sysoev.ru 
1168115Sigor@sysoev.ru static void
1169115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1170115Sigor@sysoev.ru {
1171115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1172115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1173115Sigor@sysoev.ru 
1174115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1175115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1176115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1177115Sigor@sysoev.ru     {
1178115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1179115Sigor@sysoev.ru         skcf->socket->count++;
1180115Sigor@sysoev.ru     }
1181115Sigor@sysoev.ru }
1182115Sigor@sysoev.ru 
1183115Sigor@sysoev.ru 
118420Sigor@sysoev.ru static nxt_int_t
1185139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1186139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
118720Sigor@sysoev.ru {
1188153Sigor@sysoev.ru     nxt_joint_job_t   *job;
118953Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
119020Sigor@sysoev.ru 
119153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
119253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
119353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
119453Sigor@sysoev.ru     {
1195154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1196153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1197139Sigor@sysoev.ru             return NXT_ERROR;
1198139Sigor@sysoev.ru         }
1199139Sigor@sysoev.ru 
1200154Sigor@sysoev.ru         job->work.next = recf->jobs;
1201154Sigor@sysoev.ru         recf->jobs = &job->work;
1202154Sigor@sysoev.ru 
1203153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1204153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1205153Sigor@sysoev.ru         job->work.task = &job->task;
1206153Sigor@sysoev.ru         job->work.obj = job;
1207153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1208153Sigor@sysoev.ru         job->tmcf = tmcf;
1209154Sigor@sysoev.ru 
1210154Sigor@sysoev.ru         tmcf->count++;
121120Sigor@sysoev.ru     }
121220Sigor@sysoev.ru 
121353Sigor@sysoev.ru     return NXT_OK;
121453Sigor@sysoev.ru }
121520Sigor@sysoev.ru 
121620Sigor@sysoev.ru 
121753Sigor@sysoev.ru static nxt_int_t
121853Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
121953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
122053Sigor@sysoev.ru {
122153Sigor@sysoev.ru     nxt_int_t                 ret;
122253Sigor@sysoev.ru     nxt_uint_t                i, threads;
122353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
122420Sigor@sysoev.ru 
122553Sigor@sysoev.ru     recf = tmcf->engines->elts;
122653Sigor@sysoev.ru     threads = tmcf->conf->threads;
122720Sigor@sysoev.ru 
122853Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
122953Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
123053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
123153Sigor@sysoev.ru             return ret;
123253Sigor@sysoev.ru         }
123320Sigor@sysoev.ru     }
123420Sigor@sysoev.ru 
123520Sigor@sysoev.ru     return NXT_OK;
123620Sigor@sysoev.ru }
123753Sigor@sysoev.ru 
123853Sigor@sysoev.ru 
123953Sigor@sysoev.ru static nxt_int_t
124053Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
124153Sigor@sysoev.ru     nxt_event_engine_t *engine)
124253Sigor@sysoev.ru {
124353Sigor@sysoev.ru     nxt_int_t            ret;
124453Sigor@sysoev.ru     nxt_thread_link_t    *link;
124553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
124653Sigor@sysoev.ru 
124753Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
124853Sigor@sysoev.ru 
124953Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
125053Sigor@sysoev.ru         return NXT_ERROR;
125153Sigor@sysoev.ru     }
125253Sigor@sysoev.ru 
125353Sigor@sysoev.ru     link->start = nxt_router_thread_start;
125453Sigor@sysoev.ru     link->engine = engine;
125553Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
125653Sigor@sysoev.ru     link->work.task = task;
125753Sigor@sysoev.ru     link->work.data = link;
125853Sigor@sysoev.ru 
125953Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
126053Sigor@sysoev.ru 
126153Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
126253Sigor@sysoev.ru 
126353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
126453Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
126553Sigor@sysoev.ru     }
126653Sigor@sysoev.ru 
126753Sigor@sysoev.ru     return ret;
126853Sigor@sysoev.ru }
126953Sigor@sysoev.ru 
127053Sigor@sysoev.ru 
127153Sigor@sysoev.ru static void
1272133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1273133Sigor@sysoev.ru {
1274167Smax.romanov@nginx.com     nxt_app_t    *app;
1275167Smax.romanov@nginx.com     nxt_port_t   *port;
1276141Smax.romanov@nginx.com 
1277141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1278133Sigor@sysoev.ru 
1279133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1280133Sigor@sysoev.ru 
1281167Smax.romanov@nginx.com         nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app);
1282167Smax.romanov@nginx.com 
1283163Smax.romanov@nginx.com         app->live = 0;
1284163Smax.romanov@nginx.com 
1285167Smax.romanov@nginx.com         if (nxt_router_app_free(NULL, app) != 0) {
1286163Smax.romanov@nginx.com             continue;
1287163Smax.romanov@nginx.com         }
1288163Smax.romanov@nginx.com 
1289167Smax.romanov@nginx.com         if (!nxt_queue_is_empty(&app->requests)) {
1290167Smax.romanov@nginx.com 
1291167Smax.romanov@nginx.com             nxt_thread_log_debug("app '%V' %p pending requests found",
1292167Smax.romanov@nginx.com                                  &app->name, app);
1293167Smax.romanov@nginx.com             continue;
1294163Smax.romanov@nginx.com         }
1295163Smax.romanov@nginx.com 
1296167Smax.romanov@nginx.com         do {
1297167Smax.romanov@nginx.com             port = nxt_router_app_get_port(app, 0);
1298167Smax.romanov@nginx.com             if (port == NULL) {
1299167Smax.romanov@nginx.com                 break;
1300167Smax.romanov@nginx.com             }
1301167Smax.romanov@nginx.com 
1302167Smax.romanov@nginx.com             nxt_thread_log_debug("port %p send quit", port);
1303167Smax.romanov@nginx.com 
1304167Smax.romanov@nginx.com             nxt_port_socket_write(&port->engine->task, port,
1305167Smax.romanov@nginx.com                                   NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
1306167Smax.romanov@nginx.com         } while (1);
1307167Smax.romanov@nginx.com 
1308141Smax.romanov@nginx.com     } nxt_queue_loop;
1309133Sigor@sysoev.ru 
1310133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1311133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1312133Sigor@sysoev.ru }
1313133Sigor@sysoev.ru 
1314133Sigor@sysoev.ru 
1315133Sigor@sysoev.ru static void
131653Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf)
131753Sigor@sysoev.ru {
131853Sigor@sysoev.ru     nxt_uint_t                n;
131953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
132053Sigor@sysoev.ru 
132153Sigor@sysoev.ru     recf = tmcf->engines->elts;
132253Sigor@sysoev.ru 
132353Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1324154Sigor@sysoev.ru         nxt_router_engine_post(recf);
132553Sigor@sysoev.ru         recf++;
132653Sigor@sysoev.ru     }
132753Sigor@sysoev.ru }
132853Sigor@sysoev.ru 
132953Sigor@sysoev.ru 
133053Sigor@sysoev.ru static void
1331154Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf)
133253Sigor@sysoev.ru {
1333154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1334154Sigor@sysoev.ru 
1335154Sigor@sysoev.ru     for (work = recf->jobs; work != NULL; work = next) {
1336154Sigor@sysoev.ru         next = work->next;
1337154Sigor@sysoev.ru         work->next = NULL;
1338154Sigor@sysoev.ru 
1339154Sigor@sysoev.ru         nxt_event_engine_post(recf->engine, work);
134053Sigor@sysoev.ru     }
134153Sigor@sysoev.ru }
134253Sigor@sysoev.ru 
134353Sigor@sysoev.ru 
134453Sigor@sysoev.ru static void
1345119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
134688Smax.romanov@nginx.com 
1347119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
1348192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_QUIT         */
1349192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_NEW_PORT     */
1350192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_CHANGE_FILE  */
1351192Smax.romanov@nginx.com     /* TODO: remove mmap_handler from app ports */
1352192Smax.romanov@nginx.com     nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP         */
1353119Smax.romanov@nginx.com     nxt_router_app_data_handler,
1354192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_REMOVE_PID   */
1355192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_READY        */
1356192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_START_WORKER */
1357190Smax.romanov@nginx.com     nxt_port_rpc_handler,
1358190Smax.romanov@nginx.com     nxt_port_rpc_handler,
135988Smax.romanov@nginx.com };
136088Smax.romanov@nginx.com 
136188Smax.romanov@nginx.com 
136288Smax.romanov@nginx.com static void
136353Sigor@sysoev.ru nxt_router_thread_start(void *data)
136453Sigor@sysoev.ru {
1365141Smax.romanov@nginx.com     nxt_int_t           ret;
1366141Smax.romanov@nginx.com     nxt_port_t          *port;
136788Smax.romanov@nginx.com     nxt_task_t          *task;
136853Sigor@sysoev.ru     nxt_thread_t        *thread;
136953Sigor@sysoev.ru     nxt_thread_link_t   *link;
137053Sigor@sysoev.ru     nxt_event_engine_t  *engine;
137153Sigor@sysoev.ru 
137253Sigor@sysoev.ru     link = data;
137353Sigor@sysoev.ru     engine = link->engine;
137488Smax.romanov@nginx.com     task = &engine->task;
137553Sigor@sysoev.ru 
137653Sigor@sysoev.ru     thread = nxt_thread();
137753Sigor@sysoev.ru 
1378165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1379165Smax.romanov@nginx.com 
138053Sigor@sysoev.ru     /* STUB */
138153Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
138253Sigor@sysoev.ru 
138353Sigor@sysoev.ru     engine->task.thread = thread;
138453Sigor@sysoev.ru     engine->task.log = thread->log;
138553Sigor@sysoev.ru     thread->engine = engine;
138663Sigor@sysoev.ru     thread->task = &engine->task;
138753Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
138853Sigor@sysoev.ru 
138963Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
139053Sigor@sysoev.ru 
1391163Smax.romanov@nginx.com     port = nxt_port_new(nxt_port_get_next_id(), nxt_pid, NXT_PROCESS_ROUTER);
1392141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1393141Smax.romanov@nginx.com         return;
1394141Smax.romanov@nginx.com     }
1395141Smax.romanov@nginx.com 
1396141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1397141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1398163Smax.romanov@nginx.com         nxt_mp_release(port->mem_pool, port);
1399141Smax.romanov@nginx.com         return;
1400141Smax.romanov@nginx.com     }
1401141Smax.romanov@nginx.com 
1402141Smax.romanov@nginx.com     engine->port = port;
1403141Smax.romanov@nginx.com 
1404141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1405141Smax.romanov@nginx.com 
140653Sigor@sysoev.ru     nxt_event_engine_start(engine);
140753Sigor@sysoev.ru }
140853Sigor@sysoev.ru 
140953Sigor@sysoev.ru 
141053Sigor@sysoev.ru static void
141153Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
141253Sigor@sysoev.ru {
1413153Sigor@sysoev.ru     nxt_joint_job_t          *job;
141453Sigor@sysoev.ru     nxt_listen_event_t       *listen;
141553Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
141653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
141753Sigor@sysoev.ru 
1418153Sigor@sysoev.ru     job = obj;
141953Sigor@sysoev.ru     joint = data;
142053Sigor@sysoev.ru 
142153Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
142253Sigor@sysoev.ru 
1423159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1424159Sigor@sysoev.ru 
142553Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
142653Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
142753Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
142853Sigor@sysoev.ru         return;
142953Sigor@sysoev.ru     }
143053Sigor@sysoev.ru 
143153Sigor@sysoev.ru     listen->socket.data = joint;
1432139Sigor@sysoev.ru 
1433153Sigor@sysoev.ru     job->work.next = NULL;
1434153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1435153Sigor@sysoev.ru 
1436153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
143753Sigor@sysoev.ru }
143853Sigor@sysoev.ru 
143953Sigor@sysoev.ru 
144053Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
144153Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
144253Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
144353Sigor@sysoev.ru {
1444115Sigor@sysoev.ru     nxt_socket_t        fd;
1445115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
144653Sigor@sysoev.ru     nxt_listen_event_t  *listen;
144753Sigor@sysoev.ru 
1448115Sigor@sysoev.ru     fd = skcf->socket->fd;
144953Sigor@sysoev.ru 
1450115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1451115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1452115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
145353Sigor@sysoev.ru     {
1454115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
145553Sigor@sysoev.ru 
1456115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
145753Sigor@sysoev.ru             return listen;
145853Sigor@sysoev.ru         }
145953Sigor@sysoev.ru     }
146053Sigor@sysoev.ru 
146153Sigor@sysoev.ru     return NULL;
146253Sigor@sysoev.ru }
146353Sigor@sysoev.ru 
146453Sigor@sysoev.ru 
146553Sigor@sysoev.ru static void
146653Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
146753Sigor@sysoev.ru {
1468153Sigor@sysoev.ru     nxt_joint_job_t          *job;
146953Sigor@sysoev.ru     nxt_event_engine_t       *engine;
147053Sigor@sysoev.ru     nxt_listen_event_t       *listen;
147153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
147253Sigor@sysoev.ru 
1473153Sigor@sysoev.ru     job = obj;
147453Sigor@sysoev.ru     joint = data;
147553Sigor@sysoev.ru 
1476139Sigor@sysoev.ru     engine = task->thread->engine;
1477139Sigor@sysoev.ru 
1478159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
1479159Sigor@sysoev.ru 
148053Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
148153Sigor@sysoev.ru                                      joint->socket_conf);
148253Sigor@sysoev.ru 
148353Sigor@sysoev.ru     old = listen->socket.data;
148453Sigor@sysoev.ru     listen->socket.data = joint;
1485177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
148653Sigor@sysoev.ru 
1487153Sigor@sysoev.ru     job->work.next = NULL;
1488153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1489153Sigor@sysoev.ru 
1490153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
1491139Sigor@sysoev.ru 
1492181Smax.romanov@nginx.com     /*
1493181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
1494181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
1495181Smax.romanov@nginx.com      */
1496181Smax.romanov@nginx.com 
1497181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
149853Sigor@sysoev.ru }
149953Sigor@sysoev.ru 
150053Sigor@sysoev.ru 
150153Sigor@sysoev.ru static void
150253Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
150353Sigor@sysoev.ru {
1504153Sigor@sysoev.ru     nxt_joint_job_t     *job;
1505153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
1506153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
1507153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1508153Sigor@sysoev.ru 
1509153Sigor@sysoev.ru     job = obj;
151053Sigor@sysoev.ru     skcf = data;
151153Sigor@sysoev.ru 
1512139Sigor@sysoev.ru     engine = task->thread->engine;
1513139Sigor@sysoev.ru 
151453Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
151553Sigor@sysoev.ru 
151653Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
151753Sigor@sysoev.ru 
1518163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
1519163Smax.romanov@nginx.com               listen->socket.fd);
1520163Smax.romanov@nginx.com 
152153Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
152253Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
152353Sigor@sysoev.ru 
152453Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1525139Sigor@sysoev.ru 
1526153Sigor@sysoev.ru     job->work.next = NULL;
1527153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1528153Sigor@sysoev.ru 
1529153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
153053Sigor@sysoev.ru }
153153Sigor@sysoev.ru 
153253Sigor@sysoev.ru 
153353Sigor@sysoev.ru static void
153453Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
153553Sigor@sysoev.ru {
153653Sigor@sysoev.ru     nxt_timer_t              *timer;
153753Sigor@sysoev.ru     nxt_listen_event_t       *listen;
153853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
153953Sigor@sysoev.ru 
154053Sigor@sysoev.ru     timer = obj;
154153Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
154253Sigor@sysoev.ru     joint = listen->socket.data;
154353Sigor@sysoev.ru 
1544163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
1545163Smax.romanov@nginx.com               listen->socket.fd);
1546163Smax.romanov@nginx.com 
154753Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
1548123Smax.romanov@nginx.com 
1549123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
1550123Smax.romanov@nginx.com     task = &task->thread->engine->task;
1551123Smax.romanov@nginx.com 
155253Sigor@sysoev.ru     nxt_free(listen);
155353Sigor@sysoev.ru 
155453Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
155553Sigor@sysoev.ru }
155653Sigor@sysoev.ru 
155753Sigor@sysoev.ru 
155853Sigor@sysoev.ru static void
155953Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
156053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
156153Sigor@sysoev.ru {
1562118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
1563115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
156453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
156553Sigor@sysoev.ru 
1566118Sigor@sysoev.ru     skcf = joint->socket_conf;
1567118Sigor@sysoev.ru     rtsk = skcf->socket;
1568118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
156953Sigor@sysoev.ru 
157053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
157153Sigor@sysoev.ru 
1572163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
1573163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
1574163Smax.romanov@nginx.com 
1575115Sigor@sysoev.ru     if (--rtsk->count != 0) {
1576115Sigor@sysoev.ru         rtsk = NULL;
157753Sigor@sysoev.ru     }
157853Sigor@sysoev.ru 
157953Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
158053Sigor@sysoev.ru 
1581115Sigor@sysoev.ru     if (rtsk != NULL) {
1582115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
1583115Sigor@sysoev.ru         nxt_free(rtsk);
1584118Sigor@sysoev.ru         skcf->socket = NULL;
158553Sigor@sysoev.ru     }
158653Sigor@sysoev.ru 
158753Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
158853Sigor@sysoev.ru }
158953Sigor@sysoev.ru 
159053Sigor@sysoev.ru 
159153Sigor@sysoev.ru static void
159253Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
159353Sigor@sysoev.ru {
1594156Sigor@sysoev.ru     nxt_bool_t             exit;
159553Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
159653Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
159753Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
159853Sigor@sysoev.ru 
1599163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
160053Sigor@sysoev.ru 
160153Sigor@sysoev.ru     if (--joint->count != 0) {
160253Sigor@sysoev.ru         return;
160353Sigor@sysoev.ru     }
160453Sigor@sysoev.ru 
160553Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
160653Sigor@sysoev.ru 
160753Sigor@sysoev.ru     skcf = joint->socket_conf;
160853Sigor@sysoev.ru     rtcf = skcf->router_conf;
160953Sigor@sysoev.ru     lock = &rtcf->router->lock;
161053Sigor@sysoev.ru 
161153Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
161253Sigor@sysoev.ru 
1613163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
1614163Smax.romanov@nginx.com               rtcf, rtcf->count);
1615163Smax.romanov@nginx.com 
161653Sigor@sysoev.ru     if (--skcf->count != 0) {
161753Sigor@sysoev.ru         rtcf = NULL;
161853Sigor@sysoev.ru 
161953Sigor@sysoev.ru     } else {
162053Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
162153Sigor@sysoev.ru 
162253Sigor@sysoev.ru         if (--rtcf->count != 0) {
162353Sigor@sysoev.ru             rtcf = NULL;
162453Sigor@sysoev.ru         }
162553Sigor@sysoev.ru     }
162653Sigor@sysoev.ru 
162753Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
162853Sigor@sysoev.ru 
1629141Smax.romanov@nginx.com     /* TODO remove engine->port */
1630141Smax.romanov@nginx.com     /* TODO excude from connected ports */
1631141Smax.romanov@nginx.com 
1632156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
1633156Sigor@sysoev.ru     exit = nxt_queue_is_empty(&joint->engine->joints);
1634156Sigor@sysoev.ru 
163553Sigor@sysoev.ru     if (rtcf != NULL) {
1636115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
1637131Smax.romanov@nginx.com 
1638131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
1639131Smax.romanov@nginx.com 
164065Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
164153Sigor@sysoev.ru     }
164253Sigor@sysoev.ru 
1643156Sigor@sysoev.ru     if (exit) {
164453Sigor@sysoev.ru         nxt_thread_exit(task->thread);
164553Sigor@sysoev.ru     }
164653Sigor@sysoev.ru }
164753Sigor@sysoev.ru 
164853Sigor@sysoev.ru 
164953Sigor@sysoev.ru static void
165053Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
165153Sigor@sysoev.ru {
1652141Smax.romanov@nginx.com     nxt_port_t           *port;
165353Sigor@sysoev.ru     nxt_thread_link_t    *link;
165453Sigor@sysoev.ru     nxt_event_engine_t   *engine;
165553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
165653Sigor@sysoev.ru 
165758Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
165853Sigor@sysoev.ru     link = data;
165953Sigor@sysoev.ru 
166053Sigor@sysoev.ru     nxt_thread_wait(handle);
166153Sigor@sysoev.ru 
166253Sigor@sysoev.ru     engine = link->engine;
166353Sigor@sysoev.ru 
166453Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
166553Sigor@sysoev.ru 
1666141Smax.romanov@nginx.com     port = engine->port;
1667141Smax.romanov@nginx.com 
1668141Smax.romanov@nginx.com     // TODO notify all apps
1669141Smax.romanov@nginx.com 
1670163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
1671163Smax.romanov@nginx.com     nxt_port_release(port);
1672163Smax.romanov@nginx.com 
1673163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
167463Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
167553Sigor@sysoev.ru 
167653Sigor@sysoev.ru     nxt_event_engine_free(engine);
167753Sigor@sysoev.ru 
167853Sigor@sysoev.ru     nxt_free(link);
167953Sigor@sysoev.ru }
168053Sigor@sysoev.ru 
168153Sigor@sysoev.ru 
168262Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_read_state
168353Sigor@sysoev.ru     nxt_aligned(64) =
168453Sigor@sysoev.ru {
168553Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
168653Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
168753Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
168853Sigor@sysoev.ru 
168953Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
169053Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
169153Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
169253Sigor@sysoev.ru };
169353Sigor@sysoev.ru 
169453Sigor@sysoev.ru 
169553Sigor@sysoev.ru static void
169653Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
169753Sigor@sysoev.ru {
169853Sigor@sysoev.ru     size_t                   size;
169962Sigor@sysoev.ru     nxt_conn_t               *c;
170053Sigor@sysoev.ru     nxt_event_engine_t       *engine;
170153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
170253Sigor@sysoev.ru 
170353Sigor@sysoev.ru     c = obj;
170453Sigor@sysoev.ru     joint = data;
170553Sigor@sysoev.ru 
170653Sigor@sysoev.ru     nxt_debug(task, "router conn init");
170753Sigor@sysoev.ru 
170853Sigor@sysoev.ru     joint->count++;
170953Sigor@sysoev.ru 
171053Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
171153Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
171253Sigor@sysoev.ru 
171353Sigor@sysoev.ru     c->socket.data = NULL;
171453Sigor@sysoev.ru 
171553Sigor@sysoev.ru     engine = task->thread->engine;
171653Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
171753Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
171853Sigor@sysoev.ru 
171953Sigor@sysoev.ru     c->read_state = &nxt_router_conn_read_state;
172053Sigor@sysoev.ru 
172162Sigor@sysoev.ru     nxt_conn_read(engine, c);
172253Sigor@sysoev.ru }
172353Sigor@sysoev.ru 
172453Sigor@sysoev.ru 
172562Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
172653Sigor@sysoev.ru     nxt_aligned(64) =
172753Sigor@sysoev.ru {
172888Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
172953Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
173053Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
173153Sigor@sysoev.ru };
173253Sigor@sysoev.ru 
173353Sigor@sysoev.ru 
173453Sigor@sysoev.ru static void
1735119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
173688Smax.romanov@nginx.com {
173788Smax.romanov@nginx.com     size_t               dump_size;
173888Smax.romanov@nginx.com     nxt_buf_t            *b, *i, *last;
173988Smax.romanov@nginx.com     nxt_conn_t           *c;
174088Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
174188Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
174288Smax.romanov@nginx.com 
174388Smax.romanov@nginx.com     b = msg->buf;
174488Smax.romanov@nginx.com     engine = task->thread->engine;
174588Smax.romanov@nginx.com 
174688Smax.romanov@nginx.com     rc = nxt_event_engine_request_find(engine, msg->port_msg.stream);
174788Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
174888Smax.romanov@nginx.com 
174988Smax.romanov@nginx.com         nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream);
175088Smax.romanov@nginx.com 
175195Smax.romanov@nginx.com         /* Mark buffers as read. */
175288Smax.romanov@nginx.com         for (i = b; i != NULL; i = i->next) {
175388Smax.romanov@nginx.com             i->mem.pos = i->mem.free;
175488Smax.romanov@nginx.com         }
175588Smax.romanov@nginx.com 
175688Smax.romanov@nginx.com         return;
175788Smax.romanov@nginx.com     }
175888Smax.romanov@nginx.com 
175988Smax.romanov@nginx.com     c = rc->conn;
176088Smax.romanov@nginx.com 
176188Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
176288Smax.romanov@nginx.com 
176388Smax.romanov@nginx.com     if (dump_size > 300) {
176488Smax.romanov@nginx.com         dump_size = 300;
176588Smax.romanov@nginx.com     }
176688Smax.romanov@nginx.com 
1767119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
176888Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
176988Smax.romanov@nginx.com               b->mem.pos);
177088Smax.romanov@nginx.com 
177188Smax.romanov@nginx.com     if (msg->size == 0) {
177288Smax.romanov@nginx.com         b = NULL;
177388Smax.romanov@nginx.com     }
177488Smax.romanov@nginx.com 
177588Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
177688Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
177788Smax.romanov@nginx.com 
177888Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
177988Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
178088Smax.romanov@nginx.com             /* TODO pogorevaTb */
178188Smax.romanov@nginx.com         }
178288Smax.romanov@nginx.com 
178388Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
1784167Smax.romanov@nginx.com 
1785167Smax.romanov@nginx.com         if (rc->app_port != NULL) {
1786167Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
1787167Smax.romanov@nginx.com 
1788167Smax.romanov@nginx.com             rc->app_port = NULL;
1789167Smax.romanov@nginx.com         }
179088Smax.romanov@nginx.com     }
179188Smax.romanov@nginx.com 
179288Smax.romanov@nginx.com     if (b == NULL) {
179388Smax.romanov@nginx.com         return;
179488Smax.romanov@nginx.com     }
179588Smax.romanov@nginx.com 
179688Smax.romanov@nginx.com     if (c->write == NULL) {
179788Smax.romanov@nginx.com         c->write = b;
179888Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
179988Smax.romanov@nginx.com 
180088Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
180188Smax.romanov@nginx.com     } else {
180288Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
180388Smax.romanov@nginx.com 
180488Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
180588Smax.romanov@nginx.com     }
180688Smax.romanov@nginx.com }
180788Smax.romanov@nginx.com 
1808141Smax.romanov@nginx.com nxt_inline const char *
1809141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
1810141Smax.romanov@nginx.com {
1811141Smax.romanov@nginx.com     switch (code) {
1812141Smax.romanov@nginx.com     case 400: return "Bad request";
1813141Smax.romanov@nginx.com     case 404: return "Not found";
1814141Smax.romanov@nginx.com     case 403: return "Forbidden";
1815141Smax.romanov@nginx.com     case 500:
1816141Smax.romanov@nginx.com     default:  return "Internal server error";
1817141Smax.romanov@nginx.com     }
1818141Smax.romanov@nginx.com }
1819141Smax.romanov@nginx.com 
1820163Smax.romanov@nginx.com 
1821163Smax.romanov@nginx.com static nxt_buf_t *
1822163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
1823163Smax.romanov@nginx.com     const char* fmt, va_list args)
182488Smax.romanov@nginx.com {
1825163Smax.romanov@nginx.com     nxt_buf_t   *b, *last;
1826163Smax.romanov@nginx.com     const char  *msg;
1827163Smax.romanov@nginx.com 
1828163Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, mp, 16384);
1829141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1830163Smax.romanov@nginx.com         return NULL;
1831141Smax.romanov@nginx.com     }
1832141Smax.romanov@nginx.com 
1833141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
1834141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
1835141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
1836141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
1837141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
1838141Smax.romanov@nginx.com 
1839141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
1840141Smax.romanov@nginx.com 
1841141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
1842141Smax.romanov@nginx.com 
1843141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
1844141Smax.romanov@nginx.com 
1845163Smax.romanov@nginx.com     last = nxt_buf_mem_ts_alloc(task, mp, 0);
1846163Smax.romanov@nginx.com 
1847141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
1848163Smax.romanov@nginx.com         nxt_mp_release(mp, b);
1849163Smax.romanov@nginx.com         return NULL;
1850141Smax.romanov@nginx.com     }
1851141Smax.romanov@nginx.com 
1852163Smax.romanov@nginx.com     nxt_buf_set_sync(last);
1853163Smax.romanov@nginx.com     nxt_buf_set_last(last);
1854163Smax.romanov@nginx.com 
1855141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
1856141Smax.romanov@nginx.com 
1857163Smax.romanov@nginx.com     return b;
1858163Smax.romanov@nginx.com }
1859163Smax.romanov@nginx.com 
1860163Smax.romanov@nginx.com 
1861163Smax.romanov@nginx.com 
1862163Smax.romanov@nginx.com static void
1863163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
1864163Smax.romanov@nginx.com     const char* fmt, ...)
1865163Smax.romanov@nginx.com {
1866163Smax.romanov@nginx.com     va_list    args;
1867163Smax.romanov@nginx.com     nxt_buf_t  *b;
1868163Smax.romanov@nginx.com 
1869163Smax.romanov@nginx.com     va_start(args, fmt);
1870163Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args);
1871163Smax.romanov@nginx.com     va_end(args);
1872163Smax.romanov@nginx.com 
1873141Smax.romanov@nginx.com     if (c->write == NULL) {
1874141Smax.romanov@nginx.com         c->write = b;
1875141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
1876141Smax.romanov@nginx.com 
1877141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
1878141Smax.romanov@nginx.com     } else {
1879141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
1880141Smax.romanov@nginx.com 
1881141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
1882141Smax.romanov@nginx.com     }
1883141Smax.romanov@nginx.com }
1884141Smax.romanov@nginx.com 
1885141Smax.romanov@nginx.com 
1886141Smax.romanov@nginx.com static void
1887192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
1888192Smax.romanov@nginx.com {
1889192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1890192Smax.romanov@nginx.com 
1891192Smax.romanov@nginx.com     sw = data;
1892192Smax.romanov@nginx.com 
1893192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
1894192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
1895192Smax.romanov@nginx.com 
1896192Smax.romanov@nginx.com     msg->new_port->app = sw->app;
1897192Smax.romanov@nginx.com 
1898192Smax.romanov@nginx.com     sw->app->pending_workers--;
1899192Smax.romanov@nginx.com     sw->app->workers++;
1900192Smax.romanov@nginx.com 
1901192Smax.romanov@nginx.com     nxt_debug(task, "sw %p got port %p", sw, msg->new_port);
1902192Smax.romanov@nginx.com 
1903192Smax.romanov@nginx.com     nxt_router_app_release_port(task, msg->new_port, sw->app);
1904192Smax.romanov@nginx.com 
1905192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
1906192Smax.romanov@nginx.com }
1907192Smax.romanov@nginx.com 
1908192Smax.romanov@nginx.com 
1909192Smax.romanov@nginx.com static void
1910192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
1911192Smax.romanov@nginx.com {
1912192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1913192Smax.romanov@nginx.com 
1914192Smax.romanov@nginx.com     sw = data;
1915192Smax.romanov@nginx.com 
1916192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
1917192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
1918192Smax.romanov@nginx.com 
1919192Smax.romanov@nginx.com     sw->app->pending_workers--;
1920192Smax.romanov@nginx.com 
1921192Smax.romanov@nginx.com     nxt_debug(task, "sw %p error, failed to start app '%V'", sw, &sw->app->name);
1922192Smax.romanov@nginx.com 
1923192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
1924192Smax.romanov@nginx.com }
1925192Smax.romanov@nginx.com 
1926192Smax.romanov@nginx.com 
1927192Smax.romanov@nginx.com static void
1928141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
1929141Smax.romanov@nginx.com {
1930174Sigor@sysoev.ru     size_t              size;
1931192Smax.romanov@nginx.com     uint32_t            stream;
1932141Smax.romanov@nginx.com     nxt_buf_t           *b;
1933141Smax.romanov@nginx.com     nxt_app_t           *app;
1934192Smax.romanov@nginx.com     nxt_port_t          *master_port, *router_port;
1935141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
1936141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
1937141Smax.romanov@nginx.com 
1938141Smax.romanov@nginx.com     sw = obj;
1939141Smax.romanov@nginx.com     app = sw->app;
1940141Smax.romanov@nginx.com 
1941167Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->ra->link);
1942167Smax.romanov@nginx.com 
1943163Smax.romanov@nginx.com     if (app->workers + app->pending_workers >= app->max_workers) {
1944167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p %uD/%uD running/penging workers, "
1945167Smax.romanov@nginx.com                   "post sw #%uxD release to %p", &app->name, app,
1946192Smax.romanov@nginx.com                   "sw %p release", &app->name, app,
1947192Smax.romanov@nginx.com                    app->workers, app->pending_workers, sw);
1948192Smax.romanov@nginx.com 
1949192Smax.romanov@nginx.com         nxt_router_sw_release(task, sw);
1950163Smax.romanov@nginx.com 
1951163Smax.romanov@nginx.com         return;
1952163Smax.romanov@nginx.com     }
1953163Smax.romanov@nginx.com 
1954163Smax.romanov@nginx.com     app->pending_workers++;
1955163Smax.romanov@nginx.com 
1956192Smax.romanov@nginx.com     nxt_debug(task, "sw %p send", sw);
195788Smax.romanov@nginx.com 
1958119Smax.romanov@nginx.com     rt = task->thread->runtime;
1959192Smax.romanov@nginx.com     master_port = rt->port_by_type[NXT_PROCESS_MASTER];
1960192Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1961141Smax.romanov@nginx.com 
1962174Sigor@sysoev.ru     size = app->name.length + 1 + app->conf.length;
1963174Sigor@sysoev.ru 
1964192Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(master_port->mem_pool, size, 0);
1965174Sigor@sysoev.ru 
1966174Sigor@sysoev.ru     nxt_buf_cpystr(b, &app->name);
1967174Sigor@sysoev.ru     *b->mem.free++ = '\0';
1968141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1969141Smax.romanov@nginx.com 
1970192Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
1971192Smax.romanov@nginx.com                                            nxt_router_sw_ready,
1972192Smax.romanov@nginx.com                                            nxt_router_sw_error,
1973192Smax.romanov@nginx.com                                            master_port->pid, sw);
1974192Smax.romanov@nginx.com 
1975192Smax.romanov@nginx.com     nxt_port_socket_write(task, master_port, NXT_PORT_MSG_START_WORKER, -1,
1976192Smax.romanov@nginx.com                           stream, router_port->id, b);
1977141Smax.romanov@nginx.com }
1978141Smax.romanov@nginx.com 
1979141Smax.romanov@nginx.com 
1980163Smax.romanov@nginx.com static nxt_bool_t
1981167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app)
1982163Smax.romanov@nginx.com {
1983192Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
1984192Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
1985167Smax.romanov@nginx.com 
1986167Smax.romanov@nginx.com     nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app,
1987167Smax.romanov@nginx.com                          app->live, app->workers, app->pending_workers,
1988167Smax.romanov@nginx.com                          nxt_queue_is_empty(&app->requests));
1989167Smax.romanov@nginx.com 
1990163Smax.romanov@nginx.com     if (app->live == 0 && app->workers == 0 &&
1991163Smax.romanov@nginx.com         app->pending_workers == 0 &&
1992163Smax.romanov@nginx.com         nxt_queue_is_empty(&app->requests)) {
1993163Smax.romanov@nginx.com 
1994163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
1995163Smax.romanov@nginx.com         nxt_free(app);
1996163Smax.romanov@nginx.com 
1997163Smax.romanov@nginx.com         return 1;
1998163Smax.romanov@nginx.com     }
1999163Smax.romanov@nginx.com 
2000167Smax.romanov@nginx.com     if (app->live == 1 && nxt_queue_is_empty(&app->requests) == 0 &&
2001167Smax.romanov@nginx.com        (app->workers + app->pending_workers < app->max_workers)) {
2002167Smax.romanov@nginx.com 
2003167Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2004167Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2005167Smax.romanov@nginx.com 
2006167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2007167Smax.romanov@nginx.com 
2008192Smax.romanov@nginx.com         nxt_router_sw_create(task, app, ra);
2009167Smax.romanov@nginx.com     }
2010167Smax.romanov@nginx.com 
2011163Smax.romanov@nginx.com     return 0;
2012163Smax.romanov@nginx.com }
2013163Smax.romanov@nginx.com 
2014163Smax.romanov@nginx.com 
2015141Smax.romanov@nginx.com static nxt_port_t *
2016167Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id)
2017141Smax.romanov@nginx.com {
2018141Smax.romanov@nginx.com     nxt_port_t        *port;
2019141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2020141Smax.romanov@nginx.com 
2021141Smax.romanov@nginx.com     port = NULL;
2022141Smax.romanov@nginx.com 
2023141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2024141Smax.romanov@nginx.com 
2025141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2026141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
2027141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2028141Smax.romanov@nginx.com 
2029141Smax.romanov@nginx.com         lnk->next = NULL;
2030141Smax.romanov@nginx.com 
2031141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2032167Smax.romanov@nginx.com 
2033167Smax.romanov@nginx.com         port->app_req_id = req_id;
2034141Smax.romanov@nginx.com     }
2035141Smax.romanov@nginx.com 
2036141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2037141Smax.romanov@nginx.com 
2038141Smax.romanov@nginx.com     return port;
2039141Smax.romanov@nginx.com }
2040141Smax.romanov@nginx.com 
2041141Smax.romanov@nginx.com 
2042141Smax.romanov@nginx.com static void
2043141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
2044141Smax.romanov@nginx.com {
2045141Smax.romanov@nginx.com     nxt_app_t            *app;
2046141Smax.romanov@nginx.com     nxt_port_t           *port;
2047141Smax.romanov@nginx.com     nxt_work_t           *work;
2048141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
2049167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
2050141Smax.romanov@nginx.com 
2051141Smax.romanov@nginx.com     port = obj;
2052141Smax.romanov@nginx.com     app = data;
2053141Smax.romanov@nginx.com 
2054141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2055141Smax.romanov@nginx.com     nxt_assert(app == port->app);
2056141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
2057141Smax.romanov@nginx.com 
2058141Smax.romanov@nginx.com 
2059141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
2060163Smax.romanov@nginx.com         work = &port->work;
2061141Smax.romanov@nginx.com 
2062141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
2063141Smax.romanov@nginx.com 
2064141Smax.romanov@nginx.com         work->next = NULL;
2065141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
2066166Smax.romanov@nginx.com         work->task = &port->engine->task;
2067141Smax.romanov@nginx.com         work->obj = port;
2068141Smax.romanov@nginx.com         work->data = app;
2069141Smax.romanov@nginx.com 
2070141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
2071141Smax.romanov@nginx.com 
2072141Smax.romanov@nginx.com         return;
2073141Smax.romanov@nginx.com     }
2074141Smax.romanov@nginx.com 
2075141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2076141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2077141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2078141Smax.romanov@nginx.com 
2079167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2080167Smax.romanov@nginx.com 
2081167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p process next request #%uxD",
2082167Smax.romanov@nginx.com                   &app->name, app, ra->req_id);
2083167Smax.romanov@nginx.com 
2084167Smax.romanov@nginx.com         ra->app_port = port;
2085182Smax.romanov@nginx.com         port->app_req_id = ra->req_id;
2086167Smax.romanov@nginx.com 
2087167Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, ra, port);
2088167Smax.romanov@nginx.com 
2089167Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
2090141Smax.romanov@nginx.com 
2091141Smax.romanov@nginx.com         return;
2092141Smax.romanov@nginx.com     }
2093141Smax.romanov@nginx.com 
2094167Smax.romanov@nginx.com     port->app_req_id = 0;
2095167Smax.romanov@nginx.com 
2096163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2097167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)",
2098167Smax.romanov@nginx.com                   &app->name, app, port->pid);
2099163Smax.romanov@nginx.com 
2100163Smax.romanov@nginx.com         app->workers--;
2101167Smax.romanov@nginx.com         nxt_router_app_free(task, app);
2102163Smax.romanov@nginx.com 
2103163Smax.romanov@nginx.com         port->app = NULL;
2104163Smax.romanov@nginx.com 
2105163Smax.romanov@nginx.com         nxt_port_release(port);
2106163Smax.romanov@nginx.com 
2107163Smax.romanov@nginx.com         return;
2108163Smax.romanov@nginx.com     }
2109163Smax.romanov@nginx.com 
2110163Smax.romanov@nginx.com     if (!app->live) {
2111167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2112167Smax.romanov@nginx.com                   &app->name, app);
2113163Smax.romanov@nginx.com 
2114163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2115163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2116163Smax.romanov@nginx.com 
2117163Smax.romanov@nginx.com         return;
2118163Smax.romanov@nginx.com     }
2119163Smax.romanov@nginx.com 
2120167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2121167Smax.romanov@nginx.com               &app->name, app);
2122141Smax.romanov@nginx.com 
2123141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2124141Smax.romanov@nginx.com 
2125141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
2126141Smax.romanov@nginx.com 
2127141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2128141Smax.romanov@nginx.com }
2129141Smax.romanov@nginx.com 
2130141Smax.romanov@nginx.com 
2131163Smax.romanov@nginx.com nxt_bool_t
2132141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
2133141Smax.romanov@nginx.com {
2134163Smax.romanov@nginx.com     nxt_app_t   *app;
2135163Smax.romanov@nginx.com     nxt_bool_t  busy;
2136141Smax.romanov@nginx.com 
2137141Smax.romanov@nginx.com     app = port->app;
2138167Smax.romanov@nginx.com     busy = port->app_req_id != 0;
2139163Smax.romanov@nginx.com 
2140163Smax.romanov@nginx.com     if (app == NULL) {
2141167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, no app", port);
2142167Smax.romanov@nginx.com 
2143163Smax.romanov@nginx.com         nxt_assert(port->app_link.next == NULL);
2144163Smax.romanov@nginx.com 
2145163Smax.romanov@nginx.com         return 1;
2146141Smax.romanov@nginx.com     }
2147141Smax.romanov@nginx.com 
2148141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2149141Smax.romanov@nginx.com 
2150163Smax.romanov@nginx.com     if (port->app_link.next != NULL) {
2151163Smax.romanov@nginx.com 
2152163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2153163Smax.romanov@nginx.com         port->app_link.next = NULL;
2154163Smax.romanov@nginx.com 
2155163Smax.romanov@nginx.com     }
2156141Smax.romanov@nginx.com 
2157141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2158163Smax.romanov@nginx.com 
2159163Smax.romanov@nginx.com     if (busy == 0) {
2160167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port,
2161167Smax.romanov@nginx.com                              &app->name, app);
2162163Smax.romanov@nginx.com 
2163163Smax.romanov@nginx.com         app->workers--;
2164167Smax.romanov@nginx.com         nxt_router_app_free(&port->engine->task, app);
2165163Smax.romanov@nginx.com 
2166163Smax.romanov@nginx.com         return 1;
2167163Smax.romanov@nginx.com     }
2168163Smax.romanov@nginx.com 
2169167Smax.romanov@nginx.com     nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, req #%uxD",
2170167Smax.romanov@nginx.com                          port, &app->name, app, port->app_req_id);
2171167Smax.romanov@nginx.com 
2172163Smax.romanov@nginx.com     return 0;
2173141Smax.romanov@nginx.com }
2174141Smax.romanov@nginx.com 
2175141Smax.romanov@nginx.com 
2176167Smax.romanov@nginx.com static nxt_int_t
2177167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2178141Smax.romanov@nginx.com {
2179141Smax.romanov@nginx.com     nxt_app_t                *app;
2180141Smax.romanov@nginx.com     nxt_conn_t               *c;
2181167Smax.romanov@nginx.com     nxt_port_t               *port;
2182141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
2183141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2184141Smax.romanov@nginx.com 
2185141Smax.romanov@nginx.com     port = NULL;
2186167Smax.romanov@nginx.com     c = ra->rc->conn;
2187141Smax.romanov@nginx.com 
2188141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2189141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2190141Smax.romanov@nginx.com 
2191141Smax.romanov@nginx.com     if (app == NULL) {
2192167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2193141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2194141Smax.romanov@nginx.com         return NXT_ERROR;
2195141Smax.romanov@nginx.com     }
2196141Smax.romanov@nginx.com 
2197141Smax.romanov@nginx.com 
2198167Smax.romanov@nginx.com     port = nxt_router_app_get_port(app, ra->req_id);
2199141Smax.romanov@nginx.com 
2200141Smax.romanov@nginx.com     if (port != NULL) {
2201163Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V'", &app->name);
2202163Smax.romanov@nginx.com 
2203167Smax.romanov@nginx.com         ra->app_port = port;
2204141Smax.romanov@nginx.com         return NXT_OK;
2205141Smax.romanov@nginx.com     }
2206141Smax.romanov@nginx.com 
2207192Smax.romanov@nginx.com     sw = nxt_router_sw_create(task, app, ra);
2208141Smax.romanov@nginx.com 
2209141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
2210167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2211141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
2212141Smax.romanov@nginx.com         return NXT_ERROR;
2213141Smax.romanov@nginx.com     }
2214141Smax.romanov@nginx.com 
2215141Smax.romanov@nginx.com     return NXT_AGAIN;
221688Smax.romanov@nginx.com }
221788Smax.romanov@nginx.com 
221888Smax.romanov@nginx.com 
221988Smax.romanov@nginx.com static void
222053Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
222153Sigor@sysoev.ru {
222288Smax.romanov@nginx.com     size_t                    size, preread;
222353Sigor@sysoev.ru     nxt_int_t                 ret;
222453Sigor@sysoev.ru     nxt_buf_t                 *b;
222562Sigor@sysoev.ru     nxt_conn_t                *c;
222688Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
222753Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
222888Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
222953Sigor@sysoev.ru 
223053Sigor@sysoev.ru     c = obj;
223188Smax.romanov@nginx.com     ap = data;
223288Smax.romanov@nginx.com     b = c->read;
223353Sigor@sysoev.ru 
223453Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
223553Sigor@sysoev.ru 
223688Smax.romanov@nginx.com     if (ap == NULL) {
223788Smax.romanov@nginx.com         ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
223888Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
223953Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
224053Sigor@sysoev.ru             return;
224153Sigor@sysoev.ru         }
224253Sigor@sysoev.ru 
224388Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
224461Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
224561Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
224661Sigor@sysoev.ru             return;
224761Sigor@sysoev.ru         }
224888Smax.romanov@nginx.com 
224988Smax.romanov@nginx.com         c->socket.data = ap;
2250113Smax.romanov@nginx.com 
2251113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2252113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
225353Sigor@sysoev.ru     }
225453Sigor@sysoev.ru 
225588Smax.romanov@nginx.com     h = &ap->r.header;
225688Smax.romanov@nginx.com 
225788Smax.romanov@nginx.com     ret = nxt_app_http_req_parse(task, ap, b);
225853Sigor@sysoev.ru 
225953Sigor@sysoev.ru     nxt_debug(task, "http parse request: %d", ret);
226053Sigor@sysoev.ru 
226153Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
226253Sigor@sysoev.ru 
226353Sigor@sysoev.ru     case NXT_DONE:
226488Smax.romanov@nginx.com         preread = nxt_buf_mem_used_size(&b->mem);
226588Smax.romanov@nginx.com 
226688Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
226788Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
226888Smax.romanov@nginx.com                   h->parsed_content_length, preread);
226988Smax.romanov@nginx.com 
227088Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
227188Smax.romanov@nginx.com         return;
227253Sigor@sysoev.ru 
227353Sigor@sysoev.ru     case NXT_ERROR:
227453Sigor@sysoev.ru         nxt_router_conn_close(task, c, data);
227553Sigor@sysoev.ru         return;
227653Sigor@sysoev.ru 
227753Sigor@sysoev.ru     default:  /* NXT_AGAIN */
227853Sigor@sysoev.ru 
227988Smax.romanov@nginx.com         if (h->done == 0) {
228088Smax.romanov@nginx.com 
228188Smax.romanov@nginx.com             if (c->read->mem.free == c->read->mem.end) {
228288Smax.romanov@nginx.com                 joint = c->listen->socket.data;
228388Smax.romanov@nginx.com                 size = joint->socket_conf->large_header_buffer_size;
228488Smax.romanov@nginx.com 
228588Smax.romanov@nginx.com                 if (size > (size_t) nxt_buf_mem_size(&b->mem)) {
228688Smax.romanov@nginx.com                     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
228788Smax.romanov@nginx.com                     if (nxt_slow_path(b == NULL)) {
228888Smax.romanov@nginx.com                         nxt_router_conn_close(task, c, data);
228988Smax.romanov@nginx.com                         return;
229088Smax.romanov@nginx.com                     }
229188Smax.romanov@nginx.com 
229288Smax.romanov@nginx.com                     size = c->read->mem.free - c->read->mem.pos;
2293141Smax.romanov@nginx.com 
2294141Smax.romanov@nginx.com                     c->read = nxt_buf_cpy(b, c->read->mem.pos, size);
229588Smax.romanov@nginx.com                 } else {
2296141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 400,
2297141Smax.romanov@nginx.com                                          "Too long request headers");
2298141Smax.romanov@nginx.com                     return;
229988Smax.romanov@nginx.com                 }
230088Smax.romanov@nginx.com             }
230188Smax.romanov@nginx.com         }
230288Smax.romanov@nginx.com 
230388Smax.romanov@nginx.com         if (ap->r.body.done == 0) {
230488Smax.romanov@nginx.com 
230588Smax.romanov@nginx.com             preread = nxt_buf_mem_used_size(&b->mem);
230688Smax.romanov@nginx.com 
230788Smax.romanov@nginx.com             if (h->parsed_content_length - preread >
230888Smax.romanov@nginx.com                 (size_t) nxt_buf_mem_free_size(&b->mem)) {
230988Smax.romanov@nginx.com 
231088Smax.romanov@nginx.com                 b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0);
231188Smax.romanov@nginx.com                 if (nxt_slow_path(b == NULL)) {
2312141Smax.romanov@nginx.com                     nxt_router_gen_error(task, c, 500, "Failed to allocate "
2313141Smax.romanov@nginx.com                                          "buffer for request body");
2314141Smax.romanov@nginx.com                     return;
231588Smax.romanov@nginx.com                 }
231688Smax.romanov@nginx.com 
2317141Smax.romanov@nginx.com                 c->read = nxt_buf_cpy(b, c->read->mem.pos, preread);
231853Sigor@sysoev.ru             }
231953Sigor@sysoev.ru 
232088Smax.romanov@nginx.com             nxt_debug(task, "router request body read again, rest: %uz",
232188Smax.romanov@nginx.com                       h->parsed_content_length - preread);
232253Sigor@sysoev.ru 
232353Sigor@sysoev.ru         }
232453Sigor@sysoev.ru 
232588Smax.romanov@nginx.com     }
232688Smax.romanov@nginx.com 
232788Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
232888Smax.romanov@nginx.com }
232988Smax.romanov@nginx.com 
233088Smax.romanov@nginx.com 
233188Smax.romanov@nginx.com static void
233288Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
233388Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
233488Smax.romanov@nginx.com {
2335167Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2336122Smax.romanov@nginx.com     nxt_int_t            res;
2337167Smax.romanov@nginx.com     nxt_port_t           *port;
233888Smax.romanov@nginx.com     nxt_req_id_t         req_id;
233988Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
2340167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
234188Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
234288Smax.romanov@nginx.com 
234388Smax.romanov@nginx.com     engine = task->thread->engine;
234488Smax.romanov@nginx.com 
234588Smax.romanov@nginx.com     do {
2346138Sigor@sysoev.ru         req_id = nxt_random(&task->thread->random);
234788Smax.romanov@nginx.com     } while (nxt_event_engine_request_find(engine, req_id) != NULL);
234888Smax.romanov@nginx.com 
234988Smax.romanov@nginx.com     rc = nxt_conn_request_add(c, req_id);
2350122Smax.romanov@nginx.com 
235188Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2352141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2353141Smax.romanov@nginx.com                              "req->conn link");
2354141Smax.romanov@nginx.com 
2355141Smax.romanov@nginx.com         return;
235688Smax.romanov@nginx.com     }
235788Smax.romanov@nginx.com 
235888Smax.romanov@nginx.com     nxt_event_engine_request_add(engine, rc);
235988Smax.romanov@nginx.com 
236088Smax.romanov@nginx.com     nxt_debug(task, "req_id %uxD linked to conn %p at engine %p",
236188Smax.romanov@nginx.com               req_id, c, engine);
236253Sigor@sysoev.ru 
2363167Smax.romanov@nginx.com 
2364167Smax.romanov@nginx.com     ra = nxt_router_ra_create(task, rc);
2365167Smax.romanov@nginx.com 
2366167Smax.romanov@nginx.com     ra->ap = ap;
2367167Smax.romanov@nginx.com     ra->reply_port = engine->port;
2368167Smax.romanov@nginx.com 
2369167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
2370141Smax.romanov@nginx.com 
2371141Smax.romanov@nginx.com     if (res != NXT_OK) {
2372141Smax.romanov@nginx.com         return;
2373141Smax.romanov@nginx.com     }
2374141Smax.romanov@nginx.com 
2375167Smax.romanov@nginx.com     port = ra->app_port;
2376141Smax.romanov@nginx.com 
2377141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2378141Smax.romanov@nginx.com         nxt_router_gen_error(task, rc->conn, 500, "Application port not found");
2379141Smax.romanov@nginx.com         return;
2380141Smax.romanov@nginx.com     }
2381141Smax.romanov@nginx.com 
2382122Smax.romanov@nginx.com     port_mp = port->mem_pool;
2383167Smax.romanov@nginx.com     port->mem_pool = c->mem_pool;
2384167Smax.romanov@nginx.com 
2385167Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra, port);
2386167Smax.romanov@nginx.com 
2387167Smax.romanov@nginx.com     port->mem_pool = port_mp;
2388167Smax.romanov@nginx.com 
2389167Smax.romanov@nginx.com 
2390167Smax.romanov@nginx.com     nxt_router_ra_release(task, ra, ra->work.data);
2391167Smax.romanov@nginx.com }
2392167Smax.romanov@nginx.com 
2393167Smax.romanov@nginx.com 
2394167Smax.romanov@nginx.com static void
2395167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra,
2396167Smax.romanov@nginx.com     nxt_port_t *port)
2397167Smax.romanov@nginx.com {
2398167Smax.romanov@nginx.com     nxt_int_t            res;
2399167Smax.romanov@nginx.com     nxt_port_t           *c_port, *reply_port;
2400167Smax.romanov@nginx.com     nxt_conn_t           *c;
2401167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
2402167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
2403167Smax.romanov@nginx.com 
2404167Smax.romanov@nginx.com     reply_port = ra->reply_port;
2405167Smax.romanov@nginx.com     ap = ra->ap;
2406167Smax.romanov@nginx.com     c = ra->rc->conn;
2407141Smax.romanov@nginx.com 
2408141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
2409141Smax.romanov@nginx.com                                              reply_port->id);
2410141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
2411141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
2412122Smax.romanov@nginx.com 
2413122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
2414167Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2415141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
2416167Smax.romanov@nginx.com             return;
2417122Smax.romanov@nginx.com         }
2418122Smax.romanov@nginx.com 
2419141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
242088Smax.romanov@nginx.com     }
242188Smax.romanov@nginx.com 
242288Smax.romanov@nginx.com     wmsg.port = port;
242388Smax.romanov@nginx.com     wmsg.write = NULL;
242488Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
2425167Smax.romanov@nginx.com     wmsg.stream = ra->req_id;
2426167Smax.romanov@nginx.com 
2427167Smax.romanov@nginx.com     res = port->app->module->prepare_msg(task, &ap->r, &wmsg);
2428122Smax.romanov@nginx.com 
2429122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2430167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2431141Smax.romanov@nginx.com                              "Failed to prepare message for application");
2432167Smax.romanov@nginx.com         return;
2433122Smax.romanov@nginx.com     }
243488Smax.romanov@nginx.com 
243588Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
243688Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
243788Smax.romanov@nginx.com                     wmsg.port->socket.fd);
243888Smax.romanov@nginx.com 
2439122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
2440167Smax.romanov@nginx.com                                  -1, ra->req_id, reply_port->id, wmsg.write);
2441122Smax.romanov@nginx.com 
2442122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2443167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2444141Smax.romanov@nginx.com                              "Failed to send message to application");
2445167Smax.romanov@nginx.com         return;
2446122Smax.romanov@nginx.com     }
244753Sigor@sysoev.ru }
244853Sigor@sysoev.ru 
244953Sigor@sysoev.ru 
245062Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
245153Sigor@sysoev.ru     nxt_aligned(64) =
245253Sigor@sysoev.ru {
245353Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
245453Sigor@sysoev.ru };
245553Sigor@sysoev.ru 
245653Sigor@sysoev.ru 
245753Sigor@sysoev.ru static void
245888Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
245988Smax.romanov@nginx.com {
246088Smax.romanov@nginx.com     nxt_buf_t         *b;
246188Smax.romanov@nginx.com     nxt_bool_t        last;
246288Smax.romanov@nginx.com     nxt_conn_t        *c;
246388Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
246488Smax.romanov@nginx.com 
246588Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
246688Smax.romanov@nginx.com 
246788Smax.romanov@nginx.com     c = obj;
246888Smax.romanov@nginx.com     b = c->write;
246988Smax.romanov@nginx.com 
247088Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
247188Smax.romanov@nginx.com 
247288Smax.romanov@nginx.com     last = 0;
247388Smax.romanov@nginx.com 
247488Smax.romanov@nginx.com     while (b != NULL) {
247588Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
247688Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
247788Smax.romanov@nginx.com                 break;
247888Smax.romanov@nginx.com             }
247988Smax.romanov@nginx.com         }
248088Smax.romanov@nginx.com 
248188Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
248288Smax.romanov@nginx.com             last = 1;
248388Smax.romanov@nginx.com         }
248488Smax.romanov@nginx.com 
248588Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
248688Smax.romanov@nginx.com 
248788Smax.romanov@nginx.com         b = b->next;
248888Smax.romanov@nginx.com     }
248988Smax.romanov@nginx.com 
249088Smax.romanov@nginx.com     c->write = b;
249188Smax.romanov@nginx.com 
249288Smax.romanov@nginx.com     if (b != NULL) {
249388Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
249488Smax.romanov@nginx.com 
249588Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
249688Smax.romanov@nginx.com     } else {
249788Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
249888Smax.romanov@nginx.com                   last);
249988Smax.romanov@nginx.com 
250088Smax.romanov@nginx.com         if (last != 0) {
250188Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
250288Smax.romanov@nginx.com 
250388Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
250488Smax.romanov@nginx.com                                c->socket.data);
250588Smax.romanov@nginx.com         }
250688Smax.romanov@nginx.com     }
250788Smax.romanov@nginx.com }
250888Smax.romanov@nginx.com 
250988Smax.romanov@nginx.com 
251088Smax.romanov@nginx.com static void
251153Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
251253Sigor@sysoev.ru {
251362Sigor@sysoev.ru     nxt_conn_t  *c;
251453Sigor@sysoev.ru 
251553Sigor@sysoev.ru     c = obj;
251653Sigor@sysoev.ru 
251753Sigor@sysoev.ru     nxt_debug(task, "router conn close");
251853Sigor@sysoev.ru 
251953Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
252053Sigor@sysoev.ru 
252162Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
252253Sigor@sysoev.ru }
252353Sigor@sysoev.ru 
252453Sigor@sysoev.ru 
252553Sigor@sysoev.ru static void
2526164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
2527164Smax.romanov@nginx.com {
2528164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2529164Smax.romanov@nginx.com 
2530164Smax.romanov@nginx.com     joint = obj;
2531164Smax.romanov@nginx.com 
2532164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
2533164Smax.romanov@nginx.com }
2534164Smax.romanov@nginx.com 
2535164Smax.romanov@nginx.com 
2536164Smax.romanov@nginx.com static void
253753Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
253853Sigor@sysoev.ru {
253962Sigor@sysoev.ru     nxt_conn_t               *c;
254088Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
254153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
254253Sigor@sysoev.ru 
254353Sigor@sysoev.ru     c = obj;
254453Sigor@sysoev.ru 
254553Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
254653Sigor@sysoev.ru 
254788Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
254888Smax.romanov@nginx.com 
254988Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id);
255088Smax.romanov@nginx.com 
2551141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2552141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2553141Smax.romanov@nginx.com 
2554141Smax.romanov@nginx.com             rc->app_port = NULL;
2555141Smax.romanov@nginx.com         }
2556141Smax.romanov@nginx.com 
2557167Smax.romanov@nginx.com         rc->conn = NULL;
2558167Smax.romanov@nginx.com 
255988Smax.romanov@nginx.com         nxt_event_engine_request_remove(task->thread->engine, rc);
256088Smax.romanov@nginx.com 
256188Smax.romanov@nginx.com     } nxt_queue_loop;
256288Smax.romanov@nginx.com 
2563122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
2564122Smax.romanov@nginx.com 
2565131Smax.romanov@nginx.com     joint = c->listen->socket.data;
2566131Smax.romanov@nginx.com 
2567131Smax.romanov@nginx.com     task = &task->thread->engine->task;
2568131Smax.romanov@nginx.com 
2569164Smax.romanov@nginx.com     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL);
2570164Smax.romanov@nginx.com 
2571164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
257253Sigor@sysoev.ru }
257353Sigor@sysoev.ru 
257453Sigor@sysoev.ru 
257553Sigor@sysoev.ru static void
257653Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
257753Sigor@sysoev.ru {
257862Sigor@sysoev.ru     nxt_conn_t  *c;
257953Sigor@sysoev.ru 
258053Sigor@sysoev.ru     c = obj;
258153Sigor@sysoev.ru 
258253Sigor@sysoev.ru     nxt_debug(task, "router conn error");
258353Sigor@sysoev.ru 
258453Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
258553Sigor@sysoev.ru 
258662Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
258753Sigor@sysoev.ru }
258853Sigor@sysoev.ru 
258953Sigor@sysoev.ru 
259053Sigor@sysoev.ru static void
259153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
259253Sigor@sysoev.ru {
259362Sigor@sysoev.ru     nxt_conn_t   *c;
259462Sigor@sysoev.ru     nxt_timer_t  *timer;
259553Sigor@sysoev.ru 
259653Sigor@sysoev.ru     timer = obj;
259753Sigor@sysoev.ru 
259853Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
259953Sigor@sysoev.ru 
260062Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
260153Sigor@sysoev.ru 
260253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
260353Sigor@sysoev.ru 
260462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
260553Sigor@sysoev.ru }
260653Sigor@sysoev.ru 
260753Sigor@sysoev.ru 
260853Sigor@sysoev.ru static nxt_msec_t
260962Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
261053Sigor@sysoev.ru {
261153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
261253Sigor@sysoev.ru 
261353Sigor@sysoev.ru     joint = c->listen->socket.data;
261453Sigor@sysoev.ru 
261553Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
261653Sigor@sysoev.ru }
2617