xref: /unit/src/nxt_router.c (revision 318)
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 {
13*318Smax.romanov@nginx.com     nxt_str_t         type;
14*318Smax.romanov@nginx.com     uint32_t          workers;
15*318Smax.romanov@nginx.com     nxt_msec_t        timeout;
16*318Smax.romanov@nginx.com     uint32_t          requests;
17*318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
18133Sigor@sysoev.ru } nxt_router_app_conf_t;
19133Sigor@sysoev.ru 
20133Sigor@sysoev.ru 
21133Sigor@sysoev.ru typedef struct {
22133Sigor@sysoev.ru     nxt_str_t  application;
23115Sigor@sysoev.ru } nxt_router_listener_conf_t;
24115Sigor@sysoev.ru 
25115Sigor@sysoev.ru 
26167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
27141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t;
28141Smax.romanov@nginx.com 
29141Smax.romanov@nginx.com struct nxt_start_worker_s {
30141Smax.romanov@nginx.com     nxt_app_t              *app;
31167Smax.romanov@nginx.com     nxt_req_app_link_t     *ra;
32141Smax.romanov@nginx.com 
33141Smax.romanov@nginx.com     nxt_work_t             work;
34141Smax.romanov@nginx.com };
35141Smax.romanov@nginx.com 
36141Smax.romanov@nginx.com 
37*318Smax.romanov@nginx.com typedef struct {
38*318Smax.romanov@nginx.com     uint32_t             stream;
39*318Smax.romanov@nginx.com     nxt_conn_t           *conn;
40*318Smax.romanov@nginx.com     nxt_port_t           *app_port;
41*318Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
42*318Smax.romanov@nginx.com 
43*318Smax.romanov@nginx.com     nxt_queue_link_t     link;     /* for nxt_conn_t.requests */
44*318Smax.romanov@nginx.com } nxt_req_conn_link_t;
45*318Smax.romanov@nginx.com 
46*318Smax.romanov@nginx.com 
47167Smax.romanov@nginx.com struct nxt_req_app_link_s {
48*318Smax.romanov@nginx.com     uint32_t             stream;
49167Smax.romanov@nginx.com     nxt_port_t           *app_port;
50*318Smax.romanov@nginx.com     nxt_pid_t            app_pid;
51167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
52167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
53167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
54167Smax.romanov@nginx.com 
55167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
56167Smax.romanov@nginx.com 
57167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
58167Smax.romanov@nginx.com     nxt_work_t           work;
59167Smax.romanov@nginx.com };
60167Smax.romanov@nginx.com 
61167Smax.romanov@nginx.com 
62198Sigor@sysoev.ru typedef struct {
63198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
64198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
65198Sigor@sysoev.ru } nxt_socket_rpc_t;
66198Sigor@sysoev.ru 
67198Sigor@sysoev.ru 
68*318Smax.romanov@nginx.com typedef struct {
69*318Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
70*318Smax.romanov@nginx.com     nxt_port_recv_msg_t  msg;
71*318Smax.romanov@nginx.com     nxt_work_t           work;
72*318Smax.romanov@nginx.com } nxt_remove_pid_msg_t;
73*318Smax.romanov@nginx.com 
74*318Smax.romanov@nginx.com 
75*318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj,
76*318Smax.romanov@nginx.com     void *data);
77*318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj,
78*318Smax.romanov@nginx.com     void *data);
79*318Smax.romanov@nginx.com 
80139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
81198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
82198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
83139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
84139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
85139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
86139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
87193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
8853Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
8953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9053Sigor@sysoev.ru 
91115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
92115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
93133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
94133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
95133Sigor@sysoev.ru     nxt_str_t *name);
96198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
97198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
98198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
99198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
100198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
101198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
10265Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
10365Sigor@sysoev.ru     nxt_sockaddr_t *sa);
10453Sigor@sysoev.ru 
10553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
10653Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
10753Sigor@sysoev.ru     const nxt_event_interface_t *interface);
108115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
109115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
110115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
111115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
112115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
113115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
114115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
115154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
116154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
117154Sigor@sysoev.ru     nxt_work_handler_t handler);
118313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
119313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
120139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
121139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
12253Sigor@sysoev.ru 
12353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
12453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
12553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
12653Sigor@sysoev.ru     nxt_event_engine_t *engine);
127133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router,
128133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
12953Sigor@sysoev.ru 
130315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
131315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
132315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
133315Sigor@sysoev.ru     nxt_work_t *jobs);
13453Sigor@sysoev.ru 
13553Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
13653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
13753Sigor@sysoev.ru     void *data);
13853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
13953Sigor@sysoev.ru     void *data);
14053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
14153Sigor@sysoev.ru     void *data);
142313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
143313Sigor@sysoev.ru     void *data);
14453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
14553Sigor@sysoev.ru     void *data);
14653Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
14753Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
14853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
14953Sigor@sysoev.ru     void *data);
15053Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
15153Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
15253Sigor@sysoev.ru 
153167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj,
154167Smax.romanov@nginx.com     void *data);
155167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app);
156*318Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t stream);
157141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj,
158141Smax.romanov@nginx.com     void *data);
159141Smax.romanov@nginx.com 
16053Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
16153Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
16253Sigor@sysoev.ru     void *data);
163206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
164206Smax.romanov@nginx.com     void *data);
16588Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
16688Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
167141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
168167Smax.romanov@nginx.com     nxt_req_app_link_t *ra, nxt_port_t *port);
169216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
170216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
171216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
172216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
173216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
174216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
17588Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
17653Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
17753Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
17853Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
17953Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
180*318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
18162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
18220Sigor@sysoev.ru 
183141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
184141Smax.romanov@nginx.com     const char* fmt, ...);
185141Smax.romanov@nginx.com 
186119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
18720Sigor@sysoev.ru 
188216Sigor@sysoev.ru 
189216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
190216Sigor@sysoev.ru     nxt_python_prepare_msg,
191216Sigor@sysoev.ru     nxt_php_prepare_msg,
192216Sigor@sysoev.ru     nxt_go_prepare_msg,
193216Sigor@sysoev.ru };
194216Sigor@sysoev.ru 
195216Sigor@sysoev.ru 
19620Sigor@sysoev.ru nxt_int_t
197141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
19820Sigor@sysoev.ru {
199141Smax.romanov@nginx.com     nxt_int_t      ret;
200141Smax.romanov@nginx.com     nxt_router_t   *router;
201141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
202141Smax.romanov@nginx.com 
203141Smax.romanov@nginx.com     rt = task->thread->runtime;
20453Sigor@sysoev.ru 
20588Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
20688Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
20788Smax.romanov@nginx.com         return ret;
20888Smax.romanov@nginx.com     }
20988Smax.romanov@nginx.com 
21053Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
21153Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
21253Sigor@sysoev.ru         return NXT_ERROR;
21353Sigor@sysoev.ru     }
21453Sigor@sysoev.ru 
21553Sigor@sysoev.ru     nxt_queue_init(&router->engines);
21653Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
217133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
21853Sigor@sysoev.ru 
219119Smax.romanov@nginx.com     nxt_router = router;
220119Smax.romanov@nginx.com 
221115Sigor@sysoev.ru     return NXT_OK;
222115Sigor@sysoev.ru }
223115Sigor@sysoev.ru 
224115Sigor@sysoev.ru 
225167Smax.romanov@nginx.com static nxt_start_worker_t *
226192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
227167Smax.romanov@nginx.com {
228240Sigor@sysoev.ru     nxt_port_t          *main_port;
229167Smax.romanov@nginx.com     nxt_runtime_t       *rt;
230167Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
231167Smax.romanov@nginx.com 
232192Smax.romanov@nginx.com     sw = nxt_zalloc(sizeof(nxt_start_worker_t));
233167Smax.romanov@nginx.com 
234167Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
235167Smax.romanov@nginx.com         return NULL;
236167Smax.romanov@nginx.com     }
237167Smax.romanov@nginx.com 
238167Smax.romanov@nginx.com     sw->app = app;
239167Smax.romanov@nginx.com     sw->ra = ra;
240167Smax.romanov@nginx.com 
241*318Smax.romanov@nginx.com     nxt_debug(task, "sw %p create, stream #%uD, app '%V' %p", sw,
242*318Smax.romanov@nginx.com                     ra->stream, &app->name, app);
243167Smax.romanov@nginx.com 
244167Smax.romanov@nginx.com     rt = task->thread->runtime;
245240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
246167Smax.romanov@nginx.com 
247167Smax.romanov@nginx.com     sw->work.handler = nxt_router_send_sw_request;
248240Sigor@sysoev.ru     sw->work.task = &main_port->engine->task;
249167Smax.romanov@nginx.com     sw->work.obj = sw;
250167Smax.romanov@nginx.com     sw->work.data = task->thread->engine;
251167Smax.romanov@nginx.com     sw->work.next = NULL;
252167Smax.romanov@nginx.com 
253240Sigor@sysoev.ru     if (task->thread->engine != main_port->engine) {
254240Sigor@sysoev.ru         nxt_debug(task, "sw %p post send to main engine %p", sw,
255240Sigor@sysoev.ru                   main_port->engine);
256240Sigor@sysoev.ru 
257240Sigor@sysoev.ru         nxt_event_engine_post(main_port->engine, &sw->work);
258167Smax.romanov@nginx.com 
259167Smax.romanov@nginx.com     } else {
260167Smax.romanov@nginx.com         nxt_router_send_sw_request(task, sw, sw->work.data);
261167Smax.romanov@nginx.com     }
262167Smax.romanov@nginx.com 
263167Smax.romanov@nginx.com     return sw;
264167Smax.romanov@nginx.com }
265167Smax.romanov@nginx.com 
266167Smax.romanov@nginx.com 
267192Smax.romanov@nginx.com nxt_inline void
268192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw)
269141Smax.romanov@nginx.com {
270192Smax.romanov@nginx.com     nxt_debug(task, "sw %p release", sw);
271192Smax.romanov@nginx.com 
272192Smax.romanov@nginx.com     nxt_free(sw);
273141Smax.romanov@nginx.com }
274141Smax.romanov@nginx.com 
275141Smax.romanov@nginx.com 
276*318Smax.romanov@nginx.com nxt_inline void
277*318Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_req_conn_link_t *rc)
278*318Smax.romanov@nginx.com {
279*318Smax.romanov@nginx.com     nxt_queue_remove(&rc->link);
280*318Smax.romanov@nginx.com 
281*318Smax.romanov@nginx.com     if (rc->ra != NULL) {
282*318Smax.romanov@nginx.com         rc->ra->rc = NULL;
283*318Smax.romanov@nginx.com         rc->ra = NULL;
284*318Smax.romanov@nginx.com     }
285*318Smax.romanov@nginx.com 
286*318Smax.romanov@nginx.com     rc->conn = NULL;
287*318Smax.romanov@nginx.com }
288*318Smax.romanov@nginx.com 
289*318Smax.romanov@nginx.com 
290167Smax.romanov@nginx.com static nxt_req_app_link_t *
291167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
292167Smax.romanov@nginx.com {
293167Smax.romanov@nginx.com     nxt_mp_t            *mp;
294*318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
295167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
296167Smax.romanov@nginx.com 
297167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
298*318Smax.romanov@nginx.com     engine = task->thread->engine;
299167Smax.romanov@nginx.com 
300167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
301167Smax.romanov@nginx.com 
302167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
303167Smax.romanov@nginx.com         return NULL;
304167Smax.romanov@nginx.com     }
305167Smax.romanov@nginx.com 
306*318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD create", rc->stream);
307167Smax.romanov@nginx.com 
308167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
309167Smax.romanov@nginx.com 
310*318Smax.romanov@nginx.com     ra->stream = rc->stream;
311*318Smax.romanov@nginx.com     ra->app_pid = -1;
312167Smax.romanov@nginx.com     ra->rc = rc;
313*318Smax.romanov@nginx.com     rc->ra = ra;
314*318Smax.romanov@nginx.com     ra->reply_port = engine->port;
315167Smax.romanov@nginx.com 
316167Smax.romanov@nginx.com     ra->mem_pool = mp;
317167Smax.romanov@nginx.com 
318167Smax.romanov@nginx.com     ra->work.handler = NULL;
319*318Smax.romanov@nginx.com     ra->work.task = &engine->task;
320167Smax.romanov@nginx.com     ra->work.obj = ra;
321*318Smax.romanov@nginx.com     ra->work.data = engine;
322167Smax.romanov@nginx.com 
323167Smax.romanov@nginx.com     return ra;
324167Smax.romanov@nginx.com }
325167Smax.romanov@nginx.com 
326167Smax.romanov@nginx.com 
327167Smax.romanov@nginx.com static void
328167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
329167Smax.romanov@nginx.com {
330*318Smax.romanov@nginx.com     nxt_port_t          *app_port;
331*318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
332*318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
333*318Smax.romanov@nginx.com 
334*318Smax.romanov@nginx.com     ra = obj;
335*318Smax.romanov@nginx.com     engine = data;
336*318Smax.romanov@nginx.com 
337*318Smax.romanov@nginx.com     if (ra->app_port != NULL) {
338*318Smax.romanov@nginx.com 
339*318Smax.romanov@nginx.com         app_port = ra->app_port;
340*318Smax.romanov@nginx.com         ra->app_port = NULL;
341*318Smax.romanov@nginx.com 
342*318Smax.romanov@nginx.com         if (task->thread->engine != engine) {
343*318Smax.romanov@nginx.com             ra->app_pid = app_port->pid;
344*318Smax.romanov@nginx.com         }
345*318Smax.romanov@nginx.com 
346*318Smax.romanov@nginx.com         nxt_router_app_release_port(task, app_port, app_port->app);
347*318Smax.romanov@nginx.com 
348*318Smax.romanov@nginx.com #if 0
349*318Smax.romanov@nginx.com         /* Uncomment to hold app port until complete response received. */
350*318Smax.romanov@nginx.com         if (ra->rc != NULL) {
351*318Smax.romanov@nginx.com             ra->rc->app_port = ra->app_port;
352*318Smax.romanov@nginx.com 
353*318Smax.romanov@nginx.com         } else {
354*318Smax.romanov@nginx.com             nxt_router_app_release_port(task, ra->app_port, ra->app_port->app);
355*318Smax.romanov@nginx.com         }
356*318Smax.romanov@nginx.com #endif
357*318Smax.romanov@nginx.com     }
358*318Smax.romanov@nginx.com 
359*318Smax.romanov@nginx.com     if (task->thread->engine != engine) {
360*318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
361*318Smax.romanov@nginx.com         ra->work.task = &engine->task;
362*318Smax.romanov@nginx.com         ra->work.next = NULL;
363*318Smax.romanov@nginx.com 
364*318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
365*318Smax.romanov@nginx.com                   ra->stream, engine);
366*318Smax.romanov@nginx.com 
367*318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
368*318Smax.romanov@nginx.com 
369*318Smax.romanov@nginx.com         return;
370*318Smax.romanov@nginx.com     }
371*318Smax.romanov@nginx.com 
372*318Smax.romanov@nginx.com     if (ra->rc != NULL && ra->app_pid != -1) {
373*318Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, ra->rc, ra->app_pid);
374*318Smax.romanov@nginx.com     }
375*318Smax.romanov@nginx.com 
376*318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
377*318Smax.romanov@nginx.com 
378*318Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
379*318Smax.romanov@nginx.com }
380*318Smax.romanov@nginx.com 
381*318Smax.romanov@nginx.com 
382*318Smax.romanov@nginx.com static void
383*318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data)
384*318Smax.romanov@nginx.com {
385*318Smax.romanov@nginx.com     nxt_conn_t          *c;
386167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
387167Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
388167Smax.romanov@nginx.com 
389167Smax.romanov@nginx.com     ra = obj;
390167Smax.romanov@nginx.com     engine = data;
391167Smax.romanov@nginx.com 
392167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
393*318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_abort;
394167Smax.romanov@nginx.com         ra->work.task = &engine->task;
395167Smax.romanov@nginx.com         ra->work.next = NULL;
396167Smax.romanov@nginx.com 
397*318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine);
398167Smax.romanov@nginx.com 
399167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
400167Smax.romanov@nginx.com 
401167Smax.romanov@nginx.com         return;
402167Smax.romanov@nginx.com     }
403167Smax.romanov@nginx.com 
404*318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD abort", ra->stream);
405*318Smax.romanov@nginx.com 
406*318Smax.romanov@nginx.com     if (ra->rc != NULL) {
407*318Smax.romanov@nginx.com         c = ra->rc->conn;
408*318Smax.romanov@nginx.com 
409*318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
410*318Smax.romanov@nginx.com                              "Failed to start application worker");
411167Smax.romanov@nginx.com     }
412167Smax.romanov@nginx.com 
413167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
414167Smax.romanov@nginx.com }
415167Smax.romanov@nginx.com 
416167Smax.romanov@nginx.com 
417141Smax.romanov@nginx.com void
418141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
419141Smax.romanov@nginx.com {
420141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
421141Smax.romanov@nginx.com 
422192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
423141Smax.romanov@nginx.com         return;
424141Smax.romanov@nginx.com     }
425141Smax.romanov@nginx.com 
426192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
427192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
428141Smax.romanov@nginx.com     }
429192Smax.romanov@nginx.com 
430192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
431141Smax.romanov@nginx.com }
432141Smax.romanov@nginx.com 
433141Smax.romanov@nginx.com 
434139Sigor@sysoev.ru void
435139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
436115Sigor@sysoev.ru {
437139Sigor@sysoev.ru     size_t                  dump_size;
438198Sigor@sysoev.ru     nxt_int_t               ret;
439139Sigor@sysoev.ru     nxt_buf_t               *b;
440139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
441139Sigor@sysoev.ru 
442139Sigor@sysoev.ru     b = msg->buf;
443139Sigor@sysoev.ru 
444139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
445139Sigor@sysoev.ru 
446139Sigor@sysoev.ru     if (dump_size > 300) {
447139Sigor@sysoev.ru         dump_size = 300;
44853Sigor@sysoev.ru     }
44953Sigor@sysoev.ru 
450139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
451139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
452139Sigor@sysoev.ru 
453139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
454139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
455139Sigor@sysoev.ru         return;
45653Sigor@sysoev.ru     }
45753Sigor@sysoev.ru 
458139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
459139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
460139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
461198Sigor@sysoev.ru                                        msg->port_msg.pid,
462198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
463198Sigor@sysoev.ru 
464198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
465198Sigor@sysoev.ru 
466198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
467198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
468198Sigor@sysoev.ru 
469198Sigor@sysoev.ru     } else {
470198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
471139Sigor@sysoev.ru     }
47253Sigor@sysoev.ru }
47353Sigor@sysoev.ru 
47453Sigor@sysoev.ru 
475192Smax.romanov@nginx.com void
476192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
477192Smax.romanov@nginx.com {
478*318Smax.romanov@nginx.com     nxt_mp_t              *mp;
479*318Smax.romanov@nginx.com     nxt_buf_t             *buf;
480*318Smax.romanov@nginx.com     nxt_event_engine_t    *engine;
481*318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
482*318Smax.romanov@nginx.com 
483192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
484192Smax.romanov@nginx.com 
485192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
486192Smax.romanov@nginx.com         return;
487192Smax.romanov@nginx.com     }
488192Smax.romanov@nginx.com 
489*318Smax.romanov@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
490*318Smax.romanov@nginx.com 
491*318Smax.romanov@nginx.com     buf = nxt_buf_mem_alloc(mp, nxt_buf_used_size(msg->buf), 0);
492*318Smax.romanov@nginx.com     buf->mem.free = nxt_cpymem(buf->mem.free, msg->buf->mem.pos,
493*318Smax.romanov@nginx.com                                nxt_buf_used_size(msg->buf));
494*318Smax.romanov@nginx.com 
495*318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
496*318Smax.romanov@nginx.com     {
497*318Smax.romanov@nginx.com         rp = nxt_mp_retain(mp, sizeof(nxt_remove_pid_msg_t));
498*318Smax.romanov@nginx.com 
499*318Smax.romanov@nginx.com         rp->mem_pool = mp;
500*318Smax.romanov@nginx.com 
501*318Smax.romanov@nginx.com         rp->msg.fd = msg->fd;
502*318Smax.romanov@nginx.com         rp->msg.buf = buf;
503*318Smax.romanov@nginx.com         rp->msg.port = engine->port;
504*318Smax.romanov@nginx.com         rp->msg.port_msg = msg->port_msg;
505*318Smax.romanov@nginx.com         rp->msg.size = msg->size;
506*318Smax.romanov@nginx.com         rp->msg.new_port = NULL;
507*318Smax.romanov@nginx.com 
508*318Smax.romanov@nginx.com         rp->work.handler = nxt_router_worker_remove_pid_handler;
509*318Smax.romanov@nginx.com         rp->work.task = &engine->task;
510*318Smax.romanov@nginx.com         rp->work.obj = rp;
511*318Smax.romanov@nginx.com         rp->work.data = task->thread->engine;
512*318Smax.romanov@nginx.com         rp->work.next = NULL;
513*318Smax.romanov@nginx.com 
514*318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &rp->work);
515*318Smax.romanov@nginx.com     }
516*318Smax.romanov@nginx.com     nxt_queue_loop;
517*318Smax.romanov@nginx.com 
518192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
519192Smax.romanov@nginx.com 
520192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
521192Smax.romanov@nginx.com }
522192Smax.romanov@nginx.com 
523192Smax.romanov@nginx.com 
524*318Smax.romanov@nginx.com static void
525*318Smax.romanov@nginx.com nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj, void *data)
526*318Smax.romanov@nginx.com {
527*318Smax.romanov@nginx.com     nxt_event_engine_t    *engine;
528*318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
529*318Smax.romanov@nginx.com 
530*318Smax.romanov@nginx.com     rp = obj;
531*318Smax.romanov@nginx.com 
532*318Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, &rp->msg);
533*318Smax.romanov@nginx.com 
534*318Smax.romanov@nginx.com     engine = rp->work.data;
535*318Smax.romanov@nginx.com 
536*318Smax.romanov@nginx.com     rp->work.handler = nxt_router_worker_remove_pid_done;
537*318Smax.romanov@nginx.com     rp->work.task = &engine->task;
538*318Smax.romanov@nginx.com     rp->work.next = NULL;
539*318Smax.romanov@nginx.com 
540*318Smax.romanov@nginx.com     nxt_event_engine_post(engine, &rp->work);
541*318Smax.romanov@nginx.com }
542*318Smax.romanov@nginx.com 
543*318Smax.romanov@nginx.com 
544*318Smax.romanov@nginx.com static void
545*318Smax.romanov@nginx.com nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj, void *data)
546*318Smax.romanov@nginx.com {
547*318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
548*318Smax.romanov@nginx.com 
549*318Smax.romanov@nginx.com     rp = obj;
550*318Smax.romanov@nginx.com 
551*318Smax.romanov@nginx.com     nxt_mp_release(rp->mem_pool, rp);
552*318Smax.romanov@nginx.com }
553*318Smax.romanov@nginx.com 
554*318Smax.romanov@nginx.com 
55553Sigor@sysoev.ru static nxt_router_temp_conf_t *
556139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
55753Sigor@sysoev.ru {
55865Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
55953Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
56053Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
56153Sigor@sysoev.ru 
56265Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
56353Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
56453Sigor@sysoev.ru         return NULL;
56553Sigor@sysoev.ru     }
56653Sigor@sysoev.ru 
56765Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
56853Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
56953Sigor@sysoev.ru         goto fail;
57053Sigor@sysoev.ru     }
57153Sigor@sysoev.ru 
57253Sigor@sysoev.ru     rtcf->mem_pool = mp;
57353Sigor@sysoev.ru 
57465Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
57553Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
57653Sigor@sysoev.ru         goto fail;
57753Sigor@sysoev.ru     }
57853Sigor@sysoev.ru 
57965Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
58053Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
58153Sigor@sysoev.ru         goto temp_fail;
58253Sigor@sysoev.ru     }
58353Sigor@sysoev.ru 
58453Sigor@sysoev.ru     tmcf->mem_pool = tmp;
58553Sigor@sysoev.ru     tmcf->conf = rtcf;
586139Sigor@sysoev.ru     tmcf->count = 1;
587139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
58853Sigor@sysoev.ru 
58953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
59053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
59153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
59253Sigor@sysoev.ru         goto temp_fail;
59353Sigor@sysoev.ru     }
59453Sigor@sysoev.ru 
59553Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
59653Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
59753Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
59853Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
59953Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
600133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
601133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
60253Sigor@sysoev.ru 
60353Sigor@sysoev.ru     return tmcf;
60453Sigor@sysoev.ru 
60553Sigor@sysoev.ru temp_fail:
60653Sigor@sysoev.ru 
60765Sigor@sysoev.ru     nxt_mp_destroy(tmp);
60853Sigor@sysoev.ru 
60953Sigor@sysoev.ru fail:
61053Sigor@sysoev.ru 
61165Sigor@sysoev.ru     nxt_mp_destroy(mp);
61253Sigor@sysoev.ru 
61353Sigor@sysoev.ru     return NULL;
61453Sigor@sysoev.ru }
61553Sigor@sysoev.ru 
61653Sigor@sysoev.ru 
617198Sigor@sysoev.ru static void
618198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
619139Sigor@sysoev.ru {
620139Sigor@sysoev.ru     nxt_int_t                    ret;
621139Sigor@sysoev.ru     nxt_router_t                 *router;
622139Sigor@sysoev.ru     nxt_runtime_t                *rt;
623198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
624198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
625198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
626139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
627139Sigor@sysoev.ru 
628198Sigor@sysoev.ru     tmcf = obj;
629198Sigor@sysoev.ru 
630198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
631198Sigor@sysoev.ru 
632198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
633198Sigor@sysoev.ru         nxt_queue_remove(qlk);
634198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
635198Sigor@sysoev.ru 
636198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
637198Sigor@sysoev.ru 
638198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
639198Sigor@sysoev.ru 
640198Sigor@sysoev.ru         return;
641139Sigor@sysoev.ru     }
642139Sigor@sysoev.ru 
643139Sigor@sysoev.ru     rt = task->thread->runtime;
644139Sigor@sysoev.ru 
645139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
646139Sigor@sysoev.ru 
647198Sigor@sysoev.ru     router = tmcf->conf->router;
648198Sigor@sysoev.ru 
649139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
650139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
651198Sigor@sysoev.ru         goto fail;
652139Sigor@sysoev.ru     }
653139Sigor@sysoev.ru 
654139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
655139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
656198Sigor@sysoev.ru         goto fail;
657139Sigor@sysoev.ru     }
658139Sigor@sysoev.ru 
659139Sigor@sysoev.ru     nxt_router_apps_sort(router, tmcf);
660139Sigor@sysoev.ru 
661315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
662139Sigor@sysoev.ru 
663139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
664139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
665139Sigor@sysoev.ru 
666198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
667198Sigor@sysoev.ru 
668198Sigor@sysoev.ru     return;
669198Sigor@sysoev.ru 
670198Sigor@sysoev.ru fail:
671198Sigor@sysoev.ru 
672198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
673198Sigor@sysoev.ru 
674198Sigor@sysoev.ru     return;
675139Sigor@sysoev.ru }
676139Sigor@sysoev.ru 
677139Sigor@sysoev.ru 
678139Sigor@sysoev.ru static void
679139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
680139Sigor@sysoev.ru {
681153Sigor@sysoev.ru     nxt_joint_job_t  *job;
682153Sigor@sysoev.ru 
683153Sigor@sysoev.ru     job = obj;
684153Sigor@sysoev.ru 
685198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
686139Sigor@sysoev.ru }
687139Sigor@sysoev.ru 
688139Sigor@sysoev.ru 
689139Sigor@sysoev.ru static void
690198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
691139Sigor@sysoev.ru {
692139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
693139Sigor@sysoev.ru 
694139Sigor@sysoev.ru     if (--tmcf->count == 0) {
695193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
696139Sigor@sysoev.ru     }
697139Sigor@sysoev.ru }
698139Sigor@sysoev.ru 
699139Sigor@sysoev.ru 
700139Sigor@sysoev.ru static void
701139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
702139Sigor@sysoev.ru {
703148Sigor@sysoev.ru     nxt_socket_t       s;
704149Sigor@sysoev.ru     nxt_router_t       *router;
705148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
706148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
707148Sigor@sysoev.ru 
708198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
709198Sigor@sysoev.ru 
710148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
711148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
712148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
713148Sigor@sysoev.ru     {
714148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
715148Sigor@sysoev.ru         s = skcf->listen.socket;
716148Sigor@sysoev.ru 
717148Sigor@sysoev.ru         if (s != -1) {
718148Sigor@sysoev.ru             nxt_socket_close(task, s);
719148Sigor@sysoev.ru         }
720148Sigor@sysoev.ru 
721148Sigor@sysoev.ru         nxt_free(skcf->socket);
722148Sigor@sysoev.ru     }
723148Sigor@sysoev.ru 
724149Sigor@sysoev.ru     router = tmcf->conf->router;
725149Sigor@sysoev.ru 
726149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
727149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
728149Sigor@sysoev.ru 
729148Sigor@sysoev.ru     // TODO: new engines and threads
730148Sigor@sysoev.ru 
731139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
732139Sigor@sysoev.ru 
733193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
734139Sigor@sysoev.ru }
735139Sigor@sysoev.ru 
736139Sigor@sysoev.ru 
737139Sigor@sysoev.ru static void
738139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
739193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
740139Sigor@sysoev.ru {
741193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
742139Sigor@sysoev.ru }
743139Sigor@sysoev.ru 
744139Sigor@sysoev.ru 
745115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
746115Sigor@sysoev.ru     {
747133Sigor@sysoev.ru         nxt_string("listeners_threads"),
748115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
749115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
750115Sigor@sysoev.ru     },
751115Sigor@sysoev.ru };
752115Sigor@sysoev.ru 
753115Sigor@sysoev.ru 
754133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
755115Sigor@sysoev.ru     {
756133Sigor@sysoev.ru         nxt_string("type"),
757115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
758133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
759115Sigor@sysoev.ru     },
760115Sigor@sysoev.ru 
761115Sigor@sysoev.ru     {
762133Sigor@sysoev.ru         nxt_string("workers"),
763115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
764133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
765133Sigor@sysoev.ru     },
766*318Smax.romanov@nginx.com 
767*318Smax.romanov@nginx.com     {
768*318Smax.romanov@nginx.com         nxt_string("limits"),
769*318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
770*318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
771*318Smax.romanov@nginx.com     },
772*318Smax.romanov@nginx.com };
773*318Smax.romanov@nginx.com 
774*318Smax.romanov@nginx.com 
775*318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
776*318Smax.romanov@nginx.com     {
777*318Smax.romanov@nginx.com         nxt_string("timeout"),
778*318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
779*318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
780*318Smax.romanov@nginx.com     },
781*318Smax.romanov@nginx.com 
782*318Smax.romanov@nginx.com     {
783*318Smax.romanov@nginx.com         nxt_string("requests"),
784*318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
785*318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
786*318Smax.romanov@nginx.com     },
787133Sigor@sysoev.ru };
788133Sigor@sysoev.ru 
789133Sigor@sysoev.ru 
790133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
791133Sigor@sysoev.ru     {
792133Sigor@sysoev.ru         nxt_string("application"),
793133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
794133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
795115Sigor@sysoev.ru     },
796115Sigor@sysoev.ru };
797115Sigor@sysoev.ru 
798115Sigor@sysoev.ru 
799115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
800115Sigor@sysoev.ru     {
801115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
802115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
803115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
804115Sigor@sysoev.ru     },
805115Sigor@sysoev.ru 
806115Sigor@sysoev.ru     {
807115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
808115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
809115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
810115Sigor@sysoev.ru     },
811115Sigor@sysoev.ru 
812115Sigor@sysoev.ru     {
813206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
814206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
815206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
816206Smax.romanov@nginx.com     },
817206Smax.romanov@nginx.com 
818206Smax.romanov@nginx.com     {
819206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
820206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
821206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
822206Smax.romanov@nginx.com     },
823206Smax.romanov@nginx.com 
824206Smax.romanov@nginx.com     {
825206Smax.romanov@nginx.com         nxt_string("max_body_size"),
826206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
827206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
828206Smax.romanov@nginx.com     },
829206Smax.romanov@nginx.com 
830206Smax.romanov@nginx.com     {
831115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
832115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
833115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
834115Sigor@sysoev.ru     },
835206Smax.romanov@nginx.com 
836206Smax.romanov@nginx.com     {
837206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
838206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
839206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
840206Smax.romanov@nginx.com     },
841115Sigor@sysoev.ru };
842115Sigor@sysoev.ru 
843115Sigor@sysoev.ru 
84453Sigor@sysoev.ru static nxt_int_t
845115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
846115Sigor@sysoev.ru     u_char *start, u_char *end)
84753Sigor@sysoev.ru {
848133Sigor@sysoev.ru     u_char                      *p;
849133Sigor@sysoev.ru     size_t                      size;
850115Sigor@sysoev.ru     nxt_mp_t                    *mp;
851115Sigor@sysoev.ru     uint32_t                    next;
852115Sigor@sysoev.ru     nxt_int_t                   ret;
853115Sigor@sysoev.ru     nxt_str_t                   name;
854133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
855133Sigor@sysoev.ru     nxt_app_type_t              type;
856115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
857133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
858133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
859133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
860115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
861216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
862133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
863115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
864115Sigor@sysoev.ru 
865115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
866133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
867115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
868115Sigor@sysoev.ru 
869208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
870115Sigor@sysoev.ru     if (conf == NULL) {
871115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
872115Sigor@sysoev.ru         return NXT_ERROR;
873115Sigor@sysoev.ru     }
874115Sigor@sysoev.ru 
875213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
876213Svbart@nginx.com 
877213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
878136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
879115Sigor@sysoev.ru     if (ret != NXT_OK) {
880133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
881115Sigor@sysoev.ru         return NXT_ERROR;
882115Sigor@sysoev.ru     }
883115Sigor@sysoev.ru 
884117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
885117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
886117Sigor@sysoev.ru     }
887117Sigor@sysoev.ru 
888133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
889133Sigor@sysoev.ru     if (applications == NULL) {
890133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
891115Sigor@sysoev.ru         return NXT_ERROR;
892115Sigor@sysoev.ru     }
893115Sigor@sysoev.ru 
894133Sigor@sysoev.ru     next = 0;
895133Sigor@sysoev.ru 
896133Sigor@sysoev.ru     for ( ;; ) {
897133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
898133Sigor@sysoev.ru         if (application == NULL) {
899133Sigor@sysoev.ru             break;
900133Sigor@sysoev.ru         }
901133Sigor@sysoev.ru 
902133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
903133Sigor@sysoev.ru 
904144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
905144Smax.romanov@nginx.com 
906144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
907133Sigor@sysoev.ru         if (app == NULL) {
908133Sigor@sysoev.ru             goto fail;
909133Sigor@sysoev.ru         }
910133Sigor@sysoev.ru 
911144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
912144Smax.romanov@nginx.com 
913144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
914144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
915133Sigor@sysoev.ru 
916133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
917133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
918133Sigor@sysoev.ru 
919144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
920144Smax.romanov@nginx.com 
921133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
922133Sigor@sysoev.ru 
923133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
924133Sigor@sysoev.ru 
925133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
926133Sigor@sysoev.ru             nxt_free(app);
927133Sigor@sysoev.ru 
928133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
929133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
930133Sigor@sysoev.ru             continue;
931133Sigor@sysoev.ru         }
932133Sigor@sysoev.ru 
933263Smax.romanov@nginx.com         apcf.workers = 1;
934*318Smax.romanov@nginx.com         apcf.timeout = 0;
935*318Smax.romanov@nginx.com         apcf.requests = 0;
936*318Smax.romanov@nginx.com         apcf.limits_value = NULL;
937263Smax.romanov@nginx.com 
938213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
939136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
940133Sigor@sysoev.ru         if (ret != NXT_OK) {
941133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
942133Sigor@sysoev.ru             goto app_fail;
943133Sigor@sysoev.ru         }
944115Sigor@sysoev.ru 
945*318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
946*318Smax.romanov@nginx.com 
947*318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
948*318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits is not object");
949*318Smax.romanov@nginx.com                 goto app_fail;
950*318Smax.romanov@nginx.com             }
951*318Smax.romanov@nginx.com 
952*318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
953*318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
954*318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
955*318Smax.romanov@nginx.com                                       &apcf);
956*318Smax.romanov@nginx.com             if (ret != NXT_OK) {
957*318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits map error");
958*318Smax.romanov@nginx.com                 goto app_fail;
959*318Smax.romanov@nginx.com             }
960*318Smax.romanov@nginx.com         }
961*318Smax.romanov@nginx.com 
962133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
963133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
964*318Smax.romanov@nginx.com         nxt_debug(task, "application timeout: %D", apcf.timeout);
965*318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
966133Sigor@sysoev.ru 
967216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
968216Sigor@sysoev.ru 
969216Sigor@sysoev.ru         if (lang == NULL) {
970141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
971141Smax.romanov@nginx.com                     &apcf.type);
972141Smax.romanov@nginx.com             goto app_fail;
973141Smax.romanov@nginx.com         }
974141Smax.romanov@nginx.com 
975216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
976216Sigor@sysoev.ru 
977216Sigor@sysoev.ru         type = nxt_app_parse_type(&lang->type);
978216Sigor@sysoev.ru 
979216Sigor@sysoev.ru         if (type == NXT_APP_UNKNOWN) {
980216Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
981216Sigor@sysoev.ru                     &lang->type);
982216Sigor@sysoev.ru             goto app_fail;
983216Sigor@sysoev.ru         }
984216Sigor@sysoev.ru 
985216Sigor@sysoev.ru         if (nxt_app_prepare_msg[type] == NULL) {
986133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
987216Sigor@sysoev.ru                     &lang->type);
988133Sigor@sysoev.ru             goto app_fail;
989133Sigor@sysoev.ru         }
990133Sigor@sysoev.ru 
991133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
992133Sigor@sysoev.ru         if (ret != NXT_OK) {
993133Sigor@sysoev.ru             goto app_fail;
994133Sigor@sysoev.ru         }
995133Sigor@sysoev.ru 
996141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
997141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
998141Smax.romanov@nginx.com 
999144Smax.romanov@nginx.com         app->name.length = name.length;
1000144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1001144Smax.romanov@nginx.com 
1002133Sigor@sysoev.ru         app->type = type;
1003133Sigor@sysoev.ru         app->max_workers = apcf.workers;
1004*318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1005133Sigor@sysoev.ru         app->live = 1;
1006216Sigor@sysoev.ru         app->prepare_msg = nxt_app_prepare_msg[type];
1007133Sigor@sysoev.ru 
1008133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1009133Sigor@sysoev.ru     }
1010133Sigor@sysoev.ru 
1011133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1012133Sigor@sysoev.ru #if 0
1013133Sigor@sysoev.ru     if (http == NULL) {
1014133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
1015133Sigor@sysoev.ru         return NXT_ERROR;
1016133Sigor@sysoev.ru     }
1017133Sigor@sysoev.ru #endif
1018133Sigor@sysoev.ru 
1019133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1020115Sigor@sysoev.ru     if (listeners == NULL) {
1021133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
1022115Sigor@sysoev.ru         return NXT_ERROR;
1023115Sigor@sysoev.ru     }
102453Sigor@sysoev.ru 
1025133Sigor@sysoev.ru     next = 0;
102653Sigor@sysoev.ru 
1027115Sigor@sysoev.ru     for ( ;; ) {
1028115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1029115Sigor@sysoev.ru         if (listener == NULL) {
1030115Sigor@sysoev.ru             break;
1031115Sigor@sysoev.ru         }
103253Sigor@sysoev.ru 
1033115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
1034115Sigor@sysoev.ru         if (sa == NULL) {
1035115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
1036133Sigor@sysoev.ru             goto fail;
1037115Sigor@sysoev.ru         }
1038115Sigor@sysoev.ru 
1039115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
1040115Sigor@sysoev.ru 
1041115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
1042115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
104353Sigor@sysoev.ru 
1044115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
1045115Sigor@sysoev.ru         if (skcf == NULL) {
1046133Sigor@sysoev.ru             goto fail;
1047115Sigor@sysoev.ru         }
104853Sigor@sysoev.ru 
1049213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1050136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1051115Sigor@sysoev.ru         if (ret != NXT_OK) {
1052115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
1053133Sigor@sysoev.ru             goto fail;
1054115Sigor@sysoev.ru         }
105553Sigor@sysoev.ru 
1056133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1057133Sigor@sysoev.ru 
1058133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1059133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1060133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1061206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1062206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1063206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
1064133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
1065206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
106653Sigor@sysoev.ru 
1067133Sigor@sysoev.ru         if (http != NULL) {
1068213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1069136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1070133Sigor@sysoev.ru             if (ret != NXT_OK) {
1071133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
1072133Sigor@sysoev.ru                 goto fail;
1073133Sigor@sysoev.ru             }
1074115Sigor@sysoev.ru         }
1075115Sigor@sysoev.ru 
1076115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
1077115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
1078160Sigor@sysoev.ru         skcf->router_conf->count++;
1079133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
1080133Sigor@sysoev.ru                                                             &lscf.application);
1081115Sigor@sysoev.ru 
1082115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
1083115Sigor@sysoev.ru     }
108453Sigor@sysoev.ru 
1085198Sigor@sysoev.ru     nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf);
1086198Sigor@sysoev.ru 
108753Sigor@sysoev.ru     return NXT_OK;
1088133Sigor@sysoev.ru 
1089133Sigor@sysoev.ru app_fail:
1090133Sigor@sysoev.ru 
1091133Sigor@sysoev.ru     nxt_free(app);
1092133Sigor@sysoev.ru 
1093133Sigor@sysoev.ru fail:
1094133Sigor@sysoev.ru 
1095141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1096141Smax.romanov@nginx.com 
1097141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1098133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1099133Sigor@sysoev.ru         nxt_free(app);
1100141Smax.romanov@nginx.com 
1101141Smax.romanov@nginx.com     } nxt_queue_loop;
1102133Sigor@sysoev.ru 
1103133Sigor@sysoev.ru     return NXT_ERROR;
1104133Sigor@sysoev.ru }
1105133Sigor@sysoev.ru 
1106133Sigor@sysoev.ru 
1107133Sigor@sysoev.ru static nxt_app_t *
1108133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1109133Sigor@sysoev.ru {
1110141Smax.romanov@nginx.com     nxt_app_t  *app;
1111141Smax.romanov@nginx.com 
1112141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1113133Sigor@sysoev.ru 
1114133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1115133Sigor@sysoev.ru             return app;
1116133Sigor@sysoev.ru         }
1117141Smax.romanov@nginx.com 
1118141Smax.romanov@nginx.com     } nxt_queue_loop;
1119133Sigor@sysoev.ru 
1120133Sigor@sysoev.ru     return NULL;
1121133Sigor@sysoev.ru }
1122133Sigor@sysoev.ru 
1123133Sigor@sysoev.ru 
1124133Sigor@sysoev.ru static nxt_app_t *
1125133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1126133Sigor@sysoev.ru {
1127133Sigor@sysoev.ru     nxt_app_t  *app;
1128133Sigor@sysoev.ru 
1129133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1130133Sigor@sysoev.ru 
1131133Sigor@sysoev.ru     if (app == NULL) {
1132134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1133133Sigor@sysoev.ru     }
1134133Sigor@sysoev.ru 
1135133Sigor@sysoev.ru     return app;
113653Sigor@sysoev.ru }
113753Sigor@sysoev.ru 
113853Sigor@sysoev.ru 
113953Sigor@sysoev.ru static nxt_socket_conf_t *
114065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
114153Sigor@sysoev.ru {
1142163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
1143163Smax.romanov@nginx.com 
1144163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
1145163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
114653Sigor@sysoev.ru         return NULL;
114753Sigor@sysoev.ru     }
114853Sigor@sysoev.ru 
1149163Smax.romanov@nginx.com     skcf->sockaddr = sa;
1150163Smax.romanov@nginx.com 
1151163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
1152312Sigor@sysoev.ru 
1153312Sigor@sysoev.ru     nxt_listen_socket_remote_size(&skcf->listen, sa);
1154163Smax.romanov@nginx.com 
1155163Smax.romanov@nginx.com     skcf->listen.socket = -1;
1156163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
1157163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
1158163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
1159163Smax.romanov@nginx.com 
1160163Smax.romanov@nginx.com     return skcf;
116153Sigor@sysoev.ru }
116253Sigor@sysoev.ru 
116353Sigor@sysoev.ru 
116453Sigor@sysoev.ru static void
116553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
116653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
116753Sigor@sysoev.ru {
116853Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
116953Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
117053Sigor@sysoev.ru 
117153Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
117253Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
117353Sigor@sysoev.ru          nqlk = next)
117453Sigor@sysoev.ru     {
117553Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
117653Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
117753Sigor@sysoev.ru 
117853Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
117953Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
118053Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
118153Sigor@sysoev.ru         {
118253Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
118353Sigor@sysoev.ru 
1184115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
1185115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
1186115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
1187115Sigor@sysoev.ru 
118853Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
118953Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
119053Sigor@sysoev.ru 
119153Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
119253Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
119353Sigor@sysoev.ru 
119453Sigor@sysoev.ru                 break;
119553Sigor@sysoev.ru             }
119653Sigor@sysoev.ru         }
119753Sigor@sysoev.ru     }
119853Sigor@sysoev.ru 
119953Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1200115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
120153Sigor@sysoev.ru }
120253Sigor@sysoev.ru 
120353Sigor@sysoev.ru 
1204198Sigor@sysoev.ru static void
1205198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1206198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1207198Sigor@sysoev.ru {
1208198Sigor@sysoev.ru     uint32_t          stream;
1209198Sigor@sysoev.ru     nxt_buf_t         *b;
1210198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1211198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1212198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1213198Sigor@sysoev.ru 
1214198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1215198Sigor@sysoev.ru     if (rpc == NULL) {
1216198Sigor@sysoev.ru         goto fail;
1217198Sigor@sysoev.ru     }
1218198Sigor@sysoev.ru 
1219198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1220198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1221198Sigor@sysoev.ru 
1222198Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0);
1223198Sigor@sysoev.ru     if (b == NULL) {
1224198Sigor@sysoev.ru         goto fail;
1225198Sigor@sysoev.ru     }
1226198Sigor@sysoev.ru 
1227198Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr,
1228198Sigor@sysoev.ru                              skcf->sockaddr->sockaddr_size);
1229198Sigor@sysoev.ru 
1230198Sigor@sysoev.ru     rt = task->thread->runtime;
1231240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1232198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1233198Sigor@sysoev.ru 
1234198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1235198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1236198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1237198Sigor@sysoev.ru                                            main_port->pid, rpc);
1238198Sigor@sysoev.ru     if (stream == 0) {
1239198Sigor@sysoev.ru         goto fail;
1240198Sigor@sysoev.ru     }
1241198Sigor@sysoev.ru 
1242198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1243198Sigor@sysoev.ru                           stream, router_port->id, b);
1244198Sigor@sysoev.ru 
1245198Sigor@sysoev.ru     return;
1246198Sigor@sysoev.ru 
1247198Sigor@sysoev.ru fail:
1248198Sigor@sysoev.ru 
1249198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1250198Sigor@sysoev.ru }
1251198Sigor@sysoev.ru 
1252198Sigor@sysoev.ru 
1253198Sigor@sysoev.ru static void
1254198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1255198Sigor@sysoev.ru     void *data)
125653Sigor@sysoev.ru {
1257115Sigor@sysoev.ru     nxt_int_t            ret;
1258115Sigor@sysoev.ru     nxt_socket_t         s;
1259198Sigor@sysoev.ru     nxt_socket_rpc_t     *rpc;
1260115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
126153Sigor@sysoev.ru 
1262198Sigor@sysoev.ru     rpc = data;
1263198Sigor@sysoev.ru 
1264198Sigor@sysoev.ru     s = msg->fd;
1265198Sigor@sysoev.ru 
1266198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1267198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1268198Sigor@sysoev.ru         goto fail;
126953Sigor@sysoev.ru     }
127053Sigor@sysoev.ru 
1271229Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr);
1272198Sigor@sysoev.ru 
1273198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1274198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1275198Sigor@sysoev.ru         goto fail;
1276198Sigor@sysoev.ru     }
1277198Sigor@sysoev.ru 
1278198Sigor@sysoev.ru     rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
1279198Sigor@sysoev.ru     if (nxt_slow_path(rtsk == NULL)) {
1280198Sigor@sysoev.ru         goto fail;
1281198Sigor@sysoev.ru     }
1282198Sigor@sysoev.ru 
1283198Sigor@sysoev.ru     rtsk->count = 0;
1284198Sigor@sysoev.ru     rtsk->fd = s;
1285198Sigor@sysoev.ru 
1286198Sigor@sysoev.ru     rpc->socket_conf->listen.socket = s;
1287198Sigor@sysoev.ru     rpc->socket_conf->socket = rtsk;
1288198Sigor@sysoev.ru 
1289198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1290198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1291198Sigor@sysoev.ru 
1292198Sigor@sysoev.ru     return;
1293148Sigor@sysoev.ru 
1294148Sigor@sysoev.ru fail:
1295148Sigor@sysoev.ru 
1296148Sigor@sysoev.ru     nxt_socket_close(task, s);
1297148Sigor@sysoev.ru 
1298198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1299198Sigor@sysoev.ru }
1300198Sigor@sysoev.ru 
1301198Sigor@sysoev.ru 
1302198Sigor@sysoev.ru static void
1303198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1304198Sigor@sysoev.ru     void *data)
1305198Sigor@sysoev.ru {
1306198Sigor@sysoev.ru     u_char                  *p;
1307198Sigor@sysoev.ru     size_t                  size;
1308198Sigor@sysoev.ru     uint8_t                 error;
1309198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1310198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1311198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1312198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1313198Sigor@sysoev.ru 
1314198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1315198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1316198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1317198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1318198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1319198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1320198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1321198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1322198Sigor@sysoev.ru     };
1323198Sigor@sysoev.ru 
1324198Sigor@sysoev.ru     rpc = data;
1325198Sigor@sysoev.ru     sa = rpc->socket_conf->sockaddr;
1326198Sigor@sysoev.ru 
1327198Sigor@sysoev.ru     in = msg->buf;
1328198Sigor@sysoev.ru     p = in->mem.pos;
1329198Sigor@sysoev.ru 
1330198Sigor@sysoev.ru     error = *p++;
1331198Sigor@sysoev.ru 
1332198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1333198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1334198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1335198Sigor@sysoev.ru 
1336198Sigor@sysoev.ru     tmcf = rpc->temp_conf;
1337198Sigor@sysoev.ru 
1338198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1339198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1340198Sigor@sysoev.ru         return;
1341198Sigor@sysoev.ru     }
1342198Sigor@sysoev.ru 
1343198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1344198Sigor@sysoev.ru                         "listen socket error: "
1345198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1346198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1347198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1348198Sigor@sysoev.ru 
1349198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1350198Sigor@sysoev.ru 
1351198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
135253Sigor@sysoev.ru }
135353Sigor@sysoev.ru 
135453Sigor@sysoev.ru 
135553Sigor@sysoev.ru static nxt_int_t
135653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
135753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
135853Sigor@sysoev.ru {
135953Sigor@sysoev.ru     nxt_int_t                 ret;
136053Sigor@sysoev.ru     nxt_uint_t                n, threads;
136153Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
136253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
136353Sigor@sysoev.ru 
136453Sigor@sysoev.ru     threads = tmcf->conf->threads;
136553Sigor@sysoev.ru 
136653Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
136753Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
136853Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
136953Sigor@sysoev.ru         return NXT_ERROR;
137053Sigor@sysoev.ru     }
137153Sigor@sysoev.ru 
137253Sigor@sysoev.ru     n = 0;
137353Sigor@sysoev.ru 
137453Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
137553Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
137653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
137753Sigor@sysoev.ru     {
137853Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
137953Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
138053Sigor@sysoev.ru             return NXT_ERROR;
138153Sigor@sysoev.ru         }
138253Sigor@sysoev.ru 
1383115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
138453Sigor@sysoev.ru 
138553Sigor@sysoev.ru         if (n < threads) {
1386315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1387115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
138853Sigor@sysoev.ru 
138953Sigor@sysoev.ru         } else {
1390315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1391115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
139253Sigor@sysoev.ru         }
139353Sigor@sysoev.ru 
139453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
139553Sigor@sysoev.ru             return ret;
139653Sigor@sysoev.ru         }
139753Sigor@sysoev.ru 
139853Sigor@sysoev.ru         n++;
139953Sigor@sysoev.ru     }
140053Sigor@sysoev.ru 
140153Sigor@sysoev.ru     tmcf->new_threads = n;
140253Sigor@sysoev.ru 
140353Sigor@sysoev.ru     while (n < threads) {
140453Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
140553Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
140653Sigor@sysoev.ru             return NXT_ERROR;
140753Sigor@sysoev.ru         }
140853Sigor@sysoev.ru 
1409315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1410315Sigor@sysoev.ru 
141153Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
141253Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
141353Sigor@sysoev.ru             return NXT_ERROR;
141453Sigor@sysoev.ru         }
141553Sigor@sysoev.ru 
1416115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
141753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
141853Sigor@sysoev.ru             return ret;
141953Sigor@sysoev.ru         }
142053Sigor@sysoev.ru 
142153Sigor@sysoev.ru         n++;
142253Sigor@sysoev.ru     }
142353Sigor@sysoev.ru 
142453Sigor@sysoev.ru     return NXT_OK;
142553Sigor@sysoev.ru }
142653Sigor@sysoev.ru 
142753Sigor@sysoev.ru 
142853Sigor@sysoev.ru static nxt_int_t
1429115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1430115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
143153Sigor@sysoev.ru {
1432115Sigor@sysoev.ru     nxt_int_t              ret;
1433115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
143453Sigor@sysoev.ru 
1435154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1436154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1437115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1438115Sigor@sysoev.ru         return ret;
1439115Sigor@sysoev.ru     }
1440115Sigor@sysoev.ru 
1441154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1442154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
144353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
144453Sigor@sysoev.ru         return ret;
144553Sigor@sysoev.ru     }
144653Sigor@sysoev.ru 
1447115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1448115Sigor@sysoev.ru 
1449115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1450115Sigor@sysoev.ru 
1451115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1452115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1453115Sigor@sysoev.ru 
1454115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1455115Sigor@sysoev.ru 
1456115Sigor@sysoev.ru     return ret;
145753Sigor@sysoev.ru }
145853Sigor@sysoev.ru 
145953Sigor@sysoev.ru 
146053Sigor@sysoev.ru static nxt_int_t
1461115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1462115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
146353Sigor@sysoev.ru {
1464115Sigor@sysoev.ru     nxt_int_t              ret;
1465115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
146653Sigor@sysoev.ru 
1467154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1468154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
146953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
147053Sigor@sysoev.ru         return ret;
147153Sigor@sysoev.ru     }
147253Sigor@sysoev.ru 
1473154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1474154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
147553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
147653Sigor@sysoev.ru         return ret;
147753Sigor@sysoev.ru     }
147853Sigor@sysoev.ru 
1479139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1480115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1481115Sigor@sysoev.ru         return ret;
1482115Sigor@sysoev.ru     }
1483115Sigor@sysoev.ru 
1484115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1485115Sigor@sysoev.ru 
1486115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1487115Sigor@sysoev.ru 
1488115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1489115Sigor@sysoev.ru 
1490115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1491115Sigor@sysoev.ru 
1492115Sigor@sysoev.ru     return ret;
149353Sigor@sysoev.ru }
149453Sigor@sysoev.ru 
149553Sigor@sysoev.ru 
149653Sigor@sysoev.ru static nxt_int_t
1497115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1498115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
149953Sigor@sysoev.ru {
150053Sigor@sysoev.ru     nxt_int_t  ret;
150153Sigor@sysoev.ru 
1502313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1503313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1504313Sigor@sysoev.ru         return ret;
1505313Sigor@sysoev.ru     }
1506313Sigor@sysoev.ru 
1507139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
150853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
150953Sigor@sysoev.ru         return ret;
151053Sigor@sysoev.ru     }
151153Sigor@sysoev.ru 
1512139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
151353Sigor@sysoev.ru }
151453Sigor@sysoev.ru 
151553Sigor@sysoev.ru 
151653Sigor@sysoev.ru static nxt_int_t
1517154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1518154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
151953Sigor@sysoev.ru     nxt_work_handler_t handler)
152053Sigor@sysoev.ru {
1521153Sigor@sysoev.ru     nxt_joint_job_t          *job;
152253Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1523155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
152453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
152553Sigor@sysoev.ru 
152653Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
152753Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
152853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
152953Sigor@sysoev.ru     {
1530154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1531153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1532139Sigor@sysoev.ru             return NXT_ERROR;
1533139Sigor@sysoev.ru         }
1534139Sigor@sysoev.ru 
1535154Sigor@sysoev.ru         job->work.next = recf->jobs;
1536154Sigor@sysoev.ru         recf->jobs = &job->work;
1537154Sigor@sysoev.ru 
1538153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1539153Sigor@sysoev.ru         job->work.handler = handler;
1540153Sigor@sysoev.ru         job->work.task = &job->task;
1541153Sigor@sysoev.ru         job->work.obj = job;
1542153Sigor@sysoev.ru         job->tmcf = tmcf;
154353Sigor@sysoev.ru 
1544154Sigor@sysoev.ru         tmcf->count++;
1545154Sigor@sysoev.ru 
1546154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1547154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
154853Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
154953Sigor@sysoev.ru             return NXT_ERROR;
155053Sigor@sysoev.ru         }
155153Sigor@sysoev.ru 
1552153Sigor@sysoev.ru         job->work.data = joint;
155353Sigor@sysoev.ru 
155453Sigor@sysoev.ru         joint->count = 1;
1555155Sigor@sysoev.ru 
1556155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1557155Sigor@sysoev.ru         skcf->count++;
1558155Sigor@sysoev.ru         joint->socket_conf = skcf;
1559155Sigor@sysoev.ru 
156088Smax.romanov@nginx.com         joint->engine = recf->engine;
156153Sigor@sysoev.ru     }
156253Sigor@sysoev.ru 
156320Sigor@sysoev.ru     return NXT_OK;
156420Sigor@sysoev.ru }
156520Sigor@sysoev.ru 
156620Sigor@sysoev.ru 
1567115Sigor@sysoev.ru static void
1568115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1569115Sigor@sysoev.ru {
1570115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1571115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1572115Sigor@sysoev.ru 
1573115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1574115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1575115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1576115Sigor@sysoev.ru     {
1577115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1578115Sigor@sysoev.ru         skcf->socket->count++;
1579115Sigor@sysoev.ru     }
1580115Sigor@sysoev.ru }
1581115Sigor@sysoev.ru 
1582115Sigor@sysoev.ru 
158320Sigor@sysoev.ru static nxt_int_t
1584313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
1585313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
1586313Sigor@sysoev.ru {
1587313Sigor@sysoev.ru     nxt_joint_job_t  *job;
1588313Sigor@sysoev.ru 
1589313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1590313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
1591313Sigor@sysoev.ru         return NXT_ERROR;
1592313Sigor@sysoev.ru     }
1593313Sigor@sysoev.ru 
1594313Sigor@sysoev.ru     job->work.next = recf->jobs;
1595313Sigor@sysoev.ru     recf->jobs = &job->work;
1596313Sigor@sysoev.ru 
1597313Sigor@sysoev.ru     job->task = tmcf->engine->task;
1598313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
1599313Sigor@sysoev.ru     job->work.task = &job->task;
1600313Sigor@sysoev.ru     job->work.obj = NULL;
1601313Sigor@sysoev.ru     job->work.data = NULL;
1602313Sigor@sysoev.ru     job->tmcf = NULL;
1603313Sigor@sysoev.ru 
1604313Sigor@sysoev.ru     return NXT_OK;
1605313Sigor@sysoev.ru }
1606313Sigor@sysoev.ru 
1607313Sigor@sysoev.ru 
1608313Sigor@sysoev.ru static nxt_int_t
1609139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1610139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
161120Sigor@sysoev.ru {
1612153Sigor@sysoev.ru     nxt_joint_job_t   *job;
161353Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
161420Sigor@sysoev.ru 
161553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
161653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
161753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
161853Sigor@sysoev.ru     {
1619154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1620153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1621139Sigor@sysoev.ru             return NXT_ERROR;
1622139Sigor@sysoev.ru         }
1623139Sigor@sysoev.ru 
1624154Sigor@sysoev.ru         job->work.next = recf->jobs;
1625154Sigor@sysoev.ru         recf->jobs = &job->work;
1626154Sigor@sysoev.ru 
1627153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1628153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1629153Sigor@sysoev.ru         job->work.task = &job->task;
1630153Sigor@sysoev.ru         job->work.obj = job;
1631153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1632153Sigor@sysoev.ru         job->tmcf = tmcf;
1633154Sigor@sysoev.ru 
1634154Sigor@sysoev.ru         tmcf->count++;
163520Sigor@sysoev.ru     }
163620Sigor@sysoev.ru 
163753Sigor@sysoev.ru     return NXT_OK;
163853Sigor@sysoev.ru }
163920Sigor@sysoev.ru 
164020Sigor@sysoev.ru 
164153Sigor@sysoev.ru static nxt_int_t
164253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
164353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
164453Sigor@sysoev.ru {
164553Sigor@sysoev.ru     nxt_int_t                 ret;
164653Sigor@sysoev.ru     nxt_uint_t                i, threads;
164753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
164820Sigor@sysoev.ru 
164953Sigor@sysoev.ru     recf = tmcf->engines->elts;
165053Sigor@sysoev.ru     threads = tmcf->conf->threads;
165120Sigor@sysoev.ru 
165253Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
165353Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
165453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
165553Sigor@sysoev.ru             return ret;
165653Sigor@sysoev.ru         }
165720Sigor@sysoev.ru     }
165820Sigor@sysoev.ru 
165920Sigor@sysoev.ru     return NXT_OK;
166020Sigor@sysoev.ru }
166153Sigor@sysoev.ru 
166253Sigor@sysoev.ru 
166353Sigor@sysoev.ru static nxt_int_t
166453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
166553Sigor@sysoev.ru     nxt_event_engine_t *engine)
166653Sigor@sysoev.ru {
166753Sigor@sysoev.ru     nxt_int_t            ret;
166853Sigor@sysoev.ru     nxt_thread_link_t    *link;
166953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
167053Sigor@sysoev.ru 
167153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
167253Sigor@sysoev.ru 
167353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
167453Sigor@sysoev.ru         return NXT_ERROR;
167553Sigor@sysoev.ru     }
167653Sigor@sysoev.ru 
167753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
167853Sigor@sysoev.ru     link->engine = engine;
167953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
168053Sigor@sysoev.ru     link->work.task = task;
168153Sigor@sysoev.ru     link->work.data = link;
168253Sigor@sysoev.ru 
168353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
168453Sigor@sysoev.ru 
168553Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
168653Sigor@sysoev.ru 
168753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
168853Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
168953Sigor@sysoev.ru     }
169053Sigor@sysoev.ru 
169153Sigor@sysoev.ru     return ret;
169253Sigor@sysoev.ru }
169353Sigor@sysoev.ru 
169453Sigor@sysoev.ru 
169553Sigor@sysoev.ru static void
1696133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
1697133Sigor@sysoev.ru {
1698167Smax.romanov@nginx.com     nxt_app_t    *app;
1699167Smax.romanov@nginx.com     nxt_port_t   *port;
1700141Smax.romanov@nginx.com 
1701141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1702133Sigor@sysoev.ru 
1703133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1704133Sigor@sysoev.ru 
1705167Smax.romanov@nginx.com         nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app);
1706167Smax.romanov@nginx.com 
1707163Smax.romanov@nginx.com         app->live = 0;
1708163Smax.romanov@nginx.com 
1709167Smax.romanov@nginx.com         if (nxt_router_app_free(NULL, app) != 0) {
1710163Smax.romanov@nginx.com             continue;
1711163Smax.romanov@nginx.com         }
1712163Smax.romanov@nginx.com 
1713167Smax.romanov@nginx.com         if (!nxt_queue_is_empty(&app->requests)) {
1714167Smax.romanov@nginx.com 
1715167Smax.romanov@nginx.com             nxt_thread_log_debug("app '%V' %p pending requests found",
1716167Smax.romanov@nginx.com                                  &app->name, app);
1717167Smax.romanov@nginx.com             continue;
1718163Smax.romanov@nginx.com         }
1719163Smax.romanov@nginx.com 
1720167Smax.romanov@nginx.com         do {
1721167Smax.romanov@nginx.com             port = nxt_router_app_get_port(app, 0);
1722167Smax.romanov@nginx.com             if (port == NULL) {
1723167Smax.romanov@nginx.com                 break;
1724167Smax.romanov@nginx.com             }
1725167Smax.romanov@nginx.com 
1726167Smax.romanov@nginx.com             nxt_thread_log_debug("port %p send quit", port);
1727167Smax.romanov@nginx.com 
1728167Smax.romanov@nginx.com             nxt_port_socket_write(&port->engine->task, port,
1729167Smax.romanov@nginx.com                                   NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
1730167Smax.romanov@nginx.com         } while (1);
1731167Smax.romanov@nginx.com 
1732141Smax.romanov@nginx.com     } nxt_queue_loop;
1733133Sigor@sysoev.ru 
1734133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1735133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1736133Sigor@sysoev.ru }
1737133Sigor@sysoev.ru 
1738133Sigor@sysoev.ru 
1739133Sigor@sysoev.ru static void
1740315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
174153Sigor@sysoev.ru {
174253Sigor@sysoev.ru     nxt_uint_t                n;
1743315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
174453Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
174553Sigor@sysoev.ru 
174653Sigor@sysoev.ru     recf = tmcf->engines->elts;
174753Sigor@sysoev.ru 
174853Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1749315Sigor@sysoev.ru         engine = recf->engine;
1750315Sigor@sysoev.ru 
1751315Sigor@sysoev.ru         switch (recf->action) {
1752315Sigor@sysoev.ru 
1753315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
1754315Sigor@sysoev.ru             break;
1755315Sigor@sysoev.ru 
1756315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
1757315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
1758315Sigor@sysoev.ru             break;
1759315Sigor@sysoev.ru 
1760315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
1761315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
1762315Sigor@sysoev.ru             break;
1763315Sigor@sysoev.ru         }
1764315Sigor@sysoev.ru 
1765316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
1766316Sigor@sysoev.ru 
176753Sigor@sysoev.ru         recf++;
176853Sigor@sysoev.ru     }
176953Sigor@sysoev.ru }
177053Sigor@sysoev.ru 
177153Sigor@sysoev.ru 
177253Sigor@sysoev.ru static void
1773315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
177453Sigor@sysoev.ru {
1775154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1776154Sigor@sysoev.ru 
1777315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
1778154Sigor@sysoev.ru         next = work->next;
1779154Sigor@sysoev.ru         work->next = NULL;
1780154Sigor@sysoev.ru 
1781315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
178253Sigor@sysoev.ru     }
178353Sigor@sysoev.ru }
178453Sigor@sysoev.ru 
178553Sigor@sysoev.ru 
1786119Smax.romanov@nginx.com static nxt_port_handler_t  nxt_router_app_port_handlers[] = {
1787192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_QUIT         */
1788192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_NEW_PORT     */
1789192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_CHANGE_FILE  */
1790192Smax.romanov@nginx.com     /* TODO: remove mmap_handler from app ports */
1791192Smax.romanov@nginx.com     nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP         */
1792*318Smax.romanov@nginx.com     nxt_port_rpc_handler,  /* NXT_PORT_MSG_DATA         */
1793192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_REMOVE_PID   */
1794192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_READY        */
1795192Smax.romanov@nginx.com     NULL, /* NXT_PORT_MSG_START_WORKER */
1796317Svbart@nginx.com     NULL, /* NXT_PORT_MSG_SOCKET       */
1797317Svbart@nginx.com     NULL, /* NXT_PORT_MSG_MODULES      */
1798317Svbart@nginx.com     NULL, /* NXT_PORT_MSG_CONF_STORE   */
1799190Smax.romanov@nginx.com     nxt_port_rpc_handler,
1800190Smax.romanov@nginx.com     nxt_port_rpc_handler,
180188Smax.romanov@nginx.com };
180288Smax.romanov@nginx.com 
180388Smax.romanov@nginx.com 
180488Smax.romanov@nginx.com static void
180553Sigor@sysoev.ru nxt_router_thread_start(void *data)
180653Sigor@sysoev.ru {
1807141Smax.romanov@nginx.com     nxt_int_t           ret;
1808141Smax.romanov@nginx.com     nxt_port_t          *port;
180988Smax.romanov@nginx.com     nxt_task_t          *task;
181053Sigor@sysoev.ru     nxt_thread_t        *thread;
181153Sigor@sysoev.ru     nxt_thread_link_t   *link;
181253Sigor@sysoev.ru     nxt_event_engine_t  *engine;
181353Sigor@sysoev.ru 
181453Sigor@sysoev.ru     link = data;
181553Sigor@sysoev.ru     engine = link->engine;
181688Smax.romanov@nginx.com     task = &engine->task;
181753Sigor@sysoev.ru 
181853Sigor@sysoev.ru     thread = nxt_thread();
181953Sigor@sysoev.ru 
1820165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1821165Smax.romanov@nginx.com 
182253Sigor@sysoev.ru     /* STUB */
182353Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
182453Sigor@sysoev.ru 
182553Sigor@sysoev.ru     engine->task.thread = thread;
182653Sigor@sysoev.ru     engine->task.log = thread->log;
182753Sigor@sysoev.ru     thread->engine = engine;
182863Sigor@sysoev.ru     thread->task = &engine->task;
182953Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
183053Sigor@sysoev.ru 
183163Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
183253Sigor@sysoev.ru 
1833197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1834197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1835141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1836141Smax.romanov@nginx.com         return;
1837141Smax.romanov@nginx.com     }
1838141Smax.romanov@nginx.com 
1839141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1840141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1841163Smax.romanov@nginx.com         nxt_mp_release(port->mem_pool, port);
1842141Smax.romanov@nginx.com         return;
1843141Smax.romanov@nginx.com     }
1844141Smax.romanov@nginx.com 
1845141Smax.romanov@nginx.com     engine->port = port;
1846141Smax.romanov@nginx.com 
1847141Smax.romanov@nginx.com     nxt_port_enable(task, port, nxt_router_app_port_handlers);
1848141Smax.romanov@nginx.com 
184953Sigor@sysoev.ru     nxt_event_engine_start(engine);
185053Sigor@sysoev.ru }
185153Sigor@sysoev.ru 
185253Sigor@sysoev.ru 
185353Sigor@sysoev.ru static void
185453Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
185553Sigor@sysoev.ru {
1856153Sigor@sysoev.ru     nxt_joint_job_t          *job;
185753Sigor@sysoev.ru     nxt_listen_event_t       *listen;
185853Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
185953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
186053Sigor@sysoev.ru 
1861153Sigor@sysoev.ru     job = obj;
186253Sigor@sysoev.ru     joint = data;
186353Sigor@sysoev.ru 
186453Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
186553Sigor@sysoev.ru 
1866159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
1867159Sigor@sysoev.ru 
186853Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
186953Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
187053Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
187153Sigor@sysoev.ru         return;
187253Sigor@sysoev.ru     }
187353Sigor@sysoev.ru 
187453Sigor@sysoev.ru     listen->socket.data = joint;
1875139Sigor@sysoev.ru 
1876153Sigor@sysoev.ru     job->work.next = NULL;
1877153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1878153Sigor@sysoev.ru 
1879153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
188053Sigor@sysoev.ru }
188153Sigor@sysoev.ru 
188253Sigor@sysoev.ru 
188353Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
188453Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
188553Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
188653Sigor@sysoev.ru {
1887115Sigor@sysoev.ru     nxt_socket_t        fd;
1888115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
188953Sigor@sysoev.ru     nxt_listen_event_t  *listen;
189053Sigor@sysoev.ru 
1891115Sigor@sysoev.ru     fd = skcf->socket->fd;
189253Sigor@sysoev.ru 
1893115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
1894115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
1895115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
189653Sigor@sysoev.ru     {
1897115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
189853Sigor@sysoev.ru 
1899115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
190053Sigor@sysoev.ru             return listen;
190153Sigor@sysoev.ru         }
190253Sigor@sysoev.ru     }
190353Sigor@sysoev.ru 
190453Sigor@sysoev.ru     return NULL;
190553Sigor@sysoev.ru }
190653Sigor@sysoev.ru 
190753Sigor@sysoev.ru 
190853Sigor@sysoev.ru static void
190953Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
191053Sigor@sysoev.ru {
1911153Sigor@sysoev.ru     nxt_joint_job_t          *job;
191253Sigor@sysoev.ru     nxt_event_engine_t       *engine;
191353Sigor@sysoev.ru     nxt_listen_event_t       *listen;
191453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
191553Sigor@sysoev.ru 
1916153Sigor@sysoev.ru     job = obj;
191753Sigor@sysoev.ru     joint = data;
191853Sigor@sysoev.ru 
1919139Sigor@sysoev.ru     engine = task->thread->engine;
1920139Sigor@sysoev.ru 
1921159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
1922159Sigor@sysoev.ru 
192353Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
192453Sigor@sysoev.ru                                      joint->socket_conf);
192553Sigor@sysoev.ru 
192653Sigor@sysoev.ru     old = listen->socket.data;
192753Sigor@sysoev.ru     listen->socket.data = joint;
1928177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
192953Sigor@sysoev.ru 
1930153Sigor@sysoev.ru     job->work.next = NULL;
1931153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1932153Sigor@sysoev.ru 
1933153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
1934139Sigor@sysoev.ru 
1935181Smax.romanov@nginx.com     /*
1936181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
1937181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
1938181Smax.romanov@nginx.com      */
1939181Smax.romanov@nginx.com 
1940181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
194153Sigor@sysoev.ru }
194253Sigor@sysoev.ru 
194353Sigor@sysoev.ru 
194453Sigor@sysoev.ru static void
194553Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
194653Sigor@sysoev.ru {
1947153Sigor@sysoev.ru     nxt_joint_job_t     *job;
1948153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
1949153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
1950153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1951153Sigor@sysoev.ru 
1952153Sigor@sysoev.ru     job = obj;
195353Sigor@sysoev.ru     skcf = data;
195453Sigor@sysoev.ru 
1955139Sigor@sysoev.ru     engine = task->thread->engine;
1956139Sigor@sysoev.ru 
195753Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
195853Sigor@sysoev.ru 
195953Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
196053Sigor@sysoev.ru 
1961163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
1962163Smax.romanov@nginx.com               listen->socket.fd);
1963163Smax.romanov@nginx.com 
196453Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
196553Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
196653Sigor@sysoev.ru 
196753Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
1968139Sigor@sysoev.ru 
1969153Sigor@sysoev.ru     job->work.next = NULL;
1970153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
1971153Sigor@sysoev.ru 
1972153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
197353Sigor@sysoev.ru }
197453Sigor@sysoev.ru 
197553Sigor@sysoev.ru 
197653Sigor@sysoev.ru static void
1977313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
1978313Sigor@sysoev.ru {
1979313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1980313Sigor@sysoev.ru 
1981313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
1982313Sigor@sysoev.ru 
1983313Sigor@sysoev.ru     engine = task->thread->engine;
1984313Sigor@sysoev.ru 
1985313Sigor@sysoev.ru     engine->shutdown = 1;
1986313Sigor@sysoev.ru 
1987313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
1988313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
1989313Sigor@sysoev.ru     }
1990313Sigor@sysoev.ru }
1991313Sigor@sysoev.ru 
1992313Sigor@sysoev.ru 
1993313Sigor@sysoev.ru static void
199453Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
199553Sigor@sysoev.ru {
199653Sigor@sysoev.ru     nxt_timer_t              *timer;
199753Sigor@sysoev.ru     nxt_listen_event_t       *listen;
199853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
199953Sigor@sysoev.ru 
200053Sigor@sysoev.ru     timer = obj;
200153Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
200253Sigor@sysoev.ru     joint = listen->socket.data;
200353Sigor@sysoev.ru 
2004163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2005163Smax.romanov@nginx.com               listen->socket.fd);
2006163Smax.romanov@nginx.com 
200753Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
2008123Smax.romanov@nginx.com 
2009123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
2010123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2011123Smax.romanov@nginx.com 
201253Sigor@sysoev.ru     nxt_free(listen);
201353Sigor@sysoev.ru 
201453Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
201553Sigor@sysoev.ru }
201653Sigor@sysoev.ru 
201753Sigor@sysoev.ru 
201853Sigor@sysoev.ru static void
201953Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
202053Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
202153Sigor@sysoev.ru {
2022118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
2023115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
202453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
202553Sigor@sysoev.ru 
2026118Sigor@sysoev.ru     skcf = joint->socket_conf;
2027118Sigor@sysoev.ru     rtsk = skcf->socket;
2028118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
202953Sigor@sysoev.ru 
203053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
203153Sigor@sysoev.ru 
2032163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
2033163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
2034163Smax.romanov@nginx.com 
2035115Sigor@sysoev.ru     if (--rtsk->count != 0) {
2036115Sigor@sysoev.ru         rtsk = NULL;
203753Sigor@sysoev.ru     }
203853Sigor@sysoev.ru 
203953Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
204053Sigor@sysoev.ru 
2041115Sigor@sysoev.ru     if (rtsk != NULL) {
2042115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
2043115Sigor@sysoev.ru         nxt_free(rtsk);
2044118Sigor@sysoev.ru         skcf->socket = NULL;
204553Sigor@sysoev.ru     }
204653Sigor@sysoev.ru 
204753Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
204853Sigor@sysoev.ru }
204953Sigor@sysoev.ru 
205053Sigor@sysoev.ru 
205153Sigor@sysoev.ru static void
205253Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
205353Sigor@sysoev.ru {
2054156Sigor@sysoev.ru     nxt_bool_t             exit;
205553Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
205653Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
2057313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
205853Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
205953Sigor@sysoev.ru 
2060163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
206153Sigor@sysoev.ru 
206253Sigor@sysoev.ru     if (--joint->count != 0) {
206353Sigor@sysoev.ru         return;
206453Sigor@sysoev.ru     }
206553Sigor@sysoev.ru 
206653Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
206753Sigor@sysoev.ru 
206853Sigor@sysoev.ru     skcf = joint->socket_conf;
206953Sigor@sysoev.ru     rtcf = skcf->router_conf;
207053Sigor@sysoev.ru     lock = &rtcf->router->lock;
207153Sigor@sysoev.ru 
207253Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
207353Sigor@sysoev.ru 
2074163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2075163Smax.romanov@nginx.com               rtcf, rtcf->count);
2076163Smax.romanov@nginx.com 
207753Sigor@sysoev.ru     if (--skcf->count != 0) {
207853Sigor@sysoev.ru         rtcf = NULL;
207953Sigor@sysoev.ru 
208053Sigor@sysoev.ru     } else {
208153Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
208253Sigor@sysoev.ru 
208353Sigor@sysoev.ru         if (--rtcf->count != 0) {
208453Sigor@sysoev.ru             rtcf = NULL;
208553Sigor@sysoev.ru         }
208653Sigor@sysoev.ru     }
208753Sigor@sysoev.ru 
208853Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
208953Sigor@sysoev.ru 
2090141Smax.romanov@nginx.com     /* TODO remove engine->port */
2091141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2092141Smax.romanov@nginx.com 
2093156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
2094313Sigor@sysoev.ru     engine = joint->engine;
2095313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
2096156Sigor@sysoev.ru 
209753Sigor@sysoev.ru     if (rtcf != NULL) {
2098115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2099131Smax.romanov@nginx.com 
2100131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2101131Smax.romanov@nginx.com 
210265Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
210353Sigor@sysoev.ru     }
210453Sigor@sysoev.ru 
2105156Sigor@sysoev.ru     if (exit) {
210653Sigor@sysoev.ru         nxt_thread_exit(task->thread);
210753Sigor@sysoev.ru     }
210853Sigor@sysoev.ru }
210953Sigor@sysoev.ru 
211053Sigor@sysoev.ru 
211153Sigor@sysoev.ru static void
211253Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
211353Sigor@sysoev.ru {
2114141Smax.romanov@nginx.com     nxt_port_t           *port;
211553Sigor@sysoev.ru     nxt_thread_link_t    *link;
211653Sigor@sysoev.ru     nxt_event_engine_t   *engine;
211753Sigor@sysoev.ru     nxt_thread_handle_t  handle;
211853Sigor@sysoev.ru 
211958Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
212053Sigor@sysoev.ru     link = data;
212153Sigor@sysoev.ru 
212253Sigor@sysoev.ru     nxt_thread_wait(handle);
212353Sigor@sysoev.ru 
212453Sigor@sysoev.ru     engine = link->engine;
212553Sigor@sysoev.ru 
212653Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
212753Sigor@sysoev.ru 
2128141Smax.romanov@nginx.com     port = engine->port;
2129141Smax.romanov@nginx.com 
2130141Smax.romanov@nginx.com     // TODO notify all apps
2131141Smax.romanov@nginx.com 
2132163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
2133163Smax.romanov@nginx.com     nxt_port_release(port);
2134163Smax.romanov@nginx.com 
2135163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
213663Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
213753Sigor@sysoev.ru 
213853Sigor@sysoev.ru     nxt_event_engine_free(engine);
213953Sigor@sysoev.ru 
214053Sigor@sysoev.ru     nxt_free(link);
214153Sigor@sysoev.ru }
214253Sigor@sysoev.ru 
214353Sigor@sysoev.ru 
2144206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
214553Sigor@sysoev.ru     nxt_aligned(64) =
214653Sigor@sysoev.ru {
214753Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
214853Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
214953Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
215053Sigor@sysoev.ru 
215153Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
215253Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
215353Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
215453Sigor@sysoev.ru };
215553Sigor@sysoev.ru 
215653Sigor@sysoev.ru 
2157206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
2158206Smax.romanov@nginx.com     nxt_aligned(64) =
2159206Smax.romanov@nginx.com {
2160206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
2161206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
2162206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
2163206Smax.romanov@nginx.com 
2164206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
2165206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
2166206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
2167206Smax.romanov@nginx.com     .timer_autoreset = 1,
2168206Smax.romanov@nginx.com };
2169206Smax.romanov@nginx.com 
2170206Smax.romanov@nginx.com 
217153Sigor@sysoev.ru static void
217253Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
217353Sigor@sysoev.ru {
217453Sigor@sysoev.ru     size_t                   size;
217562Sigor@sysoev.ru     nxt_conn_t               *c;
217653Sigor@sysoev.ru     nxt_event_engine_t       *engine;
217753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
217853Sigor@sysoev.ru 
217953Sigor@sysoev.ru     c = obj;
218053Sigor@sysoev.ru     joint = data;
218153Sigor@sysoev.ru 
218253Sigor@sysoev.ru     nxt_debug(task, "router conn init");
218353Sigor@sysoev.ru 
218453Sigor@sysoev.ru     joint->count++;
218553Sigor@sysoev.ru 
218653Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
218753Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
218853Sigor@sysoev.ru 
218953Sigor@sysoev.ru     c->socket.data = NULL;
219053Sigor@sysoev.ru 
219153Sigor@sysoev.ru     engine = task->thread->engine;
219253Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
219353Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
219453Sigor@sysoev.ru 
2195206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
219653Sigor@sysoev.ru 
219762Sigor@sysoev.ru     nxt_conn_read(engine, c);
219853Sigor@sysoev.ru }
219953Sigor@sysoev.ru 
220053Sigor@sysoev.ru 
220162Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
220253Sigor@sysoev.ru     nxt_aligned(64) =
220353Sigor@sysoev.ru {
220488Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
220553Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
220653Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
220753Sigor@sysoev.ru };
220853Sigor@sysoev.ru 
220953Sigor@sysoev.ru 
221053Sigor@sysoev.ru static void
2211*318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2212*318Smax.romanov@nginx.com     void *data)
221388Smax.romanov@nginx.com {
221488Smax.romanov@nginx.com     size_t               dump_size;
2215194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
221688Smax.romanov@nginx.com     nxt_conn_t           *c;
221788Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
221888Smax.romanov@nginx.com 
221988Smax.romanov@nginx.com     b = msg->buf;
2220*318Smax.romanov@nginx.com     rc = data;
222188Smax.romanov@nginx.com 
222288Smax.romanov@nginx.com     c = rc->conn;
222388Smax.romanov@nginx.com 
222488Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
222588Smax.romanov@nginx.com 
222688Smax.romanov@nginx.com     if (dump_size > 300) {
222788Smax.romanov@nginx.com         dump_size = 300;
222888Smax.romanov@nginx.com     }
222988Smax.romanov@nginx.com 
2230119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
223188Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
223288Smax.romanov@nginx.com               b->mem.pos);
223388Smax.romanov@nginx.com 
223488Smax.romanov@nginx.com     if (msg->size == 0) {
223588Smax.romanov@nginx.com         b = NULL;
223688Smax.romanov@nginx.com     }
223788Smax.romanov@nginx.com 
223888Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
223988Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
224088Smax.romanov@nginx.com 
224188Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
224288Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
224388Smax.romanov@nginx.com             /* TODO pogorevaTb */
224488Smax.romanov@nginx.com         }
224588Smax.romanov@nginx.com 
224688Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2247167Smax.romanov@nginx.com 
2248167Smax.romanov@nginx.com         if (rc->app_port != NULL) {
2249167Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
2250167Smax.romanov@nginx.com 
2251167Smax.romanov@nginx.com             rc->app_port = NULL;
2252167Smax.romanov@nginx.com         }
2253206Smax.romanov@nginx.com 
2254*318Smax.romanov@nginx.com         nxt_router_rc_unlink(rc);
225588Smax.romanov@nginx.com     }
225688Smax.romanov@nginx.com 
225788Smax.romanov@nginx.com     if (b == NULL) {
225888Smax.romanov@nginx.com         return;
225988Smax.romanov@nginx.com     }
226088Smax.romanov@nginx.com 
2261206Smax.romanov@nginx.com     if (msg->buf == b) {
2262206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2263206Smax.romanov@nginx.com         msg->buf = NULL;
2264206Smax.romanov@nginx.com     }
2265194Smax.romanov@nginx.com 
226688Smax.romanov@nginx.com     if (c->write == NULL) {
226788Smax.romanov@nginx.com         c->write = b;
226888Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
226988Smax.romanov@nginx.com 
227088Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2271277Sigor@sysoev.ru 
227288Smax.romanov@nginx.com     } else {
227388Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
227488Smax.romanov@nginx.com 
227588Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
227688Smax.romanov@nginx.com     }
227788Smax.romanov@nginx.com }
227888Smax.romanov@nginx.com 
2279277Sigor@sysoev.ru 
2280*318Smax.romanov@nginx.com static void
2281*318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2282*318Smax.romanov@nginx.com     void *data)
2283*318Smax.romanov@nginx.com {
2284*318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2285*318Smax.romanov@nginx.com 
2286*318Smax.romanov@nginx.com     rc = data;
2287*318Smax.romanov@nginx.com 
2288*318Smax.romanov@nginx.com     nxt_router_gen_error(task, rc->conn, 500,
2289*318Smax.romanov@nginx.com                          "Application terminated unexpectedly");
2290*318Smax.romanov@nginx.com 
2291*318Smax.romanov@nginx.com     nxt_router_rc_unlink(rc);
2292*318Smax.romanov@nginx.com }
2293*318Smax.romanov@nginx.com 
2294*318Smax.romanov@nginx.com 
2295141Smax.romanov@nginx.com nxt_inline const char *
2296141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2297141Smax.romanov@nginx.com {
2298141Smax.romanov@nginx.com     switch (code) {
2299141Smax.romanov@nginx.com     case 400: return "Bad request";
2300141Smax.romanov@nginx.com     case 404: return "Not found";
2301141Smax.romanov@nginx.com     case 403: return "Forbidden";
2302206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2303206Smax.romanov@nginx.com     case 411: return "Length Required";
2304206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2305141Smax.romanov@nginx.com     case 500:
2306141Smax.romanov@nginx.com     default:  return "Internal server error";
2307141Smax.romanov@nginx.com     }
2308141Smax.romanov@nginx.com }
2309141Smax.romanov@nginx.com 
2310163Smax.romanov@nginx.com 
2311163Smax.romanov@nginx.com static nxt_buf_t *
2312163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2313163Smax.romanov@nginx.com     const char* fmt, va_list args)
231488Smax.romanov@nginx.com {
2315163Smax.romanov@nginx.com     nxt_buf_t   *b, *last;
2316163Smax.romanov@nginx.com     const char  *msg;
2317163Smax.romanov@nginx.com 
2318163Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, mp, 16384);
2319141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2320163Smax.romanov@nginx.com         return NULL;
2321141Smax.romanov@nginx.com     }
2322141Smax.romanov@nginx.com 
2323141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2324141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2325141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2326141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2327141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2328141Smax.romanov@nginx.com 
2329141Smax.romanov@nginx.com     msg = (const char *) b->mem.free;
2330141Smax.romanov@nginx.com 
2331141Smax.romanov@nginx.com     b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args);
2332206Smax.romanov@nginx.com     b->mem.free[0] = '\0';
2333141Smax.romanov@nginx.com 
2334141Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, msg);
2335141Smax.romanov@nginx.com 
2336163Smax.romanov@nginx.com     last = nxt_buf_mem_ts_alloc(task, mp, 0);
2337163Smax.romanov@nginx.com 
2338141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2339163Smax.romanov@nginx.com         nxt_mp_release(mp, b);
2340163Smax.romanov@nginx.com         return NULL;
2341141Smax.romanov@nginx.com     }
2342141Smax.romanov@nginx.com 
2343163Smax.romanov@nginx.com     nxt_buf_set_sync(last);
2344163Smax.romanov@nginx.com     nxt_buf_set_last(last);
2345163Smax.romanov@nginx.com 
2346141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2347141Smax.romanov@nginx.com 
2348163Smax.romanov@nginx.com     return b;
2349163Smax.romanov@nginx.com }
2350163Smax.romanov@nginx.com 
2351163Smax.romanov@nginx.com 
2352163Smax.romanov@nginx.com 
2353163Smax.romanov@nginx.com static void
2354163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2355163Smax.romanov@nginx.com     const char* fmt, ...)
2356163Smax.romanov@nginx.com {
2357163Smax.romanov@nginx.com     va_list    args;
2358*318Smax.romanov@nginx.com     nxt_mp_t   *mp;
2359163Smax.romanov@nginx.com     nxt_buf_t  *b;
2360163Smax.romanov@nginx.com 
2361*318Smax.romanov@nginx.com     /* TODO: fix when called from main thread */
2362*318Smax.romanov@nginx.com     /* TODO: fix when called in the middle of response */
2363*318Smax.romanov@nginx.com 
2364*318Smax.romanov@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
2365*318Smax.romanov@nginx.com 
2366163Smax.romanov@nginx.com     va_start(args, fmt);
2367*318Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, mp, code, fmt, args);
2368163Smax.romanov@nginx.com     va_end(args);
2369163Smax.romanov@nginx.com 
2370273Smax.romanov@nginx.com     if (c->socket.fd == -1) {
2371*318Smax.romanov@nginx.com         nxt_mp_release(mp, b->next);
2372*318Smax.romanov@nginx.com         nxt_mp_release(mp, b);
2373273Smax.romanov@nginx.com         return;
2374273Smax.romanov@nginx.com     }
2375273Smax.romanov@nginx.com 
2376141Smax.romanov@nginx.com     if (c->write == NULL) {
2377141Smax.romanov@nginx.com         c->write = b;
2378141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2379141Smax.romanov@nginx.com 
2380141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2381277Sigor@sysoev.ru 
2382141Smax.romanov@nginx.com     } else {
2383141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2384141Smax.romanov@nginx.com 
2385141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2386141Smax.romanov@nginx.com     }
2387141Smax.romanov@nginx.com }
2388141Smax.romanov@nginx.com 
2389141Smax.romanov@nginx.com 
2390141Smax.romanov@nginx.com static void
2391192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2392192Smax.romanov@nginx.com {
2393192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2394192Smax.romanov@nginx.com 
2395192Smax.romanov@nginx.com     sw = data;
2396192Smax.romanov@nginx.com 
2397192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2398192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2399192Smax.romanov@nginx.com 
2400192Smax.romanov@nginx.com     msg->new_port->app = sw->app;
2401192Smax.romanov@nginx.com 
2402192Smax.romanov@nginx.com     sw->app->pending_workers--;
2403192Smax.romanov@nginx.com     sw->app->workers++;
2404192Smax.romanov@nginx.com 
2405192Smax.romanov@nginx.com     nxt_debug(task, "sw %p got port %p", sw, msg->new_port);
2406192Smax.romanov@nginx.com 
2407192Smax.romanov@nginx.com     nxt_router_app_release_port(task, msg->new_port, sw->app);
2408192Smax.romanov@nginx.com 
2409192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2410192Smax.romanov@nginx.com }
2411192Smax.romanov@nginx.com 
2412192Smax.romanov@nginx.com 
2413192Smax.romanov@nginx.com static void
2414192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
2415192Smax.romanov@nginx.com {
2416*318Smax.romanov@nginx.com     nxt_app_t           *app;
2417*318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2418*318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2419192Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2420192Smax.romanov@nginx.com 
2421192Smax.romanov@nginx.com     sw = data;
2422192Smax.romanov@nginx.com 
2423192Smax.romanov@nginx.com     nxt_assert(sw != NULL);
2424*318Smax.romanov@nginx.com     nxt_assert(sw->app != NULL);
2425192Smax.romanov@nginx.com     nxt_assert(sw->app->pending_workers != 0);
2426192Smax.romanov@nginx.com 
2427*318Smax.romanov@nginx.com     app = sw->app;
2428*318Smax.romanov@nginx.com 
2429192Smax.romanov@nginx.com     sw->app->pending_workers--;
2430192Smax.romanov@nginx.com 
2431277Sigor@sysoev.ru     nxt_debug(task, "sw %p error, failed to start app '%V'",
2432*318Smax.romanov@nginx.com               sw, &app->name);
2433*318Smax.romanov@nginx.com 
2434*318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2435*318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
2436*318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2437*318Smax.romanov@nginx.com 
2438*318Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2439*318Smax.romanov@nginx.com 
2440*318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
2441*318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2442*318Smax.romanov@nginx.com 
2443*318Smax.romanov@nginx.com         nxt_router_ra_abort(task, ra, ra->work.data);
2444*318Smax.romanov@nginx.com     }
2445192Smax.romanov@nginx.com 
2446192Smax.romanov@nginx.com     nxt_router_sw_release(task, sw);
2447192Smax.romanov@nginx.com }
2448192Smax.romanov@nginx.com 
2449192Smax.romanov@nginx.com 
2450192Smax.romanov@nginx.com static void
2451141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data)
2452141Smax.romanov@nginx.com {
2453174Sigor@sysoev.ru     size_t              size;
2454192Smax.romanov@nginx.com     uint32_t            stream;
2455141Smax.romanov@nginx.com     nxt_buf_t           *b;
2456141Smax.romanov@nginx.com     nxt_app_t           *app;
2457274Smax.romanov@nginx.com     nxt_port_t          *main_port, *router_port, *app_port;
2458141Smax.romanov@nginx.com     nxt_runtime_t       *rt;
2459141Smax.romanov@nginx.com     nxt_start_worker_t  *sw;
2460274Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2461141Smax.romanov@nginx.com 
2462141Smax.romanov@nginx.com     sw = obj;
2463141Smax.romanov@nginx.com     app = sw->app;
2464141Smax.romanov@nginx.com 
2465274Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->requests)) {
2466274Smax.romanov@nginx.com         ra = sw->ra;
2467*318Smax.romanov@nginx.com         app_port = nxt_router_app_get_port(app, ra->stream);
2468274Smax.romanov@nginx.com 
2469274Smax.romanov@nginx.com         if (app_port != NULL) {
2470*318Smax.romanov@nginx.com             nxt_debug(task, "app '%V' %p process stream #%uD",
2471*318Smax.romanov@nginx.com                       &app->name, app, ra->stream);
2472274Smax.romanov@nginx.com 
2473274Smax.romanov@nginx.com             ra->app_port = app_port;
2474274Smax.romanov@nginx.com 
2475274Smax.romanov@nginx.com             nxt_router_process_http_request_mp(task, ra, app_port);
2476274Smax.romanov@nginx.com 
2477274Smax.romanov@nginx.com             nxt_router_ra_release(task, ra, ra->work.data);
2478274Smax.romanov@nginx.com             nxt_router_sw_release(task, sw);
2479274Smax.romanov@nginx.com 
2480274Smax.romanov@nginx.com             return;
2481274Smax.romanov@nginx.com         }
2482274Smax.romanov@nginx.com     }
2483274Smax.romanov@nginx.com 
2484167Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->requests, &sw->ra->link);
2485167Smax.romanov@nginx.com 
2486163Smax.romanov@nginx.com     if (app->workers + app->pending_workers >= app->max_workers) {
2487244Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p %uD/%uD running/pending workers, "
2488244Smax.romanov@nginx.com                   "max_workers (%uD) reached", &app->name, app,
2489244Smax.romanov@nginx.com                    app->workers, app->pending_workers, app->max_workers);
2490192Smax.romanov@nginx.com 
2491192Smax.romanov@nginx.com         nxt_router_sw_release(task, sw);
2492163Smax.romanov@nginx.com 
2493163Smax.romanov@nginx.com         return;
2494163Smax.romanov@nginx.com     }
2495163Smax.romanov@nginx.com 
2496163Smax.romanov@nginx.com     app->pending_workers++;
2497163Smax.romanov@nginx.com 
2498192Smax.romanov@nginx.com     nxt_debug(task, "sw %p send", sw);
249988Smax.romanov@nginx.com 
2500119Smax.romanov@nginx.com     rt = task->thread->runtime;
2501240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2502192Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2503141Smax.romanov@nginx.com 
2504174Sigor@sysoev.ru     size = app->name.length + 1 + app->conf.length;
2505174Sigor@sysoev.ru 
2506240Sigor@sysoev.ru     b = nxt_buf_mem_alloc(main_port->mem_pool, size, 0);
2507174Sigor@sysoev.ru 
2508174Sigor@sysoev.ru     nxt_buf_cpystr(b, &app->name);
2509174Sigor@sysoev.ru     *b->mem.free++ = '\0';
2510141Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2511141Smax.romanov@nginx.com 
2512192Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2513192Smax.romanov@nginx.com                                            nxt_router_sw_ready,
2514192Smax.romanov@nginx.com                                            nxt_router_sw_error,
2515240Sigor@sysoev.ru                                            main_port->pid, sw);
2516240Sigor@sysoev.ru 
2517240Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2518192Smax.romanov@nginx.com                           stream, router_port->id, b);
2519141Smax.romanov@nginx.com }
2520141Smax.romanov@nginx.com 
2521141Smax.romanov@nginx.com 
2522163Smax.romanov@nginx.com static nxt_bool_t
2523167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app)
2524163Smax.romanov@nginx.com {
2525192Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2526192Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2527167Smax.romanov@nginx.com 
2528167Smax.romanov@nginx.com     nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app,
2529167Smax.romanov@nginx.com                          app->live, app->workers, app->pending_workers,
2530167Smax.romanov@nginx.com                          nxt_queue_is_empty(&app->requests));
2531167Smax.romanov@nginx.com 
2532277Sigor@sysoev.ru     if (app->live == 0
2533277Sigor@sysoev.ru         && app->workers == 0
2534277Sigor@sysoev.ru         && app->pending_workers == 0
2535277Sigor@sysoev.ru         && nxt_queue_is_empty(&app->requests))
2536277Sigor@sysoev.ru     {
2537163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2538163Smax.romanov@nginx.com         nxt_free(app);
2539163Smax.romanov@nginx.com 
2540163Smax.romanov@nginx.com         return 1;
2541163Smax.romanov@nginx.com     }
2542163Smax.romanov@nginx.com 
2543277Sigor@sysoev.ru     if (app->live == 1
2544277Sigor@sysoev.ru         && nxt_queue_is_empty(&app->requests) == 0
2545277Sigor@sysoev.ru         && app->workers + app->pending_workers < app->max_workers)
2546277Sigor@sysoev.ru     {
2547167Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2548167Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2549167Smax.romanov@nginx.com 
2550167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2551167Smax.romanov@nginx.com 
2552192Smax.romanov@nginx.com         nxt_router_sw_create(task, app, ra);
2553167Smax.romanov@nginx.com     }
2554167Smax.romanov@nginx.com 
2555163Smax.romanov@nginx.com     return 0;
2556163Smax.romanov@nginx.com }
2557163Smax.romanov@nginx.com 
2558163Smax.romanov@nginx.com 
2559141Smax.romanov@nginx.com static nxt_port_t *
2560*318Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t stream)
2561141Smax.romanov@nginx.com {
2562141Smax.romanov@nginx.com     nxt_port_t        *port;
2563141Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2564141Smax.romanov@nginx.com 
2565141Smax.romanov@nginx.com     port = NULL;
2566141Smax.romanov@nginx.com 
2567141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2568141Smax.romanov@nginx.com 
2569141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2570141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->ports);
2571141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2572141Smax.romanov@nginx.com 
2573141Smax.romanov@nginx.com         lnk->next = NULL;
2574141Smax.romanov@nginx.com 
2575141Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2576167Smax.romanov@nginx.com 
2577*318Smax.romanov@nginx.com         port->app_stream = stream;
2578141Smax.romanov@nginx.com     }
2579141Smax.romanov@nginx.com 
2580141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2581141Smax.romanov@nginx.com 
2582141Smax.romanov@nginx.com     return port;
2583141Smax.romanov@nginx.com }
2584141Smax.romanov@nginx.com 
2585141Smax.romanov@nginx.com 
2586141Smax.romanov@nginx.com static void
2587141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data)
2588141Smax.romanov@nginx.com {
2589141Smax.romanov@nginx.com     nxt_app_t            *app;
2590141Smax.romanov@nginx.com     nxt_port_t           *port;
2591141Smax.romanov@nginx.com     nxt_work_t           *work;
2592141Smax.romanov@nginx.com     nxt_queue_link_t     *lnk;
2593167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
2594141Smax.romanov@nginx.com 
2595141Smax.romanov@nginx.com     port = obj;
2596141Smax.romanov@nginx.com     app = data;
2597141Smax.romanov@nginx.com 
2598141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2599141Smax.romanov@nginx.com     nxt_assert(app == port->app);
2600141Smax.romanov@nginx.com     nxt_assert(port->app_link.next == NULL);
2601141Smax.romanov@nginx.com 
2602141Smax.romanov@nginx.com 
2603141Smax.romanov@nginx.com     if (task->thread->engine != port->engine) {
2604163Smax.romanov@nginx.com         work = &port->work;
2605141Smax.romanov@nginx.com 
2606141Smax.romanov@nginx.com         nxt_debug(task, "post release port to engine %p", port->engine);
2607141Smax.romanov@nginx.com 
2608141Smax.romanov@nginx.com         work->next = NULL;
2609141Smax.romanov@nginx.com         work->handler = nxt_router_app_release_port;
2610166Smax.romanov@nginx.com         work->task = &port->engine->task;
2611141Smax.romanov@nginx.com         work->obj = port;
2612141Smax.romanov@nginx.com         work->data = app;
2613141Smax.romanov@nginx.com 
2614141Smax.romanov@nginx.com         nxt_event_engine_post(port->engine, work);
2615141Smax.romanov@nginx.com 
2616141Smax.romanov@nginx.com         return;
2617141Smax.romanov@nginx.com     }
2618141Smax.romanov@nginx.com 
2619141Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2620141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2621141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2622141Smax.romanov@nginx.com 
2623167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2624167Smax.romanov@nginx.com 
2625*318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p process next stream #%uD",
2626*318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2627167Smax.romanov@nginx.com 
2628167Smax.romanov@nginx.com         ra->app_port = port;
2629*318Smax.romanov@nginx.com         port->app_stream = ra->stream;
2630167Smax.romanov@nginx.com 
2631167Smax.romanov@nginx.com         nxt_router_process_http_request_mp(task, ra, port);
2632167Smax.romanov@nginx.com 
2633167Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
2634141Smax.romanov@nginx.com 
2635141Smax.romanov@nginx.com         return;
2636141Smax.romanov@nginx.com     }
2637141Smax.romanov@nginx.com 
2638*318Smax.romanov@nginx.com     port->app_stream = 0;
2639167Smax.romanov@nginx.com 
2640163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2641167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)",
2642167Smax.romanov@nginx.com                   &app->name, app, port->pid);
2643163Smax.romanov@nginx.com 
2644163Smax.romanov@nginx.com         app->workers--;
2645167Smax.romanov@nginx.com         nxt_router_app_free(task, app);
2646163Smax.romanov@nginx.com 
2647163Smax.romanov@nginx.com         port->app = NULL;
2648163Smax.romanov@nginx.com 
2649163Smax.romanov@nginx.com         nxt_port_release(port);
2650163Smax.romanov@nginx.com 
2651163Smax.romanov@nginx.com         return;
2652163Smax.romanov@nginx.com     }
2653163Smax.romanov@nginx.com 
2654163Smax.romanov@nginx.com     if (!app->live) {
2655167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2656167Smax.romanov@nginx.com                   &app->name, app);
2657163Smax.romanov@nginx.com 
2658163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2659163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2660163Smax.romanov@nginx.com 
2661163Smax.romanov@nginx.com         return;
2662163Smax.romanov@nginx.com     }
2663163Smax.romanov@nginx.com 
2664167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2665167Smax.romanov@nginx.com               &app->name, app);
2666141Smax.romanov@nginx.com 
2667141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2668141Smax.romanov@nginx.com 
2669141Smax.romanov@nginx.com     nxt_queue_insert_head(&app->ports, &port->app_link);
2670141Smax.romanov@nginx.com 
2671141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2672141Smax.romanov@nginx.com }
2673141Smax.romanov@nginx.com 
2674141Smax.romanov@nginx.com 
2675163Smax.romanov@nginx.com nxt_bool_t
2676141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port)
2677141Smax.romanov@nginx.com {
2678163Smax.romanov@nginx.com     nxt_app_t   *app;
2679163Smax.romanov@nginx.com     nxt_bool_t  busy;
2680141Smax.romanov@nginx.com 
2681141Smax.romanov@nginx.com     app = port->app;
2682*318Smax.romanov@nginx.com     busy = port->app_stream != 0;
2683163Smax.romanov@nginx.com 
2684163Smax.romanov@nginx.com     if (app == NULL) {
2685167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, no app", port);
2686167Smax.romanov@nginx.com 
2687163Smax.romanov@nginx.com         nxt_assert(port->app_link.next == NULL);
2688163Smax.romanov@nginx.com 
2689163Smax.romanov@nginx.com         return 1;
2690141Smax.romanov@nginx.com     }
2691141Smax.romanov@nginx.com 
2692141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2693141Smax.romanov@nginx.com 
2694163Smax.romanov@nginx.com     if (port->app_link.next != NULL) {
2695163Smax.romanov@nginx.com 
2696163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2697163Smax.romanov@nginx.com         port->app_link.next = NULL;
2698163Smax.romanov@nginx.com 
2699163Smax.romanov@nginx.com     }
2700141Smax.romanov@nginx.com 
2701141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2702163Smax.romanov@nginx.com 
2703163Smax.romanov@nginx.com     if (busy == 0) {
2704167Smax.romanov@nginx.com         nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port,
2705167Smax.romanov@nginx.com                              &app->name, app);
2706163Smax.romanov@nginx.com 
2707163Smax.romanov@nginx.com         app->workers--;
2708167Smax.romanov@nginx.com         nxt_router_app_free(&port->engine->task, app);
2709163Smax.romanov@nginx.com 
2710163Smax.romanov@nginx.com         return 1;
2711163Smax.romanov@nginx.com     }
2712163Smax.romanov@nginx.com 
2713*318Smax.romanov@nginx.com     nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, "
2714*318Smax.romanov@nginx.com                          "app stream #%uD", port, &app->name, app,
2715*318Smax.romanov@nginx.com                          port->app_stream);
2716167Smax.romanov@nginx.com 
2717163Smax.romanov@nginx.com     return 0;
2718141Smax.romanov@nginx.com }
2719141Smax.romanov@nginx.com 
2720141Smax.romanov@nginx.com 
2721167Smax.romanov@nginx.com static nxt_int_t
2722167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2723141Smax.romanov@nginx.com {
2724141Smax.romanov@nginx.com     nxt_app_t                *app;
2725141Smax.romanov@nginx.com     nxt_conn_t               *c;
2726167Smax.romanov@nginx.com     nxt_port_t               *port;
2727*318Smax.romanov@nginx.com     nxt_event_engine_t       *engine;
2728141Smax.romanov@nginx.com     nxt_start_worker_t       *sw;
2729141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2730141Smax.romanov@nginx.com 
2731141Smax.romanov@nginx.com     port = NULL;
2732167Smax.romanov@nginx.com     c = ra->rc->conn;
2733141Smax.romanov@nginx.com 
2734141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2735141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2736141Smax.romanov@nginx.com 
2737141Smax.romanov@nginx.com     if (app == NULL) {
2738167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2739141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2740141Smax.romanov@nginx.com         return NXT_ERROR;
2741141Smax.romanov@nginx.com     }
2742141Smax.romanov@nginx.com 
2743*318Smax.romanov@nginx.com     engine = task->thread->engine;
2744*318Smax.romanov@nginx.com 
2745*318Smax.romanov@nginx.com     nxt_timer_disable(engine, &c->read_timer);
2746*318Smax.romanov@nginx.com 
2747*318Smax.romanov@nginx.com     if (app->timeout != 0) {
2748*318Smax.romanov@nginx.com         c->read_timer.handler = nxt_router_app_timeout;
2749*318Smax.romanov@nginx.com         nxt_timer_add(engine, &c->read_timer, app->timeout);
2750*318Smax.romanov@nginx.com     }
2751*318Smax.romanov@nginx.com 
2752*318Smax.romanov@nginx.com     port = nxt_router_app_get_port(app, ra->stream);
2753141Smax.romanov@nginx.com 
2754141Smax.romanov@nginx.com     if (port != NULL) {
2755163Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V'", &app->name);
2756163Smax.romanov@nginx.com 
2757167Smax.romanov@nginx.com         ra->app_port = port;
2758141Smax.romanov@nginx.com         return NXT_OK;
2759141Smax.romanov@nginx.com     }
2760141Smax.romanov@nginx.com 
2761192Smax.romanov@nginx.com     sw = nxt_router_sw_create(task, app, ra);
2762141Smax.romanov@nginx.com 
2763141Smax.romanov@nginx.com     if (nxt_slow_path(sw == NULL)) {
2764167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2765141Smax.romanov@nginx.com                              "Failed to allocate start worker struct");
2766141Smax.romanov@nginx.com         return NXT_ERROR;
2767141Smax.romanov@nginx.com     }
2768141Smax.romanov@nginx.com 
2769141Smax.romanov@nginx.com     return NXT_AGAIN;
277088Smax.romanov@nginx.com }
277188Smax.romanov@nginx.com 
277288Smax.romanov@nginx.com 
277388Smax.romanov@nginx.com static void
277453Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
277553Sigor@sysoev.ru {
2776206Smax.romanov@nginx.com     size_t                    size;
277753Sigor@sysoev.ru     nxt_int_t                 ret;
2778206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
277962Sigor@sysoev.ru     nxt_conn_t                *c;
2780268Sigor@sysoev.ru     nxt_sockaddr_t            *local;
278188Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2782206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
278353Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
278488Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
278553Sigor@sysoev.ru 
278653Sigor@sysoev.ru     c = obj;
278788Smax.romanov@nginx.com     ap = data;
2788206Smax.romanov@nginx.com     buf = c->read;
2789206Smax.romanov@nginx.com     joint = c->listen->socket.data;
279053Sigor@sysoev.ru 
279153Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
279253Sigor@sysoev.ru 
279388Smax.romanov@nginx.com     if (ap == NULL) {
2794206Smax.romanov@nginx.com         ap = nxt_mp_zalloc(c->mem_pool, sizeof(nxt_app_parse_ctx_t));
279588Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
279653Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
279753Sigor@sysoev.ru             return;
279853Sigor@sysoev.ru         }
279953Sigor@sysoev.ru 
280088Smax.romanov@nginx.com         ret = nxt_app_http_req_init(task, ap);
280161Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
280261Sigor@sysoev.ru             nxt_router_conn_close(task, c, data);
280361Sigor@sysoev.ru             return;
280461Sigor@sysoev.ru         }
280588Smax.romanov@nginx.com 
280688Smax.romanov@nginx.com         c->socket.data = ap;
2807113Smax.romanov@nginx.com 
2808113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2809113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2810206Smax.romanov@nginx.com 
2811268Sigor@sysoev.ru         local = joint->socket_conf->sockaddr;
2812268Sigor@sysoev.ru         ap->r.local.start = nxt_sockaddr_address(local);
2813268Sigor@sysoev.ru         ap->r.local.length = local->address_length;
2814268Sigor@sysoev.ru 
2815206Smax.romanov@nginx.com         ap->r.header.buf = buf;
281653Sigor@sysoev.ru     }
281753Sigor@sysoev.ru 
281888Smax.romanov@nginx.com     h = &ap->r.header;
2819206Smax.romanov@nginx.com     b = &ap->r.body;
2820206Smax.romanov@nginx.com 
2821206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2822206Smax.romanov@nginx.com 
2823206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
282453Sigor@sysoev.ru 
282553Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
282653Sigor@sysoev.ru 
282753Sigor@sysoev.ru     case NXT_DONE:
282888Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
282988Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2830206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2831206Smax.romanov@nginx.com 
2832206Smax.romanov@nginx.com         if (b->done) {
2833206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2834206Smax.romanov@nginx.com 
2835206Smax.romanov@nginx.com             return;
2836206Smax.romanov@nginx.com         }
2837206Smax.romanov@nginx.com 
2838277Sigor@sysoev.ru         if (joint->socket_conf->max_body_size > 0
2839277Sigor@sysoev.ru             && (size_t) h->parsed_content_length
2840277Sigor@sysoev.ru                > joint->socket_conf->max_body_size)
2841277Sigor@sysoev.ru         {
2842206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2843206Smax.romanov@nginx.com             return;
2844206Smax.romanov@nginx.com         }
2845206Smax.romanov@nginx.com 
2846206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2847206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2848206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2849206Smax.romanov@nginx.com 
2850206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2851206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2852206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2853206Smax.romanov@nginx.com                                      "buffer for request body");
2854206Smax.romanov@nginx.com                 return;
2855206Smax.romanov@nginx.com             }
2856206Smax.romanov@nginx.com 
2857206Smax.romanov@nginx.com             c->read = buf->next;
2858206Smax.romanov@nginx.com 
2859206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2860206Smax.romanov@nginx.com         }
2861206Smax.romanov@nginx.com 
2862206Smax.romanov@nginx.com         if (b->buf == NULL) {
2863206Smax.romanov@nginx.com             b->buf = c->read;
2864206Smax.romanov@nginx.com         }
2865206Smax.romanov@nginx.com 
2866206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
2867206Smax.romanov@nginx.com         break;
2868206Smax.romanov@nginx.com 
2869206Smax.romanov@nginx.com     case NXT_ERROR:
2870206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
2871206Smax.romanov@nginx.com         return;
2872206Smax.romanov@nginx.com 
2873206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
2874206Smax.romanov@nginx.com 
2875206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
2876206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
2877206Smax.romanov@nginx.com 
2878277Sigor@sysoev.ru             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem)
2879277Sigor@sysoev.ru                 || ap->r.header.bufs
2880277Sigor@sysoev.ru                    >= joint->socket_conf->large_header_buffers)
2881277Sigor@sysoev.ru             {
2882206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
2883206Smax.romanov@nginx.com                                      "Too long request headers");
2884206Smax.romanov@nginx.com                 return;
2885206Smax.romanov@nginx.com             }
2886206Smax.romanov@nginx.com 
2887206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2888206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2889206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
2890206Smax.romanov@nginx.com                                      "Failed to allocate large header "
2891206Smax.romanov@nginx.com                                      "buffer");
2892206Smax.romanov@nginx.com                 return;
2893206Smax.romanov@nginx.com             }
2894206Smax.romanov@nginx.com 
2895206Smax.romanov@nginx.com             ap->r.header.bufs++;
2896206Smax.romanov@nginx.com 
2897206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
2898206Smax.romanov@nginx.com 
2899206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
2900206Smax.romanov@nginx.com         }
2901206Smax.romanov@nginx.com 
2902206Smax.romanov@nginx.com     }
2903206Smax.romanov@nginx.com 
2904206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
2905206Smax.romanov@nginx.com }
2906206Smax.romanov@nginx.com 
2907206Smax.romanov@nginx.com 
2908206Smax.romanov@nginx.com static void
2909206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
2910206Smax.romanov@nginx.com {
2911206Smax.romanov@nginx.com     size_t                    size;
2912206Smax.romanov@nginx.com     nxt_int_t                 ret;
2913206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
2914206Smax.romanov@nginx.com     nxt_conn_t                *c;
2915206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2916206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
2917206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
2918206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
2919206Smax.romanov@nginx.com 
2920206Smax.romanov@nginx.com     c = obj;
2921206Smax.romanov@nginx.com     ap = data;
2922206Smax.romanov@nginx.com     buf = c->read;
2923206Smax.romanov@nginx.com 
2924206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
2925206Smax.romanov@nginx.com 
2926206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
2927206Smax.romanov@nginx.com 
2928206Smax.romanov@nginx.com     b = &ap->r.body;
2929206Smax.romanov@nginx.com     h = &ap->r.header;
2930206Smax.romanov@nginx.com 
2931206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
2932206Smax.romanov@nginx.com 
2933206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
2934206Smax.romanov@nginx.com 
2935206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
2936206Smax.romanov@nginx.com 
2937206Smax.romanov@nginx.com     case NXT_DONE:
293888Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
293988Smax.romanov@nginx.com         return;
294053Sigor@sysoev.ru 
294153Sigor@sysoev.ru     case NXT_ERROR:
2942206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
294353Sigor@sysoev.ru         return;
294453Sigor@sysoev.ru 
294553Sigor@sysoev.ru     default:  /* NXT_AGAIN */
294653Sigor@sysoev.ru 
2947206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2948206Smax.romanov@nginx.com             joint = c->listen->socket.data;
2949206Smax.romanov@nginx.com 
2950206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2951206Smax.romanov@nginx.com 
2952206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2953206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
2954206Smax.romanov@nginx.com 
2955206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2956206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2957206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2958206Smax.romanov@nginx.com                                      "buffer for request body");
2959206Smax.romanov@nginx.com                 return;
296088Smax.romanov@nginx.com             }
2961206Smax.romanov@nginx.com 
2962206Smax.romanov@nginx.com             c->read = buf->next;
296388Smax.romanov@nginx.com         }
296488Smax.romanov@nginx.com 
2965206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
2966206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
296788Smax.romanov@nginx.com     }
296888Smax.romanov@nginx.com 
296988Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
297088Smax.romanov@nginx.com }
297188Smax.romanov@nginx.com 
297288Smax.romanov@nginx.com 
297388Smax.romanov@nginx.com static void
297488Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
297588Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
297688Smax.romanov@nginx.com {
2977167Smax.romanov@nginx.com     nxt_mp_t             *port_mp;
2978122Smax.romanov@nginx.com     nxt_int_t            res;
2979167Smax.romanov@nginx.com     nxt_port_t           *port;
298088Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
2981167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
298288Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
298388Smax.romanov@nginx.com 
298488Smax.romanov@nginx.com     engine = task->thread->engine;
298588Smax.romanov@nginx.com 
2986*318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
2987*318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
2988*318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
2989*318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
2990122Smax.romanov@nginx.com 
299188Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
2992141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
2993141Smax.romanov@nginx.com                              "req->conn link");
2994141Smax.romanov@nginx.com 
2995141Smax.romanov@nginx.com         return;
299688Smax.romanov@nginx.com     }
299788Smax.romanov@nginx.com 
2998*318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
2999*318Smax.romanov@nginx.com     rc->conn = c;
3000*318Smax.romanov@nginx.com 
3001*318Smax.romanov@nginx.com     nxt_queue_insert_tail(&c->requests, &rc->link);
3002*318Smax.romanov@nginx.com 
3003*318Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD linked to conn %p at engine %p",
3004*318Smax.romanov@nginx.com               rc->stream, c, engine);
300553Sigor@sysoev.ru 
3006273Smax.romanov@nginx.com     c->socket.data = NULL;
3007167Smax.romanov@nginx.com 
3008167Smax.romanov@nginx.com     ra = nxt_router_ra_create(task, rc);
3009167Smax.romanov@nginx.com 
3010167Smax.romanov@nginx.com     ra->ap = ap;
3011167Smax.romanov@nginx.com 
3012167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
3013141Smax.romanov@nginx.com 
3014141Smax.romanov@nginx.com     if (res != NXT_OK) {
3015141Smax.romanov@nginx.com         return;
3016141Smax.romanov@nginx.com     }
3017141Smax.romanov@nginx.com 
3018167Smax.romanov@nginx.com     port = ra->app_port;
3019141Smax.romanov@nginx.com 
3020141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
3021*318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Application port not found");
3022141Smax.romanov@nginx.com         return;
3023141Smax.romanov@nginx.com     }
3024141Smax.romanov@nginx.com 
3025*318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
3026*318Smax.romanov@nginx.com 
3027122Smax.romanov@nginx.com     port_mp = port->mem_pool;
3028167Smax.romanov@nginx.com     port->mem_pool = c->mem_pool;
3029167Smax.romanov@nginx.com 
3030167Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra, port);
3031167Smax.romanov@nginx.com 
3032167Smax.romanov@nginx.com     port->mem_pool = port_mp;
3033167Smax.romanov@nginx.com 
3034167Smax.romanov@nginx.com     nxt_router_ra_release(task, ra, ra->work.data);
3035167Smax.romanov@nginx.com }
3036167Smax.romanov@nginx.com 
3037167Smax.romanov@nginx.com 
3038167Smax.romanov@nginx.com static void
3039167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra,
3040167Smax.romanov@nginx.com     nxt_port_t *port)
3041167Smax.romanov@nginx.com {
3042167Smax.romanov@nginx.com     nxt_int_t            res;
3043167Smax.romanov@nginx.com     nxt_port_t           *c_port, *reply_port;
3044167Smax.romanov@nginx.com     nxt_conn_t           *c;
3045167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
3046167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
3047167Smax.romanov@nginx.com 
3048*318Smax.romanov@nginx.com     /* TODO: it is unsafe to use ra->rc and ra->rc->conn in main thread */
3049*318Smax.romanov@nginx.com 
3050*318Smax.romanov@nginx.com     nxt_assert(ra->rc != NULL);
3051*318Smax.romanov@nginx.com 
3052167Smax.romanov@nginx.com     reply_port = ra->reply_port;
3053167Smax.romanov@nginx.com     ap = ra->ap;
3054167Smax.romanov@nginx.com     c = ra->rc->conn;
3055141Smax.romanov@nginx.com 
3056141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
3057141Smax.romanov@nginx.com                                              reply_port->id);
3058141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
3059141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
3060122Smax.romanov@nginx.com 
3061122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
3062167Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
3063141Smax.romanov@nginx.com                                  "Failed to send reply port to application");
3064167Smax.romanov@nginx.com             return;
3065122Smax.romanov@nginx.com         }
3066122Smax.romanov@nginx.com 
3067141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
306888Smax.romanov@nginx.com     }
306988Smax.romanov@nginx.com 
307088Smax.romanov@nginx.com     wmsg.port = port;
307188Smax.romanov@nginx.com     wmsg.write = NULL;
307288Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
3073*318Smax.romanov@nginx.com     wmsg.stream = ra->stream;
3074167Smax.romanov@nginx.com 
3075216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
3076122Smax.romanov@nginx.com 
3077122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3078167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
3079141Smax.romanov@nginx.com                              "Failed to prepare message for application");
3080167Smax.romanov@nginx.com         return;
3081122Smax.romanov@nginx.com     }
308288Smax.romanov@nginx.com 
308388Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
308488Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
308588Smax.romanov@nginx.com                     wmsg.port->socket.fd);
308688Smax.romanov@nginx.com 
3087122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
3088*318Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, wmsg.write);
3089122Smax.romanov@nginx.com 
3090122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3091167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
3092141Smax.romanov@nginx.com                              "Failed to send message to application");
3093167Smax.romanov@nginx.com         return;
3094122Smax.romanov@nginx.com     }
309553Sigor@sysoev.ru }
309653Sigor@sysoev.ru 
309753Sigor@sysoev.ru 
3098216Sigor@sysoev.ru static nxt_int_t
3099216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3100216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3101216Sigor@sysoev.ru {
3102216Sigor@sysoev.ru     nxt_int_t                 rc;
3103216Sigor@sysoev.ru     nxt_buf_t                 *b;
3104216Sigor@sysoev.ru     nxt_http_field_t          *field;
3105216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3106216Sigor@sysoev.ru 
3107216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3108216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3109216Sigor@sysoev.ru 
3110216Sigor@sysoev.ru     h = &r->header;
3111216Sigor@sysoev.ru 
3112216Sigor@sysoev.ru #define RC(S)                                                                 \
3113216Sigor@sysoev.ru     do {                                                                      \
3114216Sigor@sysoev.ru         rc = (S);                                                             \
3115216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3116216Sigor@sysoev.ru             goto fail;                                                        \
3117216Sigor@sysoev.ru         }                                                                     \
3118216Sigor@sysoev.ru     } while(0)
3119216Sigor@sysoev.ru 
3120216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3121216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3122216Sigor@sysoev.ru 
3123216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3124216Sigor@sysoev.ru 
3125216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3126216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3127277Sigor@sysoev.ru 
3128216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3129216Sigor@sysoev.ru         NXT_WRITE(&eof);
3130277Sigor@sysoev.ru 
3131216Sigor@sysoev.ru     } else {
3132216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3133216Sigor@sysoev.ru     }
3134216Sigor@sysoev.ru 
3135216Sigor@sysoev.ru     if (h->query.start != NULL) {
3136216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3137216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3138216Sigor@sysoev.ru     } else {
3139216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3140216Sigor@sysoev.ru     }
3141216Sigor@sysoev.ru 
3142216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3143216Sigor@sysoev.ru 
3144216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3145268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3146216Sigor@sysoev.ru 
3147216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3148216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3149216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3150216Sigor@sysoev.ru 
3151216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3152216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3153216Sigor@sysoev.ru                                              &prefix, &field->name));
3154216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3155216Sigor@sysoev.ru 
3156216Sigor@sysoev.ru     } nxt_list_loop;
3157216Sigor@sysoev.ru 
3158216Sigor@sysoev.ru     /* end-of-headers mark */
3159216Sigor@sysoev.ru     NXT_WRITE(&eof);
3160216Sigor@sysoev.ru 
3161216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3162216Sigor@sysoev.ru 
3163216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3164216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3165216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3166216Sigor@sysoev.ru     }
3167216Sigor@sysoev.ru 
3168216Sigor@sysoev.ru #undef NXT_WRITE
3169216Sigor@sysoev.ru #undef RC
3170216Sigor@sysoev.ru 
3171216Sigor@sysoev.ru     return NXT_OK;
3172216Sigor@sysoev.ru 
3173216Sigor@sysoev.ru fail:
3174216Sigor@sysoev.ru 
3175216Sigor@sysoev.ru     return NXT_ERROR;
3176216Sigor@sysoev.ru }
3177216Sigor@sysoev.ru 
3178216Sigor@sysoev.ru 
3179216Sigor@sysoev.ru static nxt_int_t
3180216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3181216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3182216Sigor@sysoev.ru {
3183216Sigor@sysoev.ru     nxt_int_t                 rc;
3184216Sigor@sysoev.ru     nxt_buf_t                 *b;
3185305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
3186216Sigor@sysoev.ru     nxt_http_field_t          *field;
3187216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3188216Sigor@sysoev.ru 
3189216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3190216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3191216Sigor@sysoev.ru 
3192216Sigor@sysoev.ru     h = &r->header;
3193216Sigor@sysoev.ru 
3194216Sigor@sysoev.ru #define RC(S)                                                                 \
3195216Sigor@sysoev.ru     do {                                                                      \
3196216Sigor@sysoev.ru         rc = (S);                                                             \
3197216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3198216Sigor@sysoev.ru             goto fail;                                                        \
3199216Sigor@sysoev.ru         }                                                                     \
3200216Sigor@sysoev.ru     } while(0)
3201216Sigor@sysoev.ru 
3202216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3203216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3204216Sigor@sysoev.ru 
3205216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3206216Sigor@sysoev.ru 
3207216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3208216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3209277Sigor@sysoev.ru 
3210216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3211216Sigor@sysoev.ru         NXT_WRITE(&eof);
3212277Sigor@sysoev.ru 
3213216Sigor@sysoev.ru     } else {
3214216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3215216Sigor@sysoev.ru     }
3216216Sigor@sysoev.ru 
3217216Sigor@sysoev.ru     if (h->query.start != NULL) {
3218216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3219216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3220216Sigor@sysoev.ru     } else {
3221216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3222216Sigor@sysoev.ru     }
3223216Sigor@sysoev.ru 
3224216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3225216Sigor@sysoev.ru 
3226216Sigor@sysoev.ru     // PHP_SELF
3227216Sigor@sysoev.ru     // SCRIPT_NAME
3228216Sigor@sysoev.ru     // SCRIPT_FILENAME
3229216Sigor@sysoev.ru     // DOCUMENT_ROOT
3230216Sigor@sysoev.ru 
3231216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3232268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3233216Sigor@sysoev.ru 
3234216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3235216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3236216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3237216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3238216Sigor@sysoev.ru 
3239216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3240305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3241305Smax.romanov@nginx.com 
3242305Smax.romanov@nginx.com     method_is_post = h->method.length == 4 &&
3243305Smax.romanov@nginx.com                      h->method.start[0] == 'P' &&
3244305Smax.romanov@nginx.com                      h->method.start[1] == 'O' &&
3245305Smax.romanov@nginx.com                      h->method.start[2] == 'S' &&
3246305Smax.romanov@nginx.com                      h->method.start[3] == 'T';
3247305Smax.romanov@nginx.com 
3248305Smax.romanov@nginx.com     if (method_is_post) {
3249305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3250305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3251305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3252305Smax.romanov@nginx.com         }
3253305Smax.romanov@nginx.com     }
3254216Sigor@sysoev.ru 
3255216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3256216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3257216Sigor@sysoev.ru                                              &prefix, &field->name));
3258216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3259216Sigor@sysoev.ru 
3260216Sigor@sysoev.ru     } nxt_list_loop;
3261216Sigor@sysoev.ru 
3262216Sigor@sysoev.ru     /* end-of-headers mark */
3263216Sigor@sysoev.ru     NXT_WRITE(&eof);
3264216Sigor@sysoev.ru 
3265305Smax.romanov@nginx.com     if (!method_is_post) {
3266305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3267305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3268305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3269305Smax.romanov@nginx.com         }
3270216Sigor@sysoev.ru     }
3271216Sigor@sysoev.ru 
3272216Sigor@sysoev.ru #undef NXT_WRITE
3273216Sigor@sysoev.ru #undef RC
3274216Sigor@sysoev.ru 
3275216Sigor@sysoev.ru     return NXT_OK;
3276216Sigor@sysoev.ru 
3277216Sigor@sysoev.ru fail:
3278216Sigor@sysoev.ru 
3279216Sigor@sysoev.ru     return NXT_ERROR;
3280216Sigor@sysoev.ru }
3281216Sigor@sysoev.ru 
3282216Sigor@sysoev.ru 
3283216Sigor@sysoev.ru static nxt_int_t
3284216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3285216Sigor@sysoev.ru {
3286216Sigor@sysoev.ru     nxt_int_t                 rc;
3287216Sigor@sysoev.ru     nxt_buf_t                 *b;
3288216Sigor@sysoev.ru     nxt_http_field_t          *field;
3289216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3290216Sigor@sysoev.ru 
3291216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3292216Sigor@sysoev.ru 
3293216Sigor@sysoev.ru     h = &r->header;
3294216Sigor@sysoev.ru 
3295216Sigor@sysoev.ru #define RC(S)                                                                 \
3296216Sigor@sysoev.ru     do {                                                                      \
3297216Sigor@sysoev.ru         rc = (S);                                                             \
3298216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3299216Sigor@sysoev.ru             goto fail;                                                        \
3300216Sigor@sysoev.ru         }                                                                     \
3301216Sigor@sysoev.ru     } while(0)
3302216Sigor@sysoev.ru 
3303216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3304216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3305216Sigor@sysoev.ru 
3306216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3307216Sigor@sysoev.ru 
3308216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3309216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3310277Sigor@sysoev.ru 
3311216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3312216Sigor@sysoev.ru         NXT_WRITE(&eof);
3313277Sigor@sysoev.ru 
3314216Sigor@sysoev.ru     } else {
3315216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3316216Sigor@sysoev.ru     }
3317216Sigor@sysoev.ru 
3318216Sigor@sysoev.ru     if (h->query.start != NULL) {
3319216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3320216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3321216Sigor@sysoev.ru     } else {
3322216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3323216Sigor@sysoev.ru     }
3324216Sigor@sysoev.ru 
3325216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3326253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3327216Sigor@sysoev.ru 
3328216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3329216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3330216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3331216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3332216Sigor@sysoev.ru 
3333216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3334216Sigor@sysoev.ru 
3335216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3336216Sigor@sysoev.ru         NXT_WRITE(&field->name);
3337216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3338216Sigor@sysoev.ru 
3339216Sigor@sysoev.ru     } nxt_list_loop;
3340216Sigor@sysoev.ru 
3341216Sigor@sysoev.ru     /* end-of-headers mark */
3342216Sigor@sysoev.ru     NXT_WRITE(&eof);
3343216Sigor@sysoev.ru 
3344216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3345216Sigor@sysoev.ru 
3346216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3347216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3348216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3349216Sigor@sysoev.ru     }
3350216Sigor@sysoev.ru 
3351216Sigor@sysoev.ru #undef NXT_WRITE
3352216Sigor@sysoev.ru #undef RC
3353216Sigor@sysoev.ru 
3354216Sigor@sysoev.ru     return NXT_OK;
3355216Sigor@sysoev.ru 
3356216Sigor@sysoev.ru fail:
3357216Sigor@sysoev.ru 
3358216Sigor@sysoev.ru     return NXT_ERROR;
3359216Sigor@sysoev.ru }
3360216Sigor@sysoev.ru 
3361216Sigor@sysoev.ru 
336262Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
336353Sigor@sysoev.ru     nxt_aligned(64) =
336453Sigor@sysoev.ru {
336553Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
336653Sigor@sysoev.ru };
336753Sigor@sysoev.ru 
336853Sigor@sysoev.ru 
336953Sigor@sysoev.ru static void
337088Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
337188Smax.romanov@nginx.com {
337288Smax.romanov@nginx.com     nxt_buf_t         *b;
337388Smax.romanov@nginx.com     nxt_bool_t        last;
337488Smax.romanov@nginx.com     nxt_conn_t        *c;
337588Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
337688Smax.romanov@nginx.com 
337788Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
337888Smax.romanov@nginx.com 
337988Smax.romanov@nginx.com     c = obj;
338088Smax.romanov@nginx.com     b = c->write;
338188Smax.romanov@nginx.com 
338288Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
338388Smax.romanov@nginx.com 
338488Smax.romanov@nginx.com     last = 0;
338588Smax.romanov@nginx.com 
338688Smax.romanov@nginx.com     while (b != NULL) {
338788Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
338888Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
338988Smax.romanov@nginx.com                 break;
339088Smax.romanov@nginx.com             }
339188Smax.romanov@nginx.com         }
339288Smax.romanov@nginx.com 
339388Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
339488Smax.romanov@nginx.com             last = 1;
339588Smax.romanov@nginx.com         }
339688Smax.romanov@nginx.com 
339788Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
339888Smax.romanov@nginx.com 
339988Smax.romanov@nginx.com         b = b->next;
340088Smax.romanov@nginx.com     }
340188Smax.romanov@nginx.com 
340288Smax.romanov@nginx.com     c->write = b;
340388Smax.romanov@nginx.com 
340488Smax.romanov@nginx.com     if (b != NULL) {
340588Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
340688Smax.romanov@nginx.com 
340788Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
3408277Sigor@sysoev.ru 
340988Smax.romanov@nginx.com     } else {
341088Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
341188Smax.romanov@nginx.com                   last);
341288Smax.romanov@nginx.com 
341388Smax.romanov@nginx.com         if (last != 0) {
341488Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
341588Smax.romanov@nginx.com 
341688Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
341788Smax.romanov@nginx.com                                c->socket.data);
341888Smax.romanov@nginx.com         }
341988Smax.romanov@nginx.com     }
342088Smax.romanov@nginx.com }
342188Smax.romanov@nginx.com 
342288Smax.romanov@nginx.com 
342388Smax.romanov@nginx.com static void
342453Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
342553Sigor@sysoev.ru {
342662Sigor@sysoev.ru     nxt_conn_t  *c;
342753Sigor@sysoev.ru 
342853Sigor@sysoev.ru     c = obj;
342953Sigor@sysoev.ru 
343053Sigor@sysoev.ru     nxt_debug(task, "router conn close");
343153Sigor@sysoev.ru 
343253Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
343353Sigor@sysoev.ru 
343462Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
343553Sigor@sysoev.ru }
343653Sigor@sysoev.ru 
343753Sigor@sysoev.ru 
343853Sigor@sysoev.ru static void
3439164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3440164Smax.romanov@nginx.com {
3441164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3442164Smax.romanov@nginx.com 
3443164Smax.romanov@nginx.com     joint = obj;
3444164Smax.romanov@nginx.com 
3445164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3446164Smax.romanov@nginx.com }
3447164Smax.romanov@nginx.com 
3448164Smax.romanov@nginx.com 
3449164Smax.romanov@nginx.com static void
345053Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
345153Sigor@sysoev.ru {
345262Sigor@sysoev.ru     nxt_conn_t               *c;
345388Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
345453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
345553Sigor@sysoev.ru 
345653Sigor@sysoev.ru     c = obj;
345753Sigor@sysoev.ru 
345853Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
345953Sigor@sysoev.ru 
346088Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
346188Smax.romanov@nginx.com 
3462*318Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream);
346388Smax.romanov@nginx.com 
3464141Smax.romanov@nginx.com         if (rc->app_port != NULL) {
3465141Smax.romanov@nginx.com             nxt_router_app_release_port(task, rc->app_port, rc->app_port->app);
3466141Smax.romanov@nginx.com 
3467141Smax.romanov@nginx.com             rc->app_port = NULL;
3468141Smax.romanov@nginx.com         }
3469141Smax.romanov@nginx.com 
3470*318Smax.romanov@nginx.com         nxt_router_rc_unlink(rc);
3471*318Smax.romanov@nginx.com 
3472*318Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream);
347388Smax.romanov@nginx.com 
347488Smax.romanov@nginx.com     } nxt_queue_loop;
347588Smax.romanov@nginx.com 
3476122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3477122Smax.romanov@nginx.com 
3478131Smax.romanov@nginx.com     joint = c->listen->socket.data;
3479131Smax.romanov@nginx.com 
3480131Smax.romanov@nginx.com     task = &task->thread->engine->task;
3481131Smax.romanov@nginx.com 
3482164Smax.romanov@nginx.com     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL);
3483164Smax.romanov@nginx.com 
3484164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
348553Sigor@sysoev.ru }
348653Sigor@sysoev.ru 
348753Sigor@sysoev.ru 
348853Sigor@sysoev.ru static void
348953Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
349053Sigor@sysoev.ru {
349162Sigor@sysoev.ru     nxt_conn_t  *c;
349253Sigor@sysoev.ru 
349353Sigor@sysoev.ru     c = obj;
349453Sigor@sysoev.ru 
349553Sigor@sysoev.ru     nxt_debug(task, "router conn error");
349653Sigor@sysoev.ru 
3497273Smax.romanov@nginx.com     if (c->socket.fd != -1) {
3498273Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_close_state;
3499273Smax.romanov@nginx.com 
3500273Smax.romanov@nginx.com         nxt_conn_close(task->thread->engine, c);
3501273Smax.romanov@nginx.com     }
350253Sigor@sysoev.ru }
350353Sigor@sysoev.ru 
350453Sigor@sysoev.ru 
350553Sigor@sysoev.ru static void
350653Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
350753Sigor@sysoev.ru {
350862Sigor@sysoev.ru     nxt_conn_t   *c;
350962Sigor@sysoev.ru     nxt_timer_t  *timer;
351053Sigor@sysoev.ru 
351153Sigor@sysoev.ru     timer = obj;
351253Sigor@sysoev.ru 
351353Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
351453Sigor@sysoev.ru 
351562Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
351653Sigor@sysoev.ru 
3517206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3518206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3519206Smax.romanov@nginx.com 
3520206Smax.romanov@nginx.com     } else {
3521206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3522206Smax.romanov@nginx.com     }
352353Sigor@sysoev.ru }
352453Sigor@sysoev.ru 
352553Sigor@sysoev.ru 
3526*318Smax.romanov@nginx.com static void
3527*318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
3528*318Smax.romanov@nginx.com {
3529*318Smax.romanov@nginx.com     nxt_conn_t   *c;
3530*318Smax.romanov@nginx.com     nxt_timer_t  *timer;
3531*318Smax.romanov@nginx.com 
3532*318Smax.romanov@nginx.com     timer = obj;
3533*318Smax.romanov@nginx.com 
3534*318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
3535*318Smax.romanov@nginx.com 
3536*318Smax.romanov@nginx.com     c = nxt_read_timer_conn(timer);
3537*318Smax.romanov@nginx.com 
3538*318Smax.romanov@nginx.com     nxt_router_gen_error(task, c, 408, "Application timeout");
3539*318Smax.romanov@nginx.com }
3540*318Smax.romanov@nginx.com 
3541*318Smax.romanov@nginx.com 
354253Sigor@sysoev.ru static nxt_msec_t
354362Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
354453Sigor@sysoev.ru {
354553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
354653Sigor@sysoev.ru 
354753Sigor@sysoev.ru     joint = c->listen->socket.data;
354853Sigor@sysoev.ru 
354953Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
355053Sigor@sysoev.ru }
3551