xref: /unit/src/nxt_router.c (revision 345)
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 {
13318Smax.romanov@nginx.com     nxt_str_t         type;
14318Smax.romanov@nginx.com     uint32_t          workers;
15318Smax.romanov@nginx.com     nxt_msec_t        timeout;
16318Smax.romanov@nginx.com     uint32_t          requests;
17318Smax.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 
28141Smax.romanov@nginx.com 
29318Smax.romanov@nginx.com typedef struct {
30318Smax.romanov@nginx.com     uint32_t             stream;
31318Smax.romanov@nginx.com     nxt_conn_t           *conn;
32343Smax.romanov@nginx.com     nxt_app_t            *app;
33318Smax.romanov@nginx.com     nxt_port_t           *app_port;
34318Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
35318Smax.romanov@nginx.com 
36318Smax.romanov@nginx.com     nxt_queue_link_t     link;     /* for nxt_conn_t.requests */
37318Smax.romanov@nginx.com } nxt_req_conn_link_t;
38318Smax.romanov@nginx.com 
39318Smax.romanov@nginx.com 
40167Smax.romanov@nginx.com struct nxt_req_app_link_s {
41318Smax.romanov@nginx.com     uint32_t             stream;
42167Smax.romanov@nginx.com     nxt_port_t           *app_port;
43318Smax.romanov@nginx.com     nxt_pid_t            app_pid;
44167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
45167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
46167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
47167Smax.romanov@nginx.com 
48167Smax.romanov@nginx.com     nxt_queue_link_t     link; /* for nxt_app_t.requests */
49167Smax.romanov@nginx.com 
50167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
51167Smax.romanov@nginx.com     nxt_work_t           work;
52*345Smax.romanov@nginx.com 
53*345Smax.romanov@nginx.com     int                  err_code;
54*345Smax.romanov@nginx.com     const char           *err_str;
55167Smax.romanov@nginx.com };
56167Smax.romanov@nginx.com 
57167Smax.romanov@nginx.com 
58198Sigor@sysoev.ru typedef struct {
59198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
60198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
61198Sigor@sysoev.ru } nxt_socket_rpc_t;
62198Sigor@sysoev.ru 
63198Sigor@sysoev.ru 
64318Smax.romanov@nginx.com typedef struct {
65318Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
66318Smax.romanov@nginx.com     nxt_port_recv_msg_t  msg;
67318Smax.romanov@nginx.com     nxt_work_t           work;
68318Smax.romanov@nginx.com } nxt_remove_pid_msg_t;
69318Smax.romanov@nginx.com 
70318Smax.romanov@nginx.com 
71343Smax.romanov@nginx.com static nxt_int_t nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app);
72343Smax.romanov@nginx.com 
73*345Smax.romanov@nginx.com static void nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra,
74*345Smax.romanov@nginx.com     int code, const char* str);
75*345Smax.romanov@nginx.com 
76318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj,
77318Smax.romanov@nginx.com     void *data);
78318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj,
79318Smax.romanov@nginx.com     void *data);
80318Smax.romanov@nginx.com 
81139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
82198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
83198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
84139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
85139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
86139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
87139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
88193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
8953Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router,
9053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
9153Sigor@sysoev.ru 
92115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
93115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
94133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
95133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
96133Sigor@sysoev.ru     nxt_str_t *name);
97198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
98198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
99198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
100198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
101198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
102198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
10365Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp,
10465Sigor@sysoev.ru     nxt_sockaddr_t *sa);
10553Sigor@sysoev.ru 
10653Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
10753Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
10853Sigor@sysoev.ru     const nxt_event_interface_t *interface);
109115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
110115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
111115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
112115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
113115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
114115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
115115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets);
116154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
117154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
118154Sigor@sysoev.ru     nxt_work_handler_t handler);
119313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
120313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
121139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
122139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
12353Sigor@sysoev.ru 
12453Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
12553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
12653Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
12753Sigor@sysoev.ru     nxt_event_engine_t *engine);
128343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
129133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
13053Sigor@sysoev.ru 
131315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
132315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
133315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
134315Sigor@sysoev.ru     nxt_work_t *jobs);
13553Sigor@sysoev.ru 
13653Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
13753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
13853Sigor@sysoev.ru     void *data);
13953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
14053Sigor@sysoev.ru     void *data);
14153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
14253Sigor@sysoev.ru     void *data);
143313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
144313Sigor@sysoev.ru     void *data);
14553Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
14653Sigor@sysoev.ru     void *data);
14753Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
14853Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
14953Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
15053Sigor@sysoev.ru     void *data);
15153Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
15253Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
15353Sigor@sysoev.ru 
154343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
155343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
156343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
157343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
158343Smax.romanov@nginx.com 
159343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app);
160343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
161343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
162141Smax.romanov@nginx.com 
16353Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data);
16453Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj,
16553Sigor@sysoev.ru     void *data);
166206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj,
167206Smax.romanov@nginx.com     void *data);
16888Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task,
16988Smax.romanov@nginx.com     nxt_conn_t *c, nxt_app_parse_ctx_t *ap);
170141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task,
171343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
172216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
173216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
174216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
175216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
176216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
177216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
17888Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data);
17953Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data);
18053Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
18153Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data);
18253Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data);
183318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
18462Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
18520Sigor@sysoev.ru 
186141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
187*345Smax.romanov@nginx.com     const char* str);
188141Smax.romanov@nginx.com 
189119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
19020Sigor@sysoev.ru 
191216Sigor@sysoev.ru 
192216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
193216Sigor@sysoev.ru     nxt_python_prepare_msg,
194216Sigor@sysoev.ru     nxt_php_prepare_msg,
195216Sigor@sysoev.ru     nxt_go_prepare_msg,
196216Sigor@sysoev.ru };
197216Sigor@sysoev.ru 
198216Sigor@sysoev.ru 
19920Sigor@sysoev.ru nxt_int_t
200141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
20120Sigor@sysoev.ru {
202141Smax.romanov@nginx.com     nxt_int_t      ret;
203141Smax.romanov@nginx.com     nxt_router_t   *router;
204141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
205141Smax.romanov@nginx.com 
206141Smax.romanov@nginx.com     rt = task->thread->runtime;
20753Sigor@sysoev.ru 
20888Smax.romanov@nginx.com     ret = nxt_app_http_init(task, rt);
20988Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
21088Smax.romanov@nginx.com         return ret;
21188Smax.romanov@nginx.com     }
21288Smax.romanov@nginx.com 
21353Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
21453Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
21553Sigor@sysoev.ru         return NXT_ERROR;
21653Sigor@sysoev.ru     }
21753Sigor@sysoev.ru 
21853Sigor@sysoev.ru     nxt_queue_init(&router->engines);
21953Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
220133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
22153Sigor@sysoev.ru 
222119Smax.romanov@nginx.com     nxt_router = router;
223119Smax.romanov@nginx.com 
224115Sigor@sysoev.ru     return NXT_OK;
225115Sigor@sysoev.ru }
226115Sigor@sysoev.ru 
227115Sigor@sysoev.ru 
228343Smax.romanov@nginx.com static void
229343Smax.romanov@nginx.com nxt_router_start_worker_handler(nxt_task_t *task, nxt_port_t *port, void *data)
230167Smax.romanov@nginx.com {
231343Smax.romanov@nginx.com     size_t         size;
232343Smax.romanov@nginx.com     uint32_t       stream;
233343Smax.romanov@nginx.com     nxt_app_t      *app;
234343Smax.romanov@nginx.com     nxt_buf_t      *b;
235343Smax.romanov@nginx.com     nxt_port_t     *main_port;
236343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
237343Smax.romanov@nginx.com 
238343Smax.romanov@nginx.com     app = data;
239167Smax.romanov@nginx.com 
240167Smax.romanov@nginx.com     rt = task->thread->runtime;
241240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
242167Smax.romanov@nginx.com 
243343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start worker", &app->name, app);
244343Smax.romanov@nginx.com 
245343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
246343Smax.romanov@nginx.com 
247343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
248343Smax.romanov@nginx.com 
249343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
250343Smax.romanov@nginx.com         goto failed;
251167Smax.romanov@nginx.com     }
252167Smax.romanov@nginx.com 
253343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
254343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
255343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
256343Smax.romanov@nginx.com 
257343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
258343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
259343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
260343Smax.romanov@nginx.com                                            -1, app);
261343Smax.romanov@nginx.com 
262343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
263343Smax.romanov@nginx.com         nxt_mp_release(b->data, b);
264343Smax.romanov@nginx.com 
265343Smax.romanov@nginx.com         goto failed;
266343Smax.romanov@nginx.com     }
267343Smax.romanov@nginx.com 
268343Smax.romanov@nginx.com     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
269343Smax.romanov@nginx.com                           stream, port->id, b);
270343Smax.romanov@nginx.com 
271343Smax.romanov@nginx.com     return;
272343Smax.romanov@nginx.com 
273343Smax.romanov@nginx.com failed:
274343Smax.romanov@nginx.com 
275343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
276343Smax.romanov@nginx.com 
277343Smax.romanov@nginx.com     app->pending_workers--;
278343Smax.romanov@nginx.com 
279343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
280343Smax.romanov@nginx.com 
281343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
282167Smax.romanov@nginx.com }
283167Smax.romanov@nginx.com 
284167Smax.romanov@nginx.com 
285343Smax.romanov@nginx.com static nxt_int_t
286343Smax.romanov@nginx.com nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app)
287141Smax.romanov@nginx.com {
288343Smax.romanov@nginx.com     nxt_int_t      res;
289343Smax.romanov@nginx.com     nxt_port_t     *router_port;
290343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
291343Smax.romanov@nginx.com 
292343Smax.romanov@nginx.com     rt = task->thread->runtime;
293343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
294343Smax.romanov@nginx.com 
295343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
296343Smax.romanov@nginx.com 
297343Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_worker_handler,
298343Smax.romanov@nginx.com                         app);
299343Smax.romanov@nginx.com 
300343Smax.romanov@nginx.com     if (res == NXT_OK) {
301343Smax.romanov@nginx.com         return res;
302318Smax.romanov@nginx.com     }
303318Smax.romanov@nginx.com 
304343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
305343Smax.romanov@nginx.com 
306343Smax.romanov@nginx.com     app->pending_workers--;
307343Smax.romanov@nginx.com 
308343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
309343Smax.romanov@nginx.com 
310343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
311343Smax.romanov@nginx.com 
312343Smax.romanov@nginx.com     return NXT_ERROR;
313318Smax.romanov@nginx.com }
314318Smax.romanov@nginx.com 
315318Smax.romanov@nginx.com 
316167Smax.romanov@nginx.com static nxt_req_app_link_t *
317167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc)
318167Smax.romanov@nginx.com {
319167Smax.romanov@nginx.com     nxt_mp_t            *mp;
320318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
321167Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
322167Smax.romanov@nginx.com 
323167Smax.romanov@nginx.com     mp = rc->conn->mem_pool;
324318Smax.romanov@nginx.com     engine = task->thread->engine;
325167Smax.romanov@nginx.com 
326167Smax.romanov@nginx.com     ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t));
327167Smax.romanov@nginx.com 
328167Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
329167Smax.romanov@nginx.com         return NULL;
330167Smax.romanov@nginx.com     }
331167Smax.romanov@nginx.com 
332318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD create", rc->stream);
333167Smax.romanov@nginx.com 
334167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
335167Smax.romanov@nginx.com 
336318Smax.romanov@nginx.com     ra->stream = rc->stream;
337318Smax.romanov@nginx.com     ra->app_pid = -1;
338167Smax.romanov@nginx.com     ra->rc = rc;
339318Smax.romanov@nginx.com     rc->ra = ra;
340318Smax.romanov@nginx.com     ra->reply_port = engine->port;
341167Smax.romanov@nginx.com 
342167Smax.romanov@nginx.com     ra->mem_pool = mp;
343167Smax.romanov@nginx.com 
344167Smax.romanov@nginx.com     ra->work.handler = NULL;
345318Smax.romanov@nginx.com     ra->work.task = &engine->task;
346167Smax.romanov@nginx.com     ra->work.obj = ra;
347318Smax.romanov@nginx.com     ra->work.data = engine;
348167Smax.romanov@nginx.com 
349167Smax.romanov@nginx.com     return ra;
350167Smax.romanov@nginx.com }
351167Smax.romanov@nginx.com 
352167Smax.romanov@nginx.com 
353167Smax.romanov@nginx.com static void
354167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data)
355167Smax.romanov@nginx.com {
356343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
357343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
358343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
359318Smax.romanov@nginx.com 
360318Smax.romanov@nginx.com     ra = obj;
361318Smax.romanov@nginx.com     engine = data;
362318Smax.romanov@nginx.com 
363343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
364343Smax.romanov@nginx.com         if (ra->app_port != NULL) {
365343Smax.romanov@nginx.com             ra->app_pid = ra->app_port->pid;
366318Smax.romanov@nginx.com         }
367318Smax.romanov@nginx.com 
368318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release;
369318Smax.romanov@nginx.com         ra->work.task = &engine->task;
370318Smax.romanov@nginx.com         ra->work.next = NULL;
371318Smax.romanov@nginx.com 
372318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
373318Smax.romanov@nginx.com                   ra->stream, engine);
374318Smax.romanov@nginx.com 
375318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
376318Smax.romanov@nginx.com 
377318Smax.romanov@nginx.com         return;
378318Smax.romanov@nginx.com     }
379318Smax.romanov@nginx.com 
380343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
381343Smax.romanov@nginx.com 
382343Smax.romanov@nginx.com     rc = ra->rc;
383343Smax.romanov@nginx.com 
384343Smax.romanov@nginx.com     if (rc != NULL) {
385343Smax.romanov@nginx.com         if (ra->app_pid != -1) {
386343Smax.romanov@nginx.com             nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_pid);
387343Smax.romanov@nginx.com         }
388343Smax.romanov@nginx.com 
389343Smax.romanov@nginx.com         rc->app_port = ra->app_port;
390343Smax.romanov@nginx.com 
391343Smax.romanov@nginx.com         ra->app_port = NULL;
392343Smax.romanov@nginx.com         rc->ra = NULL;
393343Smax.romanov@nginx.com         ra->rc = NULL;
394318Smax.romanov@nginx.com     }
395318Smax.romanov@nginx.com 
396343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
397343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
398343Smax.romanov@nginx.com 
399343Smax.romanov@nginx.com         ra->app_port = NULL;
400343Smax.romanov@nginx.com     }
401318Smax.romanov@nginx.com 
402318Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
403318Smax.romanov@nginx.com }
404318Smax.romanov@nginx.com 
405318Smax.romanov@nginx.com 
406318Smax.romanov@nginx.com static void
407318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data)
408318Smax.romanov@nginx.com {
409343Smax.romanov@nginx.com     nxt_conn_t           *c;
410343Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
411343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
412343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
413167Smax.romanov@nginx.com 
414167Smax.romanov@nginx.com     ra = obj;
415167Smax.romanov@nginx.com     engine = data;
416167Smax.romanov@nginx.com 
417167Smax.romanov@nginx.com     if (task->thread->engine != engine) {
418318Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_abort;
419167Smax.romanov@nginx.com         ra->work.task = &engine->task;
420167Smax.romanov@nginx.com         ra->work.next = NULL;
421167Smax.romanov@nginx.com 
422318Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine);
423167Smax.romanov@nginx.com 
424167Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
425167Smax.romanov@nginx.com 
426167Smax.romanov@nginx.com         return;
427167Smax.romanov@nginx.com     }
428167Smax.romanov@nginx.com 
429318Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD abort", ra->stream);
430318Smax.romanov@nginx.com 
431343Smax.romanov@nginx.com     rc = ra->rc;
432343Smax.romanov@nginx.com 
433343Smax.romanov@nginx.com     if (rc != NULL) {
434343Smax.romanov@nginx.com         c = rc->conn;
435318Smax.romanov@nginx.com 
436318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
437318Smax.romanov@nginx.com                              "Failed to start application worker");
438343Smax.romanov@nginx.com 
439343Smax.romanov@nginx.com         rc->ra = NULL;
440343Smax.romanov@nginx.com         ra->rc = NULL;
441343Smax.romanov@nginx.com     }
442343Smax.romanov@nginx.com 
443343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
444343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
445343Smax.romanov@nginx.com 
446343Smax.romanov@nginx.com         ra->app_port = NULL;
447167Smax.romanov@nginx.com     }
448167Smax.romanov@nginx.com 
449167Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
450167Smax.romanov@nginx.com }
451167Smax.romanov@nginx.com 
452167Smax.romanov@nginx.com 
453*345Smax.romanov@nginx.com static void
454*345Smax.romanov@nginx.com nxt_router_ra_error_handler(nxt_task_t *task, void *obj, void *data)
455*345Smax.romanov@nginx.com {
456*345Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
457*345Smax.romanov@nginx.com 
458*345Smax.romanov@nginx.com     ra = obj;
459*345Smax.romanov@nginx.com 
460*345Smax.romanov@nginx.com     nxt_router_ra_error(task, ra, ra->err_code, ra->err_str);
461*345Smax.romanov@nginx.com }
462*345Smax.romanov@nginx.com 
463*345Smax.romanov@nginx.com 
464*345Smax.romanov@nginx.com static void
465*345Smax.romanov@nginx.com nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, int code,
466*345Smax.romanov@nginx.com     const char* str)
467*345Smax.romanov@nginx.com {
468*345Smax.romanov@nginx.com     nxt_conn_t           *c;
469*345Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
470*345Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
471*345Smax.romanov@nginx.com 
472*345Smax.romanov@nginx.com     engine = ra->work.data;
473*345Smax.romanov@nginx.com 
474*345Smax.romanov@nginx.com     if (task->thread->engine != engine) {
475*345Smax.romanov@nginx.com         ra->err_code = code;
476*345Smax.romanov@nginx.com         ra->err_str = str;
477*345Smax.romanov@nginx.com 
478*345Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_error_handler;
479*345Smax.romanov@nginx.com         ra->work.task = &engine->task;
480*345Smax.romanov@nginx.com         ra->work.next = NULL;
481*345Smax.romanov@nginx.com 
482*345Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post error to %p", ra->stream, engine);
483*345Smax.romanov@nginx.com 
484*345Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
485*345Smax.romanov@nginx.com 
486*345Smax.romanov@nginx.com         return;
487*345Smax.romanov@nginx.com     }
488*345Smax.romanov@nginx.com 
489*345Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD error", ra->stream);
490*345Smax.romanov@nginx.com 
491*345Smax.romanov@nginx.com     rc = ra->rc;
492*345Smax.romanov@nginx.com 
493*345Smax.romanov@nginx.com     if (rc != NULL) {
494*345Smax.romanov@nginx.com         c = rc->conn;
495*345Smax.romanov@nginx.com 
496*345Smax.romanov@nginx.com         nxt_router_gen_error(task, c, code, str);
497*345Smax.romanov@nginx.com 
498*345Smax.romanov@nginx.com         rc->ra = NULL;
499*345Smax.romanov@nginx.com         ra->rc = NULL;
500*345Smax.romanov@nginx.com     }
501*345Smax.romanov@nginx.com 
502*345Smax.romanov@nginx.com     if (ra->app_port != NULL) {
503*345Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
504*345Smax.romanov@nginx.com 
505*345Smax.romanov@nginx.com         ra->app_port = NULL;
506*345Smax.romanov@nginx.com     }
507*345Smax.romanov@nginx.com 
508*345Smax.romanov@nginx.com     nxt_mp_release(ra->mem_pool, ra);
509*345Smax.romanov@nginx.com }
510*345Smax.romanov@nginx.com 
511*345Smax.romanov@nginx.com 
512343Smax.romanov@nginx.com nxt_inline void
513343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
514343Smax.romanov@nginx.com {
515343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
516343Smax.romanov@nginx.com 
517343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
518343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
519343Smax.romanov@nginx.com 
520343Smax.romanov@nginx.com         rc->app_port = NULL;
521343Smax.romanov@nginx.com     }
522343Smax.romanov@nginx.com 
523343Smax.romanov@nginx.com     ra = rc->ra;
524343Smax.romanov@nginx.com 
525343Smax.romanov@nginx.com     if (ra != NULL) {
526343Smax.romanov@nginx.com         rc->ra = NULL;
527343Smax.romanov@nginx.com         ra->rc = NULL;
528343Smax.romanov@nginx.com 
529343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
530343Smax.romanov@nginx.com 
531343Smax.romanov@nginx.com         if (ra->link.next != NULL) {
532343Smax.romanov@nginx.com             nxt_queue_remove(&ra->link);
533343Smax.romanov@nginx.com 
534343Smax.romanov@nginx.com             ra->link.next = NULL;
535343Smax.romanov@nginx.com 
536343Smax.romanov@nginx.com         } else {
537343Smax.romanov@nginx.com             ra = NULL;
538343Smax.romanov@nginx.com         }
539343Smax.romanov@nginx.com 
540343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
541343Smax.romanov@nginx.com     }
542343Smax.romanov@nginx.com 
543343Smax.romanov@nginx.com     if (ra != NULL) {
544343Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
545343Smax.romanov@nginx.com     }
546343Smax.romanov@nginx.com 
547343Smax.romanov@nginx.com     if (rc->app != NULL) {
548343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
549343Smax.romanov@nginx.com 
550343Smax.romanov@nginx.com         rc->app = NULL;
551343Smax.romanov@nginx.com     }
552343Smax.romanov@nginx.com 
553343Smax.romanov@nginx.com     nxt_queue_remove(&rc->link);
554343Smax.romanov@nginx.com 
555343Smax.romanov@nginx.com     rc->conn = NULL;
556343Smax.romanov@nginx.com }
557343Smax.romanov@nginx.com 
558343Smax.romanov@nginx.com 
559141Smax.romanov@nginx.com void
560141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
561141Smax.romanov@nginx.com {
562141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
563141Smax.romanov@nginx.com 
564192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
565141Smax.romanov@nginx.com         return;
566141Smax.romanov@nginx.com     }
567141Smax.romanov@nginx.com 
568192Smax.romanov@nginx.com     if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) {
569192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
570141Smax.romanov@nginx.com     }
571192Smax.romanov@nginx.com 
572192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
573141Smax.romanov@nginx.com }
574141Smax.romanov@nginx.com 
575141Smax.romanov@nginx.com 
576139Sigor@sysoev.ru void
577139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
578115Sigor@sysoev.ru {
579139Sigor@sysoev.ru     size_t                  dump_size;
580198Sigor@sysoev.ru     nxt_int_t               ret;
581139Sigor@sysoev.ru     nxt_buf_t               *b;
582139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
583139Sigor@sysoev.ru 
584139Sigor@sysoev.ru     b = msg->buf;
585139Sigor@sysoev.ru 
586139Sigor@sysoev.ru     dump_size = nxt_buf_used_size(b);
587139Sigor@sysoev.ru 
588139Sigor@sysoev.ru     if (dump_size > 300) {
589139Sigor@sysoev.ru         dump_size = 300;
59053Sigor@sysoev.ru     }
59153Sigor@sysoev.ru 
592139Sigor@sysoev.ru     nxt_debug(task, "router conf data (%z): %*s",
593139Sigor@sysoev.ru               msg->size, dump_size, b->mem.pos);
594139Sigor@sysoev.ru 
595139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
596139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
597139Sigor@sysoev.ru         return;
59853Sigor@sysoev.ru     }
59953Sigor@sysoev.ru 
600139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
601139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
602139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
603198Sigor@sysoev.ru                                        msg->port_msg.pid,
604198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
605198Sigor@sysoev.ru 
606198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
607198Sigor@sysoev.ru 
608198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
609198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
610198Sigor@sysoev.ru 
611198Sigor@sysoev.ru     } else {
612198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
613139Sigor@sysoev.ru     }
61453Sigor@sysoev.ru }
61553Sigor@sysoev.ru 
61653Sigor@sysoev.ru 
617192Smax.romanov@nginx.com void
618192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
619192Smax.romanov@nginx.com {
620318Smax.romanov@nginx.com     nxt_mp_t              *mp;
621318Smax.romanov@nginx.com     nxt_buf_t             *buf;
622318Smax.romanov@nginx.com     nxt_event_engine_t    *engine;
623318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
624318Smax.romanov@nginx.com 
625192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
626192Smax.romanov@nginx.com 
627192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
628192Smax.romanov@nginx.com         return;
629192Smax.romanov@nginx.com     }
630192Smax.romanov@nginx.com 
631318Smax.romanov@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
632318Smax.romanov@nginx.com 
633318Smax.romanov@nginx.com     buf = nxt_buf_mem_alloc(mp, nxt_buf_used_size(msg->buf), 0);
634318Smax.romanov@nginx.com     buf->mem.free = nxt_cpymem(buf->mem.free, msg->buf->mem.pos,
635318Smax.romanov@nginx.com                                nxt_buf_used_size(msg->buf));
636318Smax.romanov@nginx.com 
637318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
638318Smax.romanov@nginx.com     {
639318Smax.romanov@nginx.com         rp = nxt_mp_retain(mp, sizeof(nxt_remove_pid_msg_t));
640318Smax.romanov@nginx.com 
641318Smax.romanov@nginx.com         rp->mem_pool = mp;
642318Smax.romanov@nginx.com 
643318Smax.romanov@nginx.com         rp->msg.fd = msg->fd;
644318Smax.romanov@nginx.com         rp->msg.buf = buf;
645318Smax.romanov@nginx.com         rp->msg.port = engine->port;
646318Smax.romanov@nginx.com         rp->msg.port_msg = msg->port_msg;
647318Smax.romanov@nginx.com         rp->msg.size = msg->size;
648318Smax.romanov@nginx.com         rp->msg.new_port = NULL;
649318Smax.romanov@nginx.com 
650318Smax.romanov@nginx.com         rp->work.handler = nxt_router_worker_remove_pid_handler;
651318Smax.romanov@nginx.com         rp->work.task = &engine->task;
652318Smax.romanov@nginx.com         rp->work.obj = rp;
653318Smax.romanov@nginx.com         rp->work.data = task->thread->engine;
654318Smax.romanov@nginx.com         rp->work.next = NULL;
655318Smax.romanov@nginx.com 
656318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &rp->work);
657318Smax.romanov@nginx.com     }
658318Smax.romanov@nginx.com     nxt_queue_loop;
659318Smax.romanov@nginx.com 
660340Smax.romanov@nginx.com     nxt_mp_release(mp, NULL);
661340Smax.romanov@nginx.com 
662192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
663192Smax.romanov@nginx.com 
664192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
665192Smax.romanov@nginx.com }
666192Smax.romanov@nginx.com 
667192Smax.romanov@nginx.com 
668318Smax.romanov@nginx.com static void
669318Smax.romanov@nginx.com nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj, void *data)
670318Smax.romanov@nginx.com {
671343Smax.romanov@nginx.com     nxt_pid_t             pid;
672343Smax.romanov@nginx.com     nxt_buf_t             *buf;
673318Smax.romanov@nginx.com     nxt_event_engine_t    *engine;
674318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
675318Smax.romanov@nginx.com 
676318Smax.romanov@nginx.com     rp = obj;
677318Smax.romanov@nginx.com 
678343Smax.romanov@nginx.com     buf = rp->msg.buf;
679343Smax.romanov@nginx.com 
680343Smax.romanov@nginx.com     nxt_assert(nxt_buf_used_size(buf) == sizeof(pid));
681343Smax.romanov@nginx.com 
682343Smax.romanov@nginx.com     nxt_memcpy(&pid, buf->mem.pos, sizeof(pid));
683343Smax.romanov@nginx.com 
684343Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, rp->msg.port, pid);
685318Smax.romanov@nginx.com 
686318Smax.romanov@nginx.com     engine = rp->work.data;
687318Smax.romanov@nginx.com 
688318Smax.romanov@nginx.com     rp->work.handler = nxt_router_worker_remove_pid_done;
689318Smax.romanov@nginx.com     rp->work.task = &engine->task;
690318Smax.romanov@nginx.com     rp->work.next = NULL;
691318Smax.romanov@nginx.com 
692318Smax.romanov@nginx.com     nxt_event_engine_post(engine, &rp->work);
693318Smax.romanov@nginx.com }
694318Smax.romanov@nginx.com 
695318Smax.romanov@nginx.com 
696318Smax.romanov@nginx.com static void
697318Smax.romanov@nginx.com nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj, void *data)
698318Smax.romanov@nginx.com {
699318Smax.romanov@nginx.com     nxt_remove_pid_msg_t  *rp;
700318Smax.romanov@nginx.com 
701318Smax.romanov@nginx.com     rp = obj;
702318Smax.romanov@nginx.com 
703318Smax.romanov@nginx.com     nxt_mp_release(rp->mem_pool, rp);
704318Smax.romanov@nginx.com }
705318Smax.romanov@nginx.com 
706318Smax.romanov@nginx.com 
70753Sigor@sysoev.ru static nxt_router_temp_conf_t *
708139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
70953Sigor@sysoev.ru {
71065Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
71153Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
71253Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
71353Sigor@sysoev.ru 
71465Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
71553Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
71653Sigor@sysoev.ru         return NULL;
71753Sigor@sysoev.ru     }
71853Sigor@sysoev.ru 
71965Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
72053Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
72153Sigor@sysoev.ru         goto fail;
72253Sigor@sysoev.ru     }
72353Sigor@sysoev.ru 
72453Sigor@sysoev.ru     rtcf->mem_pool = mp;
72553Sigor@sysoev.ru 
72665Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
72753Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
72853Sigor@sysoev.ru         goto fail;
72953Sigor@sysoev.ru     }
73053Sigor@sysoev.ru 
73165Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
73253Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
73353Sigor@sysoev.ru         goto temp_fail;
73453Sigor@sysoev.ru     }
73553Sigor@sysoev.ru 
73653Sigor@sysoev.ru     tmcf->mem_pool = tmp;
73753Sigor@sysoev.ru     tmcf->conf = rtcf;
738139Sigor@sysoev.ru     tmcf->count = 1;
739139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
74053Sigor@sysoev.ru 
74153Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
74253Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
74353Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
74453Sigor@sysoev.ru         goto temp_fail;
74553Sigor@sysoev.ru     }
74653Sigor@sysoev.ru 
74753Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
74853Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
74953Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
75053Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
75153Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
752133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
753133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
75453Sigor@sysoev.ru 
75553Sigor@sysoev.ru     return tmcf;
75653Sigor@sysoev.ru 
75753Sigor@sysoev.ru temp_fail:
75853Sigor@sysoev.ru 
75965Sigor@sysoev.ru     nxt_mp_destroy(tmp);
76053Sigor@sysoev.ru 
76153Sigor@sysoev.ru fail:
76253Sigor@sysoev.ru 
76365Sigor@sysoev.ru     nxt_mp_destroy(mp);
76453Sigor@sysoev.ru 
76553Sigor@sysoev.ru     return NULL;
76653Sigor@sysoev.ru }
76753Sigor@sysoev.ru 
76853Sigor@sysoev.ru 
769198Sigor@sysoev.ru static void
770198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
771139Sigor@sysoev.ru {
772139Sigor@sysoev.ru     nxt_int_t                    ret;
773139Sigor@sysoev.ru     nxt_router_t                 *router;
774139Sigor@sysoev.ru     nxt_runtime_t                *rt;
775198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
776198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
777198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
778139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
779139Sigor@sysoev.ru 
780198Sigor@sysoev.ru     tmcf = obj;
781198Sigor@sysoev.ru 
782198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
783198Sigor@sysoev.ru 
784198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
785198Sigor@sysoev.ru         nxt_queue_remove(qlk);
786198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
787198Sigor@sysoev.ru 
788198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
789198Sigor@sysoev.ru 
790198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
791198Sigor@sysoev.ru 
792198Sigor@sysoev.ru         return;
793139Sigor@sysoev.ru     }
794139Sigor@sysoev.ru 
795139Sigor@sysoev.ru     rt = task->thread->runtime;
796139Sigor@sysoev.ru 
797139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
798139Sigor@sysoev.ru 
799198Sigor@sysoev.ru     router = tmcf->conf->router;
800198Sigor@sysoev.ru 
801139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
802139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
803198Sigor@sysoev.ru         goto fail;
804139Sigor@sysoev.ru     }
805139Sigor@sysoev.ru 
806139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
807139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
808198Sigor@sysoev.ru         goto fail;
809139Sigor@sysoev.ru     }
810139Sigor@sysoev.ru 
811343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
812139Sigor@sysoev.ru 
813315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
814139Sigor@sysoev.ru 
815139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
816139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
817139Sigor@sysoev.ru 
818198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
819198Sigor@sysoev.ru 
820198Sigor@sysoev.ru     return;
821198Sigor@sysoev.ru 
822198Sigor@sysoev.ru fail:
823198Sigor@sysoev.ru 
824198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
825198Sigor@sysoev.ru 
826198Sigor@sysoev.ru     return;
827139Sigor@sysoev.ru }
828139Sigor@sysoev.ru 
829139Sigor@sysoev.ru 
830139Sigor@sysoev.ru static void
831139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
832139Sigor@sysoev.ru {
833153Sigor@sysoev.ru     nxt_joint_job_t  *job;
834153Sigor@sysoev.ru 
835153Sigor@sysoev.ru     job = obj;
836153Sigor@sysoev.ru 
837198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
838139Sigor@sysoev.ru }
839139Sigor@sysoev.ru 
840139Sigor@sysoev.ru 
841139Sigor@sysoev.ru static void
842198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
843139Sigor@sysoev.ru {
844139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
845139Sigor@sysoev.ru 
846139Sigor@sysoev.ru     if (--tmcf->count == 0) {
847193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
848139Sigor@sysoev.ru     }
849139Sigor@sysoev.ru }
850139Sigor@sysoev.ru 
851139Sigor@sysoev.ru 
852139Sigor@sysoev.ru static void
853139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
854139Sigor@sysoev.ru {
855148Sigor@sysoev.ru     nxt_socket_t       s;
856149Sigor@sysoev.ru     nxt_router_t       *router;
857148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
858148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
859148Sigor@sysoev.ru 
860198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
861198Sigor@sysoev.ru 
862148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
863148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
864148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
865148Sigor@sysoev.ru     {
866148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
867148Sigor@sysoev.ru         s = skcf->listen.socket;
868148Sigor@sysoev.ru 
869148Sigor@sysoev.ru         if (s != -1) {
870148Sigor@sysoev.ru             nxt_socket_close(task, s);
871148Sigor@sysoev.ru         }
872148Sigor@sysoev.ru 
873148Sigor@sysoev.ru         nxt_free(skcf->socket);
874148Sigor@sysoev.ru     }
875148Sigor@sysoev.ru 
876149Sigor@sysoev.ru     router = tmcf->conf->router;
877149Sigor@sysoev.ru 
878149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
879149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
880149Sigor@sysoev.ru 
881148Sigor@sysoev.ru     // TODO: new engines and threads
882148Sigor@sysoev.ru 
883139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
884139Sigor@sysoev.ru 
885193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
886139Sigor@sysoev.ru }
887139Sigor@sysoev.ru 
888139Sigor@sysoev.ru 
889139Sigor@sysoev.ru static void
890139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
891193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
892139Sigor@sysoev.ru {
893193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
894139Sigor@sysoev.ru }
895139Sigor@sysoev.ru 
896139Sigor@sysoev.ru 
897115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
898115Sigor@sysoev.ru     {
899133Sigor@sysoev.ru         nxt_string("listeners_threads"),
900115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
901115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
902115Sigor@sysoev.ru     },
903115Sigor@sysoev.ru };
904115Sigor@sysoev.ru 
905115Sigor@sysoev.ru 
906133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
907115Sigor@sysoev.ru     {
908133Sigor@sysoev.ru         nxt_string("type"),
909115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
910133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
911115Sigor@sysoev.ru     },
912115Sigor@sysoev.ru 
913115Sigor@sysoev.ru     {
914133Sigor@sysoev.ru         nxt_string("workers"),
915115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
916133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, workers),
917133Sigor@sysoev.ru     },
918318Smax.romanov@nginx.com 
919318Smax.romanov@nginx.com     {
920318Smax.romanov@nginx.com         nxt_string("limits"),
921318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
922318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
923318Smax.romanov@nginx.com     },
924318Smax.romanov@nginx.com };
925318Smax.romanov@nginx.com 
926318Smax.romanov@nginx.com 
927318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
928318Smax.romanov@nginx.com     {
929318Smax.romanov@nginx.com         nxt_string("timeout"),
930318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
931318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
932318Smax.romanov@nginx.com     },
933318Smax.romanov@nginx.com 
934318Smax.romanov@nginx.com     {
935318Smax.romanov@nginx.com         nxt_string("requests"),
936318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
937318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
938318Smax.romanov@nginx.com     },
939133Sigor@sysoev.ru };
940133Sigor@sysoev.ru 
941133Sigor@sysoev.ru 
942133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
943133Sigor@sysoev.ru     {
944133Sigor@sysoev.ru         nxt_string("application"),
945133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
946133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
947115Sigor@sysoev.ru     },
948115Sigor@sysoev.ru };
949115Sigor@sysoev.ru 
950115Sigor@sysoev.ru 
951115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
952115Sigor@sysoev.ru     {
953115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
954115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
955115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
956115Sigor@sysoev.ru     },
957115Sigor@sysoev.ru 
958115Sigor@sysoev.ru     {
959115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
960115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
961115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
962115Sigor@sysoev.ru     },
963115Sigor@sysoev.ru 
964115Sigor@sysoev.ru     {
965206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
966206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
967206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
968206Smax.romanov@nginx.com     },
969206Smax.romanov@nginx.com 
970206Smax.romanov@nginx.com     {
971206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
972206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
973206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
974206Smax.romanov@nginx.com     },
975206Smax.romanov@nginx.com 
976206Smax.romanov@nginx.com     {
977206Smax.romanov@nginx.com         nxt_string("max_body_size"),
978206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
979206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
980206Smax.romanov@nginx.com     },
981206Smax.romanov@nginx.com 
982206Smax.romanov@nginx.com     {
983115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
984115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
985115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
986115Sigor@sysoev.ru     },
987206Smax.romanov@nginx.com 
988206Smax.romanov@nginx.com     {
989206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
990206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
991206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
992206Smax.romanov@nginx.com     },
993115Sigor@sysoev.ru };
994115Sigor@sysoev.ru 
995115Sigor@sysoev.ru 
99653Sigor@sysoev.ru static nxt_int_t
997115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
998115Sigor@sysoev.ru     u_char *start, u_char *end)
99953Sigor@sysoev.ru {
1000133Sigor@sysoev.ru     u_char                      *p;
1001133Sigor@sysoev.ru     size_t                      size;
1002115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1003115Sigor@sysoev.ru     uint32_t                    next;
1004115Sigor@sysoev.ru     nxt_int_t                   ret;
1005115Sigor@sysoev.ru     nxt_str_t                   name;
1006133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1007133Sigor@sysoev.ru     nxt_app_type_t              type;
1008115Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
1009133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
1010133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1011133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1012115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1013216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1014133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1015115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1016115Sigor@sysoev.ru 
1017115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
1018133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1019115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1020115Sigor@sysoev.ru 
1021208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1022115Sigor@sysoev.ru     if (conf == NULL) {
1023115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
1024115Sigor@sysoev.ru         return NXT_ERROR;
1025115Sigor@sysoev.ru     }
1026115Sigor@sysoev.ru 
1027213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
1028213Svbart@nginx.com 
1029213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1030136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
1031115Sigor@sysoev.ru     if (ret != NXT_OK) {
1032133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
1033115Sigor@sysoev.ru         return NXT_ERROR;
1034115Sigor@sysoev.ru     }
1035115Sigor@sysoev.ru 
1036117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
1037117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
1038117Sigor@sysoev.ru     }
1039117Sigor@sysoev.ru 
1040133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1041133Sigor@sysoev.ru     if (applications == NULL) {
1042133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
1043115Sigor@sysoev.ru         return NXT_ERROR;
1044115Sigor@sysoev.ru     }
1045115Sigor@sysoev.ru 
1046133Sigor@sysoev.ru     next = 0;
1047133Sigor@sysoev.ru 
1048133Sigor@sysoev.ru     for ( ;; ) {
1049133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1050133Sigor@sysoev.ru         if (application == NULL) {
1051133Sigor@sysoev.ru             break;
1052133Sigor@sysoev.ru         }
1053133Sigor@sysoev.ru 
1054133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1055133Sigor@sysoev.ru 
1056144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1057144Smax.romanov@nginx.com 
1058144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1059133Sigor@sysoev.ru         if (app == NULL) {
1060133Sigor@sysoev.ru             goto fail;
1061133Sigor@sysoev.ru         }
1062133Sigor@sysoev.ru 
1063144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1064144Smax.romanov@nginx.com 
1065144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1066144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1067133Sigor@sysoev.ru 
1068133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1069133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1070133Sigor@sysoev.ru 
1071144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1072144Smax.romanov@nginx.com 
1073133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1074133Sigor@sysoev.ru 
1075133Sigor@sysoev.ru         prev = nxt_router_app_find(&tmcf->conf->router->apps, &name);
1076133Sigor@sysoev.ru 
1077133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1078133Sigor@sysoev.ru             nxt_free(app);
1079133Sigor@sysoev.ru 
1080133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1081133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1082133Sigor@sysoev.ru             continue;
1083133Sigor@sysoev.ru         }
1084133Sigor@sysoev.ru 
1085263Smax.romanov@nginx.com         apcf.workers = 1;
1086318Smax.romanov@nginx.com         apcf.timeout = 0;
1087318Smax.romanov@nginx.com         apcf.requests = 0;
1088318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1089263Smax.romanov@nginx.com 
1090213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1091136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1092133Sigor@sysoev.ru         if (ret != NXT_OK) {
1093133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
1094133Sigor@sysoev.ru             goto app_fail;
1095133Sigor@sysoev.ru         }
1096115Sigor@sysoev.ru 
1097318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1098318Smax.romanov@nginx.com 
1099318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1100318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits is not object");
1101318Smax.romanov@nginx.com                 goto app_fail;
1102318Smax.romanov@nginx.com             }
1103318Smax.romanov@nginx.com 
1104318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1105318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1106318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1107318Smax.romanov@nginx.com                                       &apcf);
1108318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1109318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits map error");
1110318Smax.romanov@nginx.com                 goto app_fail;
1111318Smax.romanov@nginx.com             }
1112318Smax.romanov@nginx.com         }
1113318Smax.romanov@nginx.com 
1114133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1115133Sigor@sysoev.ru         nxt_debug(task, "application workers: %D", apcf.workers);
1116318Smax.romanov@nginx.com         nxt_debug(task, "application timeout: %D", apcf.timeout);
1117318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1118133Sigor@sysoev.ru 
1119216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1120216Sigor@sysoev.ru 
1121216Sigor@sysoev.ru         if (lang == NULL) {
1122141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1123141Smax.romanov@nginx.com                     &apcf.type);
1124141Smax.romanov@nginx.com             goto app_fail;
1125141Smax.romanov@nginx.com         }
1126141Smax.romanov@nginx.com 
1127216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1128216Sigor@sysoev.ru 
1129216Sigor@sysoev.ru         type = nxt_app_parse_type(&lang->type);
1130216Sigor@sysoev.ru 
1131216Sigor@sysoev.ru         if (type == NXT_APP_UNKNOWN) {
1132216Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1133216Sigor@sysoev.ru                     &lang->type);
1134216Sigor@sysoev.ru             goto app_fail;
1135216Sigor@sysoev.ru         }
1136216Sigor@sysoev.ru 
1137216Sigor@sysoev.ru         if (nxt_app_prepare_msg[type] == NULL) {
1138133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"",
1139216Sigor@sysoev.ru                     &lang->type);
1140133Sigor@sysoev.ru             goto app_fail;
1141133Sigor@sysoev.ru         }
1142133Sigor@sysoev.ru 
1143133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1144133Sigor@sysoev.ru         if (ret != NXT_OK) {
1145133Sigor@sysoev.ru             goto app_fail;
1146133Sigor@sysoev.ru         }
1147133Sigor@sysoev.ru 
1148141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1149141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1150141Smax.romanov@nginx.com 
1151144Smax.romanov@nginx.com         app->name.length = name.length;
1152144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1153144Smax.romanov@nginx.com 
1154133Sigor@sysoev.ru         app->type = type;
1155133Sigor@sysoev.ru         app->max_workers = apcf.workers;
1156318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1157133Sigor@sysoev.ru         app->live = 1;
1158343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1159216Sigor@sysoev.ru         app->prepare_msg = nxt_app_prepare_msg[type];
1160133Sigor@sysoev.ru 
1161133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1162343Smax.romanov@nginx.com 
1163343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1164133Sigor@sysoev.ru     }
1165133Sigor@sysoev.ru 
1166133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1167133Sigor@sysoev.ru #if 0
1168133Sigor@sysoev.ru     if (http == NULL) {
1169133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
1170133Sigor@sysoev.ru         return NXT_ERROR;
1171133Sigor@sysoev.ru     }
1172133Sigor@sysoev.ru #endif
1173133Sigor@sysoev.ru 
1174133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1175115Sigor@sysoev.ru     if (listeners == NULL) {
1176133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
1177115Sigor@sysoev.ru         return NXT_ERROR;
1178115Sigor@sysoev.ru     }
117953Sigor@sysoev.ru 
1180133Sigor@sysoev.ru     next = 0;
118153Sigor@sysoev.ru 
1182115Sigor@sysoev.ru     for ( ;; ) {
1183115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1184115Sigor@sysoev.ru         if (listener == NULL) {
1185115Sigor@sysoev.ru             break;
1186115Sigor@sysoev.ru         }
118753Sigor@sysoev.ru 
1188115Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
1189115Sigor@sysoev.ru         if (sa == NULL) {
1190115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name);
1191133Sigor@sysoev.ru             goto fail;
1192115Sigor@sysoev.ru         }
1193115Sigor@sysoev.ru 
1194115Sigor@sysoev.ru         sa->type = SOCK_STREAM;
1195115Sigor@sysoev.ru 
1196115Sigor@sysoev.ru         nxt_debug(task, "router listener: \"%*s\"",
1197115Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa));
119853Sigor@sysoev.ru 
1199115Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, mp, sa);
1200115Sigor@sysoev.ru         if (skcf == NULL) {
1201133Sigor@sysoev.ru             goto fail;
1202115Sigor@sysoev.ru         }
120353Sigor@sysoev.ru 
1204213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1205136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1206115Sigor@sysoev.ru         if (ret != NXT_OK) {
1207115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
1208133Sigor@sysoev.ru             goto fail;
1209115Sigor@sysoev.ru         }
121053Sigor@sysoev.ru 
1211133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1212133Sigor@sysoev.ru 
1213133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1214133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1215133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1216206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1217206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1218206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
1219133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
1220206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
122153Sigor@sysoev.ru 
1222133Sigor@sysoev.ru         if (http != NULL) {
1223213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1224136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1225133Sigor@sysoev.ru             if (ret != NXT_OK) {
1226133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
1227133Sigor@sysoev.ru                 goto fail;
1228133Sigor@sysoev.ru             }
1229115Sigor@sysoev.ru         }
1230115Sigor@sysoev.ru 
1231115Sigor@sysoev.ru         skcf->listen.handler = nxt_router_conn_init;
1232115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
1233160Sigor@sysoev.ru         skcf->router_conf->count++;
1234133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
1235133Sigor@sysoev.ru                                                             &lscf.application);
1236115Sigor@sysoev.ru 
1237115Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->pending, &skcf->link);
1238115Sigor@sysoev.ru     }
123953Sigor@sysoev.ru 
1240198Sigor@sysoev.ru     nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf);
1241198Sigor@sysoev.ru 
124253Sigor@sysoev.ru     return NXT_OK;
1243133Sigor@sysoev.ru 
1244133Sigor@sysoev.ru app_fail:
1245133Sigor@sysoev.ru 
1246133Sigor@sysoev.ru     nxt_free(app);
1247133Sigor@sysoev.ru 
1248133Sigor@sysoev.ru fail:
1249133Sigor@sysoev.ru 
1250141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1251141Smax.romanov@nginx.com 
1252141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1253133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1254133Sigor@sysoev.ru         nxt_free(app);
1255141Smax.romanov@nginx.com 
1256141Smax.romanov@nginx.com     } nxt_queue_loop;
1257133Sigor@sysoev.ru 
1258133Sigor@sysoev.ru     return NXT_ERROR;
1259133Sigor@sysoev.ru }
1260133Sigor@sysoev.ru 
1261133Sigor@sysoev.ru 
1262133Sigor@sysoev.ru static nxt_app_t *
1263133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1264133Sigor@sysoev.ru {
1265141Smax.romanov@nginx.com     nxt_app_t  *app;
1266141Smax.romanov@nginx.com 
1267141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1268133Sigor@sysoev.ru 
1269133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1270133Sigor@sysoev.ru             return app;
1271133Sigor@sysoev.ru         }
1272141Smax.romanov@nginx.com 
1273141Smax.romanov@nginx.com     } nxt_queue_loop;
1274133Sigor@sysoev.ru 
1275133Sigor@sysoev.ru     return NULL;
1276133Sigor@sysoev.ru }
1277133Sigor@sysoev.ru 
1278133Sigor@sysoev.ru 
1279133Sigor@sysoev.ru static nxt_app_t *
1280133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1281133Sigor@sysoev.ru {
1282133Sigor@sysoev.ru     nxt_app_t  *app;
1283133Sigor@sysoev.ru 
1284133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1285133Sigor@sysoev.ru 
1286133Sigor@sysoev.ru     if (app == NULL) {
1287134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1288133Sigor@sysoev.ru     }
1289133Sigor@sysoev.ru 
1290133Sigor@sysoev.ru     return app;
129153Sigor@sysoev.ru }
129253Sigor@sysoev.ru 
129353Sigor@sysoev.ru 
129453Sigor@sysoev.ru static nxt_socket_conf_t *
129565Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa)
129653Sigor@sysoev.ru {
1297163Smax.romanov@nginx.com     nxt_socket_conf_t  *skcf;
1298163Smax.romanov@nginx.com 
1299163Smax.romanov@nginx.com     skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t));
1300163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
130153Sigor@sysoev.ru         return NULL;
130253Sigor@sysoev.ru     }
130353Sigor@sysoev.ru 
1304163Smax.romanov@nginx.com     skcf->sockaddr = sa;
1305163Smax.romanov@nginx.com 
1306163Smax.romanov@nginx.com     skcf->listen.sockaddr = sa;
1307312Sigor@sysoev.ru 
1308312Sigor@sysoev.ru     nxt_listen_socket_remote_size(&skcf->listen, sa);
1309163Smax.romanov@nginx.com 
1310163Smax.romanov@nginx.com     skcf->listen.socket = -1;
1311163Smax.romanov@nginx.com     skcf->listen.backlog = NXT_LISTEN_BACKLOG;
1312163Smax.romanov@nginx.com     skcf->listen.flags = NXT_NONBLOCK;
1313163Smax.romanov@nginx.com     skcf->listen.read_after_accept = 1;
1314163Smax.romanov@nginx.com 
1315163Smax.romanov@nginx.com     return skcf;
131653Sigor@sysoev.ru }
131753Sigor@sysoev.ru 
131853Sigor@sysoev.ru 
131953Sigor@sysoev.ru static void
132053Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router,
132153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
132253Sigor@sysoev.ru {
132353Sigor@sysoev.ru     nxt_queue_link_t   *nqlk, *oqlk, *next;
132453Sigor@sysoev.ru     nxt_socket_conf_t  *nskcf, *oskcf;
132553Sigor@sysoev.ru 
132653Sigor@sysoev.ru     for (nqlk = nxt_queue_first(&tmcf->pending);
132753Sigor@sysoev.ru          nqlk != nxt_queue_tail(&tmcf->pending);
132853Sigor@sysoev.ru          nqlk = next)
132953Sigor@sysoev.ru     {
133053Sigor@sysoev.ru         next = nxt_queue_next(nqlk);
133153Sigor@sysoev.ru         nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link);
133253Sigor@sysoev.ru 
133353Sigor@sysoev.ru         for (oqlk = nxt_queue_first(&router->sockets);
133453Sigor@sysoev.ru              oqlk != nxt_queue_tail(&router->sockets);
133553Sigor@sysoev.ru              oqlk = nxt_queue_next(oqlk))
133653Sigor@sysoev.ru         {
133753Sigor@sysoev.ru             oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link);
133853Sigor@sysoev.ru 
1339115Sigor@sysoev.ru             if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) {
1340115Sigor@sysoev.ru                 nskcf->socket = oskcf->socket;
1341115Sigor@sysoev.ru                 nskcf->listen.socket = oskcf->listen.socket;
1342115Sigor@sysoev.ru 
134353Sigor@sysoev.ru                 nxt_queue_remove(oqlk);
134453Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->keeping, oqlk);
134553Sigor@sysoev.ru 
134653Sigor@sysoev.ru                 nxt_queue_remove(nqlk);
134753Sigor@sysoev.ru                 nxt_queue_insert_tail(&tmcf->updating, nqlk);
134853Sigor@sysoev.ru 
134953Sigor@sysoev.ru                 break;
135053Sigor@sysoev.ru             }
135153Sigor@sysoev.ru         }
135253Sigor@sysoev.ru     }
135353Sigor@sysoev.ru 
135453Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1355115Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
135653Sigor@sysoev.ru }
135753Sigor@sysoev.ru 
135853Sigor@sysoev.ru 
1359198Sigor@sysoev.ru static void
1360198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1361198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1362198Sigor@sysoev.ru {
1363198Sigor@sysoev.ru     uint32_t          stream;
1364198Sigor@sysoev.ru     nxt_buf_t         *b;
1365198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1366198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1367198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1368198Sigor@sysoev.ru 
1369198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1370198Sigor@sysoev.ru     if (rpc == NULL) {
1371198Sigor@sysoev.ru         goto fail;
1372198Sigor@sysoev.ru     }
1373198Sigor@sysoev.ru 
1374198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1375198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1376198Sigor@sysoev.ru 
1377198Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0);
1378198Sigor@sysoev.ru     if (b == NULL) {
1379198Sigor@sysoev.ru         goto fail;
1380198Sigor@sysoev.ru     }
1381198Sigor@sysoev.ru 
1382198Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr,
1383198Sigor@sysoev.ru                              skcf->sockaddr->sockaddr_size);
1384198Sigor@sysoev.ru 
1385198Sigor@sysoev.ru     rt = task->thread->runtime;
1386240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1387198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1388198Sigor@sysoev.ru 
1389198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1390198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1391198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1392198Sigor@sysoev.ru                                            main_port->pid, rpc);
1393198Sigor@sysoev.ru     if (stream == 0) {
1394198Sigor@sysoev.ru         goto fail;
1395198Sigor@sysoev.ru     }
1396198Sigor@sysoev.ru 
1397198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1398198Sigor@sysoev.ru                           stream, router_port->id, b);
1399198Sigor@sysoev.ru 
1400198Sigor@sysoev.ru     return;
1401198Sigor@sysoev.ru 
1402198Sigor@sysoev.ru fail:
1403198Sigor@sysoev.ru 
1404198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1405198Sigor@sysoev.ru }
1406198Sigor@sysoev.ru 
1407198Sigor@sysoev.ru 
1408198Sigor@sysoev.ru static void
1409198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1410198Sigor@sysoev.ru     void *data)
141153Sigor@sysoev.ru {
1412115Sigor@sysoev.ru     nxt_int_t            ret;
1413115Sigor@sysoev.ru     nxt_socket_t         s;
1414198Sigor@sysoev.ru     nxt_socket_rpc_t     *rpc;
1415115Sigor@sysoev.ru     nxt_router_socket_t  *rtsk;
141653Sigor@sysoev.ru 
1417198Sigor@sysoev.ru     rpc = data;
1418198Sigor@sysoev.ru 
1419198Sigor@sysoev.ru     s = msg->fd;
1420198Sigor@sysoev.ru 
1421198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1422198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1423198Sigor@sysoev.ru         goto fail;
142453Sigor@sysoev.ru     }
142553Sigor@sysoev.ru 
1426229Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr);
1427198Sigor@sysoev.ru 
1428198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1429198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1430198Sigor@sysoev.ru         goto fail;
1431198Sigor@sysoev.ru     }
1432198Sigor@sysoev.ru 
1433198Sigor@sysoev.ru     rtsk = nxt_malloc(sizeof(nxt_router_socket_t));
1434198Sigor@sysoev.ru     if (nxt_slow_path(rtsk == NULL)) {
1435198Sigor@sysoev.ru         goto fail;
1436198Sigor@sysoev.ru     }
1437198Sigor@sysoev.ru 
1438198Sigor@sysoev.ru     rtsk->count = 0;
1439198Sigor@sysoev.ru     rtsk->fd = s;
1440198Sigor@sysoev.ru 
1441198Sigor@sysoev.ru     rpc->socket_conf->listen.socket = s;
1442198Sigor@sysoev.ru     rpc->socket_conf->socket = rtsk;
1443198Sigor@sysoev.ru 
1444198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1445198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1446198Sigor@sysoev.ru 
1447198Sigor@sysoev.ru     return;
1448148Sigor@sysoev.ru 
1449148Sigor@sysoev.ru fail:
1450148Sigor@sysoev.ru 
1451148Sigor@sysoev.ru     nxt_socket_close(task, s);
1452148Sigor@sysoev.ru 
1453198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1454198Sigor@sysoev.ru }
1455198Sigor@sysoev.ru 
1456198Sigor@sysoev.ru 
1457198Sigor@sysoev.ru static void
1458198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1459198Sigor@sysoev.ru     void *data)
1460198Sigor@sysoev.ru {
1461198Sigor@sysoev.ru     u_char                  *p;
1462198Sigor@sysoev.ru     size_t                  size;
1463198Sigor@sysoev.ru     uint8_t                 error;
1464198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1465198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1466198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1467198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1468198Sigor@sysoev.ru 
1469198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1470198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1471198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1472198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1473198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1474198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1475198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1476198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1477198Sigor@sysoev.ru     };
1478198Sigor@sysoev.ru 
1479198Sigor@sysoev.ru     rpc = data;
1480198Sigor@sysoev.ru     sa = rpc->socket_conf->sockaddr;
1481198Sigor@sysoev.ru 
1482198Sigor@sysoev.ru     in = msg->buf;
1483198Sigor@sysoev.ru     p = in->mem.pos;
1484198Sigor@sysoev.ru 
1485198Sigor@sysoev.ru     error = *p++;
1486198Sigor@sysoev.ru 
1487198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1488198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1489198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1490198Sigor@sysoev.ru 
1491198Sigor@sysoev.ru     tmcf = rpc->temp_conf;
1492198Sigor@sysoev.ru 
1493198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1494198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1495198Sigor@sysoev.ru         return;
1496198Sigor@sysoev.ru     }
1497198Sigor@sysoev.ru 
1498198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1499198Sigor@sysoev.ru                         "listen socket error: "
1500198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1501198Sigor@sysoev.ru                         sa->length, nxt_sockaddr_start(sa),
1502198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1503198Sigor@sysoev.ru 
1504198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1505198Sigor@sysoev.ru 
1506198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
150753Sigor@sysoev.ru }
150853Sigor@sysoev.ru 
150953Sigor@sysoev.ru 
151053Sigor@sysoev.ru static nxt_int_t
151153Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
151253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
151353Sigor@sysoev.ru {
151453Sigor@sysoev.ru     nxt_int_t                 ret;
151553Sigor@sysoev.ru     nxt_uint_t                n, threads;
151653Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
151753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
151853Sigor@sysoev.ru 
151953Sigor@sysoev.ru     threads = tmcf->conf->threads;
152053Sigor@sysoev.ru 
152153Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
152253Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
152353Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
152453Sigor@sysoev.ru         return NXT_ERROR;
152553Sigor@sysoev.ru     }
152653Sigor@sysoev.ru 
152753Sigor@sysoev.ru     n = 0;
152853Sigor@sysoev.ru 
152953Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
153053Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
153153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
153253Sigor@sysoev.ru     {
153353Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
153453Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
153553Sigor@sysoev.ru             return NXT_ERROR;
153653Sigor@sysoev.ru         }
153753Sigor@sysoev.ru 
1538115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
153953Sigor@sysoev.ru 
154053Sigor@sysoev.ru         if (n < threads) {
1541315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1542115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
154353Sigor@sysoev.ru 
154453Sigor@sysoev.ru         } else {
1545315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1546115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
154753Sigor@sysoev.ru         }
154853Sigor@sysoev.ru 
154953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
155053Sigor@sysoev.ru             return ret;
155153Sigor@sysoev.ru         }
155253Sigor@sysoev.ru 
155353Sigor@sysoev.ru         n++;
155453Sigor@sysoev.ru     }
155553Sigor@sysoev.ru 
155653Sigor@sysoev.ru     tmcf->new_threads = n;
155753Sigor@sysoev.ru 
155853Sigor@sysoev.ru     while (n < threads) {
155953Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
156053Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
156153Sigor@sysoev.ru             return NXT_ERROR;
156253Sigor@sysoev.ru         }
156353Sigor@sysoev.ru 
1564315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1565315Sigor@sysoev.ru 
156653Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
156753Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
156853Sigor@sysoev.ru             return NXT_ERROR;
156953Sigor@sysoev.ru         }
157053Sigor@sysoev.ru 
1571115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
157253Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
157353Sigor@sysoev.ru             return ret;
157453Sigor@sysoev.ru         }
157553Sigor@sysoev.ru 
157653Sigor@sysoev.ru         n++;
157753Sigor@sysoev.ru     }
157853Sigor@sysoev.ru 
157953Sigor@sysoev.ru     return NXT_OK;
158053Sigor@sysoev.ru }
158153Sigor@sysoev.ru 
158253Sigor@sysoev.ru 
158353Sigor@sysoev.ru static nxt_int_t
1584115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1585115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
158653Sigor@sysoev.ru {
1587115Sigor@sysoev.ru     nxt_int_t              ret;
1588115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
158953Sigor@sysoev.ru 
1590154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1591154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1592115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1593115Sigor@sysoev.ru         return ret;
1594115Sigor@sysoev.ru     }
1595115Sigor@sysoev.ru 
1596154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1597154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
159853Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
159953Sigor@sysoev.ru         return ret;
160053Sigor@sysoev.ru     }
160153Sigor@sysoev.ru 
1602115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1603115Sigor@sysoev.ru 
1604115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1605115Sigor@sysoev.ru 
1606115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1607115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->updating);
1608115Sigor@sysoev.ru 
1609115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1610115Sigor@sysoev.ru 
1611115Sigor@sysoev.ru     return ret;
161253Sigor@sysoev.ru }
161353Sigor@sysoev.ru 
161453Sigor@sysoev.ru 
161553Sigor@sysoev.ru static nxt_int_t
1616115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1617115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
161853Sigor@sysoev.ru {
1619115Sigor@sysoev.ru     nxt_int_t              ret;
1620115Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
162153Sigor@sysoev.ru 
1622154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1623154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
162453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
162553Sigor@sysoev.ru         return ret;
162653Sigor@sysoev.ru     }
162753Sigor@sysoev.ru 
1628154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1629154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
163053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
163153Sigor@sysoev.ru         return ret;
163253Sigor@sysoev.ru     }
163353Sigor@sysoev.ru 
1634139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1635115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1636115Sigor@sysoev.ru         return ret;
1637115Sigor@sysoev.ru     }
1638115Sigor@sysoev.ru 
1639115Sigor@sysoev.ru     lock = &tmcf->conf->router->lock;
1640115Sigor@sysoev.ru 
1641115Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
1642115Sigor@sysoev.ru 
1643115Sigor@sysoev.ru     nxt_router_engine_socket_count(&tmcf->creating);
1644115Sigor@sysoev.ru 
1645115Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
1646115Sigor@sysoev.ru 
1647115Sigor@sysoev.ru     return ret;
164853Sigor@sysoev.ru }
164953Sigor@sysoev.ru 
165053Sigor@sysoev.ru 
165153Sigor@sysoev.ru static nxt_int_t
1652115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1653115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
165453Sigor@sysoev.ru {
165553Sigor@sysoev.ru     nxt_int_t  ret;
165653Sigor@sysoev.ru 
1657313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1658313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1659313Sigor@sysoev.ru         return ret;
1660313Sigor@sysoev.ru     }
1661313Sigor@sysoev.ru 
1662139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
166353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
166453Sigor@sysoev.ru         return ret;
166553Sigor@sysoev.ru     }
166653Sigor@sysoev.ru 
1667139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
166853Sigor@sysoev.ru }
166953Sigor@sysoev.ru 
167053Sigor@sysoev.ru 
167153Sigor@sysoev.ru static nxt_int_t
1672154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
1673154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
167453Sigor@sysoev.ru     nxt_work_handler_t handler)
167553Sigor@sysoev.ru {
1676153Sigor@sysoev.ru     nxt_joint_job_t          *job;
167753Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
1678155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
167953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
168053Sigor@sysoev.ru 
168153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
168253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
168353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
168453Sigor@sysoev.ru     {
1685154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1686153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1687139Sigor@sysoev.ru             return NXT_ERROR;
1688139Sigor@sysoev.ru         }
1689139Sigor@sysoev.ru 
1690154Sigor@sysoev.ru         job->work.next = recf->jobs;
1691154Sigor@sysoev.ru         recf->jobs = &job->work;
1692154Sigor@sysoev.ru 
1693153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1694153Sigor@sysoev.ru         job->work.handler = handler;
1695153Sigor@sysoev.ru         job->work.task = &job->task;
1696153Sigor@sysoev.ru         job->work.obj = job;
1697153Sigor@sysoev.ru         job->tmcf = tmcf;
169853Sigor@sysoev.ru 
1699154Sigor@sysoev.ru         tmcf->count++;
1700154Sigor@sysoev.ru 
1701154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
1702154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
170353Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
170453Sigor@sysoev.ru             return NXT_ERROR;
170553Sigor@sysoev.ru         }
170653Sigor@sysoev.ru 
1707153Sigor@sysoev.ru         job->work.data = joint;
170853Sigor@sysoev.ru 
170953Sigor@sysoev.ru         joint->count = 1;
1710155Sigor@sysoev.ru 
1711155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1712155Sigor@sysoev.ru         skcf->count++;
1713155Sigor@sysoev.ru         joint->socket_conf = skcf;
1714155Sigor@sysoev.ru 
171588Smax.romanov@nginx.com         joint->engine = recf->engine;
171653Sigor@sysoev.ru     }
171753Sigor@sysoev.ru 
171820Sigor@sysoev.ru     return NXT_OK;
171920Sigor@sysoev.ru }
172020Sigor@sysoev.ru 
172120Sigor@sysoev.ru 
1722115Sigor@sysoev.ru static void
1723115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets)
1724115Sigor@sysoev.ru {
1725115Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1726115Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1727115Sigor@sysoev.ru 
1728115Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
1729115Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
1730115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1731115Sigor@sysoev.ru     {
1732115Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1733115Sigor@sysoev.ru         skcf->socket->count++;
1734115Sigor@sysoev.ru     }
1735115Sigor@sysoev.ru }
1736115Sigor@sysoev.ru 
1737115Sigor@sysoev.ru 
173820Sigor@sysoev.ru static nxt_int_t
1739313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
1740313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
1741313Sigor@sysoev.ru {
1742313Sigor@sysoev.ru     nxt_joint_job_t  *job;
1743313Sigor@sysoev.ru 
1744313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1745313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
1746313Sigor@sysoev.ru         return NXT_ERROR;
1747313Sigor@sysoev.ru     }
1748313Sigor@sysoev.ru 
1749313Sigor@sysoev.ru     job->work.next = recf->jobs;
1750313Sigor@sysoev.ru     recf->jobs = &job->work;
1751313Sigor@sysoev.ru 
1752313Sigor@sysoev.ru     job->task = tmcf->engine->task;
1753313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
1754313Sigor@sysoev.ru     job->work.task = &job->task;
1755313Sigor@sysoev.ru     job->work.obj = NULL;
1756313Sigor@sysoev.ru     job->work.data = NULL;
1757313Sigor@sysoev.ru     job->tmcf = NULL;
1758313Sigor@sysoev.ru 
1759313Sigor@sysoev.ru     return NXT_OK;
1760313Sigor@sysoev.ru }
1761313Sigor@sysoev.ru 
1762313Sigor@sysoev.ru 
1763313Sigor@sysoev.ru static nxt_int_t
1764139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
1765139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
176620Sigor@sysoev.ru {
1767153Sigor@sysoev.ru     nxt_joint_job_t   *job;
176853Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
176920Sigor@sysoev.ru 
177053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
177153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
177253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
177353Sigor@sysoev.ru     {
1774154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
1775153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
1776139Sigor@sysoev.ru             return NXT_ERROR;
1777139Sigor@sysoev.ru         }
1778139Sigor@sysoev.ru 
1779154Sigor@sysoev.ru         job->work.next = recf->jobs;
1780154Sigor@sysoev.ru         recf->jobs = &job->work;
1781154Sigor@sysoev.ru 
1782153Sigor@sysoev.ru         job->task = tmcf->engine->task;
1783153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
1784153Sigor@sysoev.ru         job->work.task = &job->task;
1785153Sigor@sysoev.ru         job->work.obj = job;
1786153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1787153Sigor@sysoev.ru         job->tmcf = tmcf;
1788154Sigor@sysoev.ru 
1789154Sigor@sysoev.ru         tmcf->count++;
179020Sigor@sysoev.ru     }
179120Sigor@sysoev.ru 
179253Sigor@sysoev.ru     return NXT_OK;
179353Sigor@sysoev.ru }
179420Sigor@sysoev.ru 
179520Sigor@sysoev.ru 
179653Sigor@sysoev.ru static nxt_int_t
179753Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
179853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
179953Sigor@sysoev.ru {
180053Sigor@sysoev.ru     nxt_int_t                 ret;
180153Sigor@sysoev.ru     nxt_uint_t                i, threads;
180253Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
180320Sigor@sysoev.ru 
180453Sigor@sysoev.ru     recf = tmcf->engines->elts;
180553Sigor@sysoev.ru     threads = tmcf->conf->threads;
180620Sigor@sysoev.ru 
180753Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
180853Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
180953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
181053Sigor@sysoev.ru             return ret;
181153Sigor@sysoev.ru         }
181220Sigor@sysoev.ru     }
181320Sigor@sysoev.ru 
181420Sigor@sysoev.ru     return NXT_OK;
181520Sigor@sysoev.ru }
181653Sigor@sysoev.ru 
181753Sigor@sysoev.ru 
181853Sigor@sysoev.ru static nxt_int_t
181953Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
182053Sigor@sysoev.ru     nxt_event_engine_t *engine)
182153Sigor@sysoev.ru {
182253Sigor@sysoev.ru     nxt_int_t            ret;
182353Sigor@sysoev.ru     nxt_thread_link_t    *link;
182453Sigor@sysoev.ru     nxt_thread_handle_t  handle;
182553Sigor@sysoev.ru 
182653Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
182753Sigor@sysoev.ru 
182853Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
182953Sigor@sysoev.ru         return NXT_ERROR;
183053Sigor@sysoev.ru     }
183153Sigor@sysoev.ru 
183253Sigor@sysoev.ru     link->start = nxt_router_thread_start;
183353Sigor@sysoev.ru     link->engine = engine;
183453Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
183553Sigor@sysoev.ru     link->work.task = task;
183653Sigor@sysoev.ru     link->work.data = link;
183753Sigor@sysoev.ru 
183853Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
183953Sigor@sysoev.ru 
184053Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
184153Sigor@sysoev.ru 
184253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
184353Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
184453Sigor@sysoev.ru     }
184553Sigor@sysoev.ru 
184653Sigor@sysoev.ru     return ret;
184753Sigor@sysoev.ru }
184853Sigor@sysoev.ru 
184953Sigor@sysoev.ru 
185053Sigor@sysoev.ru static void
1851343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
1852343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
1853133Sigor@sysoev.ru {
1854343Smax.romanov@nginx.com     nxt_app_t   *app;
1855343Smax.romanov@nginx.com     nxt_port_t  *port;
1856141Smax.romanov@nginx.com 
1857141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
1858133Sigor@sysoev.ru 
1859133Sigor@sysoev.ru         nxt_queue_remove(&app->link);
1860133Sigor@sysoev.ru 
1861343Smax.romanov@nginx.com         nxt_debug(task, "about to free app '%V' %p", &app->name, app);
1862167Smax.romanov@nginx.com 
1863163Smax.romanov@nginx.com         app->live = 0;
1864163Smax.romanov@nginx.com 
1865167Smax.romanov@nginx.com         do {
1866343Smax.romanov@nginx.com             port = nxt_router_app_get_idle_port(app);
1867167Smax.romanov@nginx.com             if (port == NULL) {
1868167Smax.romanov@nginx.com                 break;
1869167Smax.romanov@nginx.com             }
1870167Smax.romanov@nginx.com 
1871343Smax.romanov@nginx.com             nxt_debug(task, "port %p send quit", port);
1872343Smax.romanov@nginx.com 
1873343Smax.romanov@nginx.com             nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0,
1874343Smax.romanov@nginx.com                                   NULL);
1875343Smax.romanov@nginx.com 
1876343Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
1877167Smax.romanov@nginx.com         } while (1);
1878167Smax.romanov@nginx.com 
1879343Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
1880343Smax.romanov@nginx.com 
1881141Smax.romanov@nginx.com     } nxt_queue_loop;
1882133Sigor@sysoev.ru 
1883133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
1884133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
1885133Sigor@sysoev.ru }
1886133Sigor@sysoev.ru 
1887133Sigor@sysoev.ru 
1888133Sigor@sysoev.ru static void
1889315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
189053Sigor@sysoev.ru {
189153Sigor@sysoev.ru     nxt_uint_t                n;
1892315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
189353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
189453Sigor@sysoev.ru 
189553Sigor@sysoev.ru     recf = tmcf->engines->elts;
189653Sigor@sysoev.ru 
189753Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
1898315Sigor@sysoev.ru         engine = recf->engine;
1899315Sigor@sysoev.ru 
1900315Sigor@sysoev.ru         switch (recf->action) {
1901315Sigor@sysoev.ru 
1902315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
1903315Sigor@sysoev.ru             break;
1904315Sigor@sysoev.ru 
1905315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
1906315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
1907315Sigor@sysoev.ru             break;
1908315Sigor@sysoev.ru 
1909315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
1910315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
1911315Sigor@sysoev.ru             break;
1912315Sigor@sysoev.ru         }
1913315Sigor@sysoev.ru 
1914316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
1915316Sigor@sysoev.ru 
191653Sigor@sysoev.ru         recf++;
191753Sigor@sysoev.ru     }
191853Sigor@sysoev.ru }
191953Sigor@sysoev.ru 
192053Sigor@sysoev.ru 
192153Sigor@sysoev.ru static void
1922315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
192353Sigor@sysoev.ru {
1924154Sigor@sysoev.ru     nxt_work_t  *work, *next;
1925154Sigor@sysoev.ru 
1926315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
1927154Sigor@sysoev.ru         next = work->next;
1928154Sigor@sysoev.ru         work->next = NULL;
1929154Sigor@sysoev.ru 
1930315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
193153Sigor@sysoev.ru     }
193253Sigor@sysoev.ru }
193353Sigor@sysoev.ru 
193453Sigor@sysoev.ru 
1935320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
1936320Smax.romanov@nginx.com     .mmap = nxt_port_mmap_handler,
1937320Smax.romanov@nginx.com     .data = nxt_port_rpc_handler,
193888Smax.romanov@nginx.com };
193988Smax.romanov@nginx.com 
194088Smax.romanov@nginx.com 
194188Smax.romanov@nginx.com static void
194253Sigor@sysoev.ru nxt_router_thread_start(void *data)
194353Sigor@sysoev.ru {
1944141Smax.romanov@nginx.com     nxt_int_t           ret;
1945141Smax.romanov@nginx.com     nxt_port_t          *port;
194688Smax.romanov@nginx.com     nxt_task_t          *task;
194753Sigor@sysoev.ru     nxt_thread_t        *thread;
194853Sigor@sysoev.ru     nxt_thread_link_t   *link;
194953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
195053Sigor@sysoev.ru 
195153Sigor@sysoev.ru     link = data;
195253Sigor@sysoev.ru     engine = link->engine;
195388Smax.romanov@nginx.com     task = &engine->task;
195453Sigor@sysoev.ru 
195553Sigor@sysoev.ru     thread = nxt_thread();
195653Sigor@sysoev.ru 
1957165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
1958165Smax.romanov@nginx.com 
195953Sigor@sysoev.ru     /* STUB */
196053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
196153Sigor@sysoev.ru 
196253Sigor@sysoev.ru     engine->task.thread = thread;
196353Sigor@sysoev.ru     engine->task.log = thread->log;
196453Sigor@sysoev.ru     thread->engine = engine;
196563Sigor@sysoev.ru     thread->task = &engine->task;
1966326Svbart@nginx.com #if 0
196753Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
1968326Svbart@nginx.com #endif
196953Sigor@sysoev.ru 
197063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
1971337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
1972337Sigor@sysoev.ru         return;
1973337Sigor@sysoev.ru     }
197453Sigor@sysoev.ru 
1975197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
1976197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
1977141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
1978141Smax.romanov@nginx.com         return;
1979141Smax.romanov@nginx.com     }
1980141Smax.romanov@nginx.com 
1981141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
1982141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1983343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
1984141Smax.romanov@nginx.com         return;
1985141Smax.romanov@nginx.com     }
1986141Smax.romanov@nginx.com 
1987141Smax.romanov@nginx.com     engine->port = port;
1988141Smax.romanov@nginx.com 
1989320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
1990141Smax.romanov@nginx.com 
199153Sigor@sysoev.ru     nxt_event_engine_start(engine);
199253Sigor@sysoev.ru }
199353Sigor@sysoev.ru 
199453Sigor@sysoev.ru 
199553Sigor@sysoev.ru static void
199653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
199753Sigor@sysoev.ru {
1998153Sigor@sysoev.ru     nxt_joint_job_t          *job;
199953Sigor@sysoev.ru     nxt_listen_event_t       *listen;
200053Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
200153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
200253Sigor@sysoev.ru 
2003153Sigor@sysoev.ru     job = obj;
200453Sigor@sysoev.ru     joint = data;
200553Sigor@sysoev.ru 
200653Sigor@sysoev.ru     ls = &joint->socket_conf->listen;
200753Sigor@sysoev.ru 
2008159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2009159Sigor@sysoev.ru 
201053Sigor@sysoev.ru     listen = nxt_listen_event(task, ls);
201153Sigor@sysoev.ru     if (nxt_slow_path(listen == NULL)) {
201253Sigor@sysoev.ru         nxt_router_listen_socket_release(task, joint);
201353Sigor@sysoev.ru         return;
201453Sigor@sysoev.ru     }
201553Sigor@sysoev.ru 
201653Sigor@sysoev.ru     listen->socket.data = joint;
2017139Sigor@sysoev.ru 
2018153Sigor@sysoev.ru     job->work.next = NULL;
2019153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2020153Sigor@sysoev.ru 
2021153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
202253Sigor@sysoev.ru }
202353Sigor@sysoev.ru 
202453Sigor@sysoev.ru 
202553Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
202653Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
202753Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
202853Sigor@sysoev.ru {
2029115Sigor@sysoev.ru     nxt_socket_t        fd;
2030115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
203153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
203253Sigor@sysoev.ru 
2033115Sigor@sysoev.ru     fd = skcf->socket->fd;
203453Sigor@sysoev.ru 
2035115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2036115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2037115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
203853Sigor@sysoev.ru     {
2039115Sigor@sysoev.ru         listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
204053Sigor@sysoev.ru 
2041115Sigor@sysoev.ru         if (fd == listen->socket.fd) {
204253Sigor@sysoev.ru             return listen;
204353Sigor@sysoev.ru         }
204453Sigor@sysoev.ru     }
204553Sigor@sysoev.ru 
204653Sigor@sysoev.ru     return NULL;
204753Sigor@sysoev.ru }
204853Sigor@sysoev.ru 
204953Sigor@sysoev.ru 
205053Sigor@sysoev.ru static void
205153Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
205253Sigor@sysoev.ru {
2053153Sigor@sysoev.ru     nxt_joint_job_t          *job;
205453Sigor@sysoev.ru     nxt_event_engine_t       *engine;
205553Sigor@sysoev.ru     nxt_listen_event_t       *listen;
205653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
205753Sigor@sysoev.ru 
2058153Sigor@sysoev.ru     job = obj;
205953Sigor@sysoev.ru     joint = data;
206053Sigor@sysoev.ru 
2061139Sigor@sysoev.ru     engine = task->thread->engine;
2062139Sigor@sysoev.ru 
2063159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2064159Sigor@sysoev.ru 
206553Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections,
206653Sigor@sysoev.ru                                      joint->socket_conf);
206753Sigor@sysoev.ru 
206853Sigor@sysoev.ru     old = listen->socket.data;
206953Sigor@sysoev.ru     listen->socket.data = joint;
2070177Sigor@sysoev.ru     listen->listen = &joint->socket_conf->listen;
207153Sigor@sysoev.ru 
2072153Sigor@sysoev.ru     job->work.next = NULL;
2073153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2074153Sigor@sysoev.ru 
2075153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2076139Sigor@sysoev.ru 
2077181Smax.romanov@nginx.com     /*
2078181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2079181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2080181Smax.romanov@nginx.com      */
2081181Smax.romanov@nginx.com 
2082181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
208353Sigor@sysoev.ru }
208453Sigor@sysoev.ru 
208553Sigor@sysoev.ru 
208653Sigor@sysoev.ru static void
208753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
208853Sigor@sysoev.ru {
2089153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2090153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2091153Sigor@sysoev.ru     nxt_listen_event_t  *listen;
2092153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2093153Sigor@sysoev.ru 
2094153Sigor@sysoev.ru     job = obj;
209553Sigor@sysoev.ru     skcf = data;
209653Sigor@sysoev.ru 
2097139Sigor@sysoev.ru     engine = task->thread->engine;
2098139Sigor@sysoev.ru 
209953Sigor@sysoev.ru     listen = nxt_router_listen_event(&engine->listen_connections, skcf);
210053Sigor@sysoev.ru 
210153Sigor@sysoev.ru     nxt_fd_event_delete(engine, &listen->socket);
210253Sigor@sysoev.ru 
2103163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2104163Smax.romanov@nginx.com               listen->socket.fd);
2105163Smax.romanov@nginx.com 
210653Sigor@sysoev.ru     listen->timer.handler = nxt_router_listen_socket_close;
210753Sigor@sysoev.ru     listen->timer.work_queue = &engine->fast_work_queue;
210853Sigor@sysoev.ru 
210953Sigor@sysoev.ru     nxt_timer_add(engine, &listen->timer, 0);
2110139Sigor@sysoev.ru 
2111153Sigor@sysoev.ru     job->work.next = NULL;
2112153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2113153Sigor@sysoev.ru 
2114153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
211553Sigor@sysoev.ru }
211653Sigor@sysoev.ru 
211753Sigor@sysoev.ru 
211853Sigor@sysoev.ru static void
2119313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2120313Sigor@sysoev.ru {
2121313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2122313Sigor@sysoev.ru 
2123313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2124313Sigor@sysoev.ru 
2125313Sigor@sysoev.ru     engine = task->thread->engine;
2126313Sigor@sysoev.ru 
2127313Sigor@sysoev.ru     engine->shutdown = 1;
2128313Sigor@sysoev.ru 
2129313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2130313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2131313Sigor@sysoev.ru     }
2132313Sigor@sysoev.ru }
2133313Sigor@sysoev.ru 
2134313Sigor@sysoev.ru 
2135313Sigor@sysoev.ru static void
213653Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
213753Sigor@sysoev.ru {
213853Sigor@sysoev.ru     nxt_timer_t              *timer;
213953Sigor@sysoev.ru     nxt_listen_event_t       *listen;
214053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
214153Sigor@sysoev.ru 
214253Sigor@sysoev.ru     timer = obj;
214353Sigor@sysoev.ru     listen = nxt_timer_data(timer, nxt_listen_event_t, timer);
214453Sigor@sysoev.ru     joint = listen->socket.data;
214553Sigor@sysoev.ru 
2146163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2147163Smax.romanov@nginx.com               listen->socket.fd);
2148163Smax.romanov@nginx.com 
214953Sigor@sysoev.ru     nxt_queue_remove(&listen->link);
2150123Smax.romanov@nginx.com 
2151123Smax.romanov@nginx.com     /* 'task' refers to listen->task and we cannot use after nxt_free() */
2152123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2153123Smax.romanov@nginx.com 
215453Sigor@sysoev.ru     nxt_free(listen);
215553Sigor@sysoev.ru 
215653Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint);
215753Sigor@sysoev.ru }
215853Sigor@sysoev.ru 
215953Sigor@sysoev.ru 
216053Sigor@sysoev.ru static void
216153Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task,
216253Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
216353Sigor@sysoev.ru {
2164118Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
2165115Sigor@sysoev.ru     nxt_router_socket_t    *rtsk;
216653Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
216753Sigor@sysoev.ru 
2168118Sigor@sysoev.ru     skcf = joint->socket_conf;
2169118Sigor@sysoev.ru     rtsk = skcf->socket;
2170118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
217153Sigor@sysoev.ru 
217253Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
217353Sigor@sysoev.ru 
2174163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket release: rtsk->count %D",
2175163Smax.romanov@nginx.com               task->thread->engine, rtsk->count);
2176163Smax.romanov@nginx.com 
2177115Sigor@sysoev.ru     if (--rtsk->count != 0) {
2178115Sigor@sysoev.ru         rtsk = NULL;
217953Sigor@sysoev.ru     }
218053Sigor@sysoev.ru 
218153Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
218253Sigor@sysoev.ru 
2183115Sigor@sysoev.ru     if (rtsk != NULL) {
2184115Sigor@sysoev.ru         nxt_socket_close(task, rtsk->fd);
2185115Sigor@sysoev.ru         nxt_free(rtsk);
2186118Sigor@sysoev.ru         skcf->socket = NULL;
218753Sigor@sysoev.ru     }
218853Sigor@sysoev.ru 
218953Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
219053Sigor@sysoev.ru }
219153Sigor@sysoev.ru 
219253Sigor@sysoev.ru 
219353Sigor@sysoev.ru static void
219453Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
219553Sigor@sysoev.ru {
2196156Sigor@sysoev.ru     nxt_bool_t             exit;
219753Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
219853Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
2199313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
220053Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
220153Sigor@sysoev.ru 
2202163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
220353Sigor@sysoev.ru 
220453Sigor@sysoev.ru     if (--joint->count != 0) {
220553Sigor@sysoev.ru         return;
220653Sigor@sysoev.ru     }
220753Sigor@sysoev.ru 
220853Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
220953Sigor@sysoev.ru 
221053Sigor@sysoev.ru     skcf = joint->socket_conf;
221153Sigor@sysoev.ru     rtcf = skcf->router_conf;
221253Sigor@sysoev.ru     lock = &rtcf->router->lock;
221353Sigor@sysoev.ru 
221453Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
221553Sigor@sysoev.ru 
2216163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2217163Smax.romanov@nginx.com               rtcf, rtcf->count);
2218163Smax.romanov@nginx.com 
221953Sigor@sysoev.ru     if (--skcf->count != 0) {
222053Sigor@sysoev.ru         rtcf = NULL;
222153Sigor@sysoev.ru 
222253Sigor@sysoev.ru     } else {
222353Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
222453Sigor@sysoev.ru 
222553Sigor@sysoev.ru         if (--rtcf->count != 0) {
222653Sigor@sysoev.ru             rtcf = NULL;
222753Sigor@sysoev.ru         }
222853Sigor@sysoev.ru     }
222953Sigor@sysoev.ru 
223053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
223153Sigor@sysoev.ru 
2232141Smax.romanov@nginx.com     /* TODO remove engine->port */
2233141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2234141Smax.romanov@nginx.com 
2235156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
2236313Sigor@sysoev.ru     engine = joint->engine;
2237313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
2238156Sigor@sysoev.ru 
223953Sigor@sysoev.ru     if (rtcf != NULL) {
2240115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2241131Smax.romanov@nginx.com 
2242131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2243131Smax.romanov@nginx.com 
224465Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
224553Sigor@sysoev.ru     }
224653Sigor@sysoev.ru 
2247156Sigor@sysoev.ru     if (exit) {
224853Sigor@sysoev.ru         nxt_thread_exit(task->thread);
224953Sigor@sysoev.ru     }
225053Sigor@sysoev.ru }
225153Sigor@sysoev.ru 
225253Sigor@sysoev.ru 
225353Sigor@sysoev.ru static void
225453Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
225553Sigor@sysoev.ru {
2256141Smax.romanov@nginx.com     nxt_port_t           *port;
225753Sigor@sysoev.ru     nxt_thread_link_t    *link;
225853Sigor@sysoev.ru     nxt_event_engine_t   *engine;
225953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
226053Sigor@sysoev.ru 
226158Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
226253Sigor@sysoev.ru     link = data;
226353Sigor@sysoev.ru 
226453Sigor@sysoev.ru     nxt_thread_wait(handle);
226553Sigor@sysoev.ru 
226653Sigor@sysoev.ru     engine = link->engine;
226753Sigor@sysoev.ru 
226853Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
226953Sigor@sysoev.ru 
2270141Smax.romanov@nginx.com     port = engine->port;
2271141Smax.romanov@nginx.com 
2272141Smax.romanov@nginx.com     // TODO notify all apps
2273141Smax.romanov@nginx.com 
2274343Smax.romanov@nginx.com     port->engine = task->thread->engine;
2275163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
2276343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
2277163Smax.romanov@nginx.com 
2278163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
227963Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
228053Sigor@sysoev.ru 
228153Sigor@sysoev.ru     nxt_event_engine_free(engine);
228253Sigor@sysoev.ru 
228353Sigor@sysoev.ru     nxt_free(link);
228453Sigor@sysoev.ru }
228553Sigor@sysoev.ru 
228653Sigor@sysoev.ru 
2287206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_header_state
228853Sigor@sysoev.ru     nxt_aligned(64) =
228953Sigor@sysoev.ru {
229053Sigor@sysoev.ru     .ready_handler = nxt_router_conn_http_header_parse,
229153Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
229253Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
229353Sigor@sysoev.ru 
229453Sigor@sysoev.ru     .timer_handler = nxt_router_conn_timeout,
229553Sigor@sysoev.ru     .timer_value = nxt_router_conn_timeout_value,
229653Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
229753Sigor@sysoev.ru };
229853Sigor@sysoev.ru 
229953Sigor@sysoev.ru 
2300206Smax.romanov@nginx.com static const nxt_conn_state_t  nxt_router_conn_read_body_state
2301206Smax.romanov@nginx.com     nxt_aligned(64) =
2302206Smax.romanov@nginx.com {
2303206Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_http_body_read,
2304206Smax.romanov@nginx.com     .close_handler = nxt_router_conn_close,
2305206Smax.romanov@nginx.com     .error_handler = nxt_router_conn_error,
2306206Smax.romanov@nginx.com 
2307206Smax.romanov@nginx.com     .timer_handler = nxt_router_conn_timeout,
2308206Smax.romanov@nginx.com     .timer_value = nxt_router_conn_timeout_value,
2309206Smax.romanov@nginx.com     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
2310206Smax.romanov@nginx.com     .timer_autoreset = 1,
2311206Smax.romanov@nginx.com };
2312206Smax.romanov@nginx.com 
2313206Smax.romanov@nginx.com 
231453Sigor@sysoev.ru static void
231553Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data)
231653Sigor@sysoev.ru {
231753Sigor@sysoev.ru     size_t                   size;
231862Sigor@sysoev.ru     nxt_conn_t               *c;
231953Sigor@sysoev.ru     nxt_event_engine_t       *engine;
232053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
232153Sigor@sysoev.ru 
232253Sigor@sysoev.ru     c = obj;
232353Sigor@sysoev.ru     joint = data;
232453Sigor@sysoev.ru 
232553Sigor@sysoev.ru     nxt_debug(task, "router conn init");
232653Sigor@sysoev.ru 
232753Sigor@sysoev.ru     joint->count++;
232853Sigor@sysoev.ru 
232953Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
233053Sigor@sysoev.ru     c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0);
233153Sigor@sysoev.ru 
233253Sigor@sysoev.ru     c->socket.data = NULL;
233353Sigor@sysoev.ru 
233453Sigor@sysoev.ru     engine = task->thread->engine;
233553Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
233653Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
233753Sigor@sysoev.ru 
2338206Smax.romanov@nginx.com     c->read_state = &nxt_router_conn_read_header_state;
233953Sigor@sysoev.ru 
234062Sigor@sysoev.ru     nxt_conn_read(engine, c);
234153Sigor@sysoev.ru }
234253Sigor@sysoev.ru 
234353Sigor@sysoev.ru 
234462Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_write_state
234553Sigor@sysoev.ru     nxt_aligned(64) =
234653Sigor@sysoev.ru {
234788Smax.romanov@nginx.com     .ready_handler = nxt_router_conn_ready,
234853Sigor@sysoev.ru     .close_handler = nxt_router_conn_close,
234953Sigor@sysoev.ru     .error_handler = nxt_router_conn_error,
235053Sigor@sysoev.ru };
235153Sigor@sysoev.ru 
235253Sigor@sysoev.ru 
235353Sigor@sysoev.ru static void
2354318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2355318Smax.romanov@nginx.com     void *data)
235688Smax.romanov@nginx.com {
235788Smax.romanov@nginx.com     size_t               dump_size;
2358194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
235988Smax.romanov@nginx.com     nxt_conn_t           *c;
236088Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
236188Smax.romanov@nginx.com 
236288Smax.romanov@nginx.com     b = msg->buf;
2363318Smax.romanov@nginx.com     rc = data;
236488Smax.romanov@nginx.com 
236588Smax.romanov@nginx.com     c = rc->conn;
236688Smax.romanov@nginx.com 
236788Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
236888Smax.romanov@nginx.com 
236988Smax.romanov@nginx.com     if (dump_size > 300) {
237088Smax.romanov@nginx.com         dump_size = 300;
237188Smax.romanov@nginx.com     }
237288Smax.romanov@nginx.com 
2373119Smax.romanov@nginx.com     nxt_debug(task, "%srouter app data (%z): %*s",
237488Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
237588Smax.romanov@nginx.com               b->mem.pos);
237688Smax.romanov@nginx.com 
237788Smax.romanov@nginx.com     if (msg->size == 0) {
237888Smax.romanov@nginx.com         b = NULL;
237988Smax.romanov@nginx.com     }
238088Smax.romanov@nginx.com 
238188Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
238288Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
238388Smax.romanov@nginx.com 
238488Smax.romanov@nginx.com         last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST);
238588Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
238688Smax.romanov@nginx.com             /* TODO pogorevaTb */
238788Smax.romanov@nginx.com         }
238888Smax.romanov@nginx.com 
238988Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2390167Smax.romanov@nginx.com 
2391343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
239288Smax.romanov@nginx.com     }
239388Smax.romanov@nginx.com 
239488Smax.romanov@nginx.com     if (b == NULL) {
239588Smax.romanov@nginx.com         return;
239688Smax.romanov@nginx.com     }
239788Smax.romanov@nginx.com 
2398206Smax.romanov@nginx.com     if (msg->buf == b) {
2399206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2400206Smax.romanov@nginx.com         msg->buf = NULL;
2401206Smax.romanov@nginx.com     }
2402194Smax.romanov@nginx.com 
240388Smax.romanov@nginx.com     if (c->write == NULL) {
240488Smax.romanov@nginx.com         c->write = b;
240588Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
240688Smax.romanov@nginx.com 
240788Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2408277Sigor@sysoev.ru 
240988Smax.romanov@nginx.com     } else {
241088Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
241188Smax.romanov@nginx.com 
241288Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
241388Smax.romanov@nginx.com     }
241488Smax.romanov@nginx.com }
241588Smax.romanov@nginx.com 
2416277Sigor@sysoev.ru 
2417318Smax.romanov@nginx.com static void
2418318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2419318Smax.romanov@nginx.com     void *data)
2420318Smax.romanov@nginx.com {
2421318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2422318Smax.romanov@nginx.com 
2423318Smax.romanov@nginx.com     rc = data;
2424318Smax.romanov@nginx.com 
2425318Smax.romanov@nginx.com     nxt_router_gen_error(task, rc->conn, 500,
2426318Smax.romanov@nginx.com                          "Application terminated unexpectedly");
2427318Smax.romanov@nginx.com 
2428343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
2429318Smax.romanov@nginx.com }
2430318Smax.romanov@nginx.com 
2431318Smax.romanov@nginx.com 
2432141Smax.romanov@nginx.com nxt_inline const char *
2433141Smax.romanov@nginx.com nxt_router_text_by_code(int code)
2434141Smax.romanov@nginx.com {
2435141Smax.romanov@nginx.com     switch (code) {
2436141Smax.romanov@nginx.com     case 400: return "Bad request";
2437141Smax.romanov@nginx.com     case 404: return "Not found";
2438141Smax.romanov@nginx.com     case 403: return "Forbidden";
2439206Smax.romanov@nginx.com     case 408: return "Request Timeout";
2440206Smax.romanov@nginx.com     case 411: return "Length Required";
2441206Smax.romanov@nginx.com     case 413: return "Request Entity Too Large";
2442141Smax.romanov@nginx.com     case 500:
2443141Smax.romanov@nginx.com     default:  return "Internal server error";
2444141Smax.romanov@nginx.com     }
2445141Smax.romanov@nginx.com }
2446141Smax.romanov@nginx.com 
2447163Smax.romanov@nginx.com 
2448163Smax.romanov@nginx.com static nxt_buf_t *
2449163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code,
2450*345Smax.romanov@nginx.com     const char* str)
245188Smax.romanov@nginx.com {
2452*345Smax.romanov@nginx.com     nxt_buf_t  *b, *last;
2453*345Smax.romanov@nginx.com 
2454*345Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, 16384, 0);
2455141Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2456163Smax.romanov@nginx.com         return NULL;
2457141Smax.romanov@nginx.com     }
2458141Smax.romanov@nginx.com 
2459141Smax.romanov@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end,
2460141Smax.romanov@nginx.com         "HTTP/1.0 %d %s\r\n"
2461141Smax.romanov@nginx.com         "Content-Type: text/plain\r\n"
2462141Smax.romanov@nginx.com         "Connection: close\r\n\r\n",
2463141Smax.romanov@nginx.com         code, nxt_router_text_by_code(code));
2464141Smax.romanov@nginx.com 
2465*345Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str));
2466*345Smax.romanov@nginx.com 
2467*345Smax.romanov@nginx.com     nxt_log_alert(task->log, "error %d: %s", code, str);
2468*345Smax.romanov@nginx.com 
2469*345Smax.romanov@nginx.com     last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST);
2470163Smax.romanov@nginx.com 
2471141Smax.romanov@nginx.com     if (nxt_slow_path(last == NULL)) {
2472*345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2473163Smax.romanov@nginx.com         return NULL;
2474141Smax.romanov@nginx.com     }
2475141Smax.romanov@nginx.com 
2476141Smax.romanov@nginx.com     nxt_buf_chain_add(&b, last);
2477141Smax.romanov@nginx.com 
2478163Smax.romanov@nginx.com     return b;
2479163Smax.romanov@nginx.com }
2480163Smax.romanov@nginx.com 
2481163Smax.romanov@nginx.com 
2482163Smax.romanov@nginx.com 
2483163Smax.romanov@nginx.com static void
2484163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code,
2485*345Smax.romanov@nginx.com     const char* str)
2486163Smax.romanov@nginx.com {
2487318Smax.romanov@nginx.com     nxt_mp_t   *mp;
2488163Smax.romanov@nginx.com     nxt_buf_t  *b;
2489163Smax.romanov@nginx.com 
2490318Smax.romanov@nginx.com     /* TODO: fix when called in the middle of response */
2491318Smax.romanov@nginx.com 
2492*345Smax.romanov@nginx.com     mp = c->mem_pool;
2493*345Smax.romanov@nginx.com 
2494*345Smax.romanov@nginx.com     b = nxt_router_get_error_buf(task, mp, code, str);
2495163Smax.romanov@nginx.com 
2496273Smax.romanov@nginx.com     if (c->socket.fd == -1) {
2497*345Smax.romanov@nginx.com         nxt_mp_free(mp, b->next);
2498*345Smax.romanov@nginx.com         nxt_mp_free(mp, b);
2499273Smax.romanov@nginx.com         return;
2500273Smax.romanov@nginx.com     }
2501273Smax.romanov@nginx.com 
2502141Smax.romanov@nginx.com     if (c->write == NULL) {
2503141Smax.romanov@nginx.com         c->write = b;
2504141Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_write_state;
2505141Smax.romanov@nginx.com 
2506141Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
2507277Sigor@sysoev.ru 
2508141Smax.romanov@nginx.com     } else {
2509141Smax.romanov@nginx.com         nxt_debug(task, "router data attach out bufs to existing chain");
2510141Smax.romanov@nginx.com 
2511141Smax.romanov@nginx.com         nxt_buf_chain_add(&c->write, b);
2512141Smax.romanov@nginx.com     }
2513141Smax.romanov@nginx.com }
2514141Smax.romanov@nginx.com 
2515141Smax.romanov@nginx.com 
2516141Smax.romanov@nginx.com static void
2517343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2518343Smax.romanov@nginx.com     void *data)
2519192Smax.romanov@nginx.com {
2520343Smax.romanov@nginx.com     nxt_app_t   *app;
2521343Smax.romanov@nginx.com     nxt_port_t  *port;
2522343Smax.romanov@nginx.com 
2523343Smax.romanov@nginx.com     app = data;
2524343Smax.romanov@nginx.com     port = msg->new_port;
2525343Smax.romanov@nginx.com 
2526343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2527343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2528343Smax.romanov@nginx.com 
2529343Smax.romanov@nginx.com     port->app = app;
2530343Smax.romanov@nginx.com 
2531343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2532343Smax.romanov@nginx.com 
2533343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2534343Smax.romanov@nginx.com 
2535343Smax.romanov@nginx.com     app->pending_workers--;
2536343Smax.romanov@nginx.com     app->workers++;
2537343Smax.romanov@nginx.com 
2538343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2539343Smax.romanov@nginx.com 
2540343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p new port ready", &app->name, app);
2541343Smax.romanov@nginx.com 
2542343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
2543192Smax.romanov@nginx.com }
2544192Smax.romanov@nginx.com 
2545192Smax.romanov@nginx.com 
2546192Smax.romanov@nginx.com static void
2547343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2548343Smax.romanov@nginx.com     void *data)
2549192Smax.romanov@nginx.com {
2550318Smax.romanov@nginx.com     nxt_app_t           *app;
2551318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2552318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2553343Smax.romanov@nginx.com 
2554343Smax.romanov@nginx.com     app = data;
2555343Smax.romanov@nginx.com 
2556343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2557343Smax.romanov@nginx.com 
2558343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
2559343Smax.romanov@nginx.com 
2560343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2561343Smax.romanov@nginx.com 
2562343Smax.romanov@nginx.com     nxt_assert(app->pending_workers != 0);
2563343Smax.romanov@nginx.com 
2564343Smax.romanov@nginx.com     app->pending_workers--;
2565318Smax.romanov@nginx.com 
2566318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2567318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
2568318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2569343Smax.romanov@nginx.com         lnk->next = NULL;
2570318Smax.romanov@nginx.com 
2571318Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2572318Smax.romanov@nginx.com 
2573343Smax.romanov@nginx.com     } else {
2574343Smax.romanov@nginx.com         ra = NULL;
2575343Smax.romanov@nginx.com     }
2576343Smax.romanov@nginx.com 
2577343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2578343Smax.romanov@nginx.com 
2579343Smax.romanov@nginx.com     if (ra != NULL) {
2580318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
2581318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2582318Smax.romanov@nginx.com 
2583318Smax.romanov@nginx.com         nxt_router_ra_abort(task, ra, ra->work.data);
2584318Smax.romanov@nginx.com     }
2585192Smax.romanov@nginx.com 
2586343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
2587192Smax.romanov@nginx.com }
2588192Smax.romanov@nginx.com 
2589192Smax.romanov@nginx.com 
2590343Smax.romanov@nginx.com void
2591343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
2592141Smax.romanov@nginx.com {
2593343Smax.romanov@nginx.com     int  c;
2594343Smax.romanov@nginx.com 
2595343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
2596343Smax.romanov@nginx.com 
2597343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
2598343Smax.romanov@nginx.com 
2599343Smax.romanov@nginx.com         nxt_assert(app->live == 0);
2600343Smax.romanov@nginx.com         nxt_assert(app->workers == 0);
2601343Smax.romanov@nginx.com         nxt_assert(app->pending_workers == 0);
2602343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->requests) != 0);
2603343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->ports) != 0);
2604343Smax.romanov@nginx.com 
2605163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2606163Smax.romanov@nginx.com         nxt_free(app);
2607163Smax.romanov@nginx.com     }
2608343Smax.romanov@nginx.com }
2609343Smax.romanov@nginx.com 
2610343Smax.romanov@nginx.com 
2611343Smax.romanov@nginx.com nxt_inline nxt_port_t *
2612343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta)
2613343Smax.romanov@nginx.com {
2614343Smax.romanov@nginx.com     nxt_port_t        *port;
2615343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2616343Smax.romanov@nginx.com 
2617343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
2618343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
2619343Smax.romanov@nginx.com 
2620343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2621343Smax.romanov@nginx.com 
2622343Smax.romanov@nginx.com     port->app_requests++;
2623343Smax.romanov@nginx.com 
2624343Smax.romanov@nginx.com     if (app->live &&
2625343Smax.romanov@nginx.com          (app->max_pending_responses == 0 ||
2626343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2627343Smax.romanov@nginx.com                 app->max_pending_responses) )
2628277Sigor@sysoev.ru     {
2629343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
2630343Smax.romanov@nginx.com 
2631343Smax.romanov@nginx.com     } else {
2632343Smax.romanov@nginx.com         lnk->next = NULL;
2633343Smax.romanov@nginx.com 
2634343Smax.romanov@nginx.com         (*use_delta)--;
2635167Smax.romanov@nginx.com     }
2636167Smax.romanov@nginx.com 
2637343Smax.romanov@nginx.com     return port;
2638163Smax.romanov@nginx.com }
2639163Smax.romanov@nginx.com 
2640163Smax.romanov@nginx.com 
2641141Smax.romanov@nginx.com static nxt_port_t *
2642343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app)
2643141Smax.romanov@nginx.com {
2644343Smax.romanov@nginx.com     nxt_port_t  *port;
2645141Smax.romanov@nginx.com 
2646141Smax.romanov@nginx.com     port = NULL;
2647141Smax.romanov@nginx.com 
2648141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2649141Smax.romanov@nginx.com 
2650343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
2651343Smax.romanov@nginx.com 
2652343Smax.romanov@nginx.com         if (port->app_requests > port->app_responses) {
2653343Smax.romanov@nginx.com             port = NULL;
2654343Smax.romanov@nginx.com 
2655343Smax.romanov@nginx.com             continue;
2656343Smax.romanov@nginx.com         }
2657343Smax.romanov@nginx.com 
2658343Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2659343Smax.romanov@nginx.com         port->app_link.next = NULL;
2660343Smax.romanov@nginx.com 
2661343Smax.romanov@nginx.com         break;
2662343Smax.romanov@nginx.com 
2663343Smax.romanov@nginx.com     } nxt_queue_loop;
2664141Smax.romanov@nginx.com 
2665141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2666141Smax.romanov@nginx.com 
2667141Smax.romanov@nginx.com     return port;
2668141Smax.romanov@nginx.com }
2669141Smax.romanov@nginx.com 
2670141Smax.romanov@nginx.com 
2671141Smax.romanov@nginx.com static void
2672343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
2673141Smax.romanov@nginx.com {
2674343Smax.romanov@nginx.com     nxt_app_t           *app;
2675343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2676343Smax.romanov@nginx.com 
2677343Smax.romanov@nginx.com     app = obj;
2678343Smax.romanov@nginx.com     ra = data;
2679141Smax.romanov@nginx.com 
2680141Smax.romanov@nginx.com     nxt_assert(app != NULL);
2681343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
2682343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
2683343Smax.romanov@nginx.com 
2684343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
2685343Smax.romanov@nginx.com               &app->name, app, ra->stream);
2686343Smax.romanov@nginx.com 
2687343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
2688343Smax.romanov@nginx.com }
2689343Smax.romanov@nginx.com 
2690343Smax.romanov@nginx.com 
2691343Smax.romanov@nginx.com static void
2692343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
2693343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
2694343Smax.romanov@nginx.com {
2695343Smax.romanov@nginx.com     int                 use_delta, ra_use_delta;
2696343Smax.romanov@nginx.com     nxt_app_t           *app;
2697343Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2698343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2699343Smax.romanov@nginx.com 
2700343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2701343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
2702343Smax.romanov@nginx.com 
2703343Smax.romanov@nginx.com     app = port->app;
2704343Smax.romanov@nginx.com 
2705343Smax.romanov@nginx.com     use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1;
2706343Smax.romanov@nginx.com 
2707343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2708343Smax.romanov@nginx.com 
2709343Smax.romanov@nginx.com     port->app_requests -= request_failed;
2710343Smax.romanov@nginx.com     port->app_responses += got_response;
2711343Smax.romanov@nginx.com 
2712343Smax.romanov@nginx.com     if (app->live != 0 &&
2713343Smax.romanov@nginx.com         port->pair[1] != -1 &&
2714343Smax.romanov@nginx.com         port->app_link.next == NULL &&
2715343Smax.romanov@nginx.com         (app->max_pending_responses == 0 ||
2716343Smax.romanov@nginx.com             (port->app_requests - port->app_responses) <
2717343Smax.romanov@nginx.com                 app->max_pending_responses) )
2718343Smax.romanov@nginx.com     {
2719343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, &port->app_link);
2720343Smax.romanov@nginx.com         use_delta++;
2721141Smax.romanov@nginx.com     }
2722141Smax.romanov@nginx.com 
2723343Smax.romanov@nginx.com     if (app->live != 0 &&
2724343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->ports) &&
2725343Smax.romanov@nginx.com         !nxt_queue_is_empty(&app->requests))
2726343Smax.romanov@nginx.com     {
2727141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
2728141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2729343Smax.romanov@nginx.com         lnk->next = NULL;
2730141Smax.romanov@nginx.com 
2731167Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link);
2732167Smax.romanov@nginx.com 
2733343Smax.romanov@nginx.com         ra_use_delta = 1;
2734343Smax.romanov@nginx.com         ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta);
2735343Smax.romanov@nginx.com 
2736343Smax.romanov@nginx.com     } else {
2737343Smax.romanov@nginx.com         ra = NULL;
2738343Smax.romanov@nginx.com         ra_use_delta = 0;
2739141Smax.romanov@nginx.com     }
2740141Smax.romanov@nginx.com 
2741343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2742343Smax.romanov@nginx.com 
2743343Smax.romanov@nginx.com     if (ra != NULL) {
2744343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2745343Smax.romanov@nginx.com                            nxt_router_app_process_request,
2746343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
2747343Smax.romanov@nginx.com 
2748343Smax.romanov@nginx.com         goto adjust_use;
2749343Smax.romanov@nginx.com     }
2750343Smax.romanov@nginx.com 
2751343Smax.romanov@nginx.com     /* ? */
2752163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
2753343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
2754343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
2755343Smax.romanov@nginx.com 
2756343Smax.romanov@nginx.com         goto adjust_use;
2757163Smax.romanov@nginx.com     }
2758163Smax.romanov@nginx.com 
2759343Smax.romanov@nginx.com     if (app->live == 0) {
2760167Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p is not alive, send QUIT to port",
2761167Smax.romanov@nginx.com                   &app->name, app);
2762163Smax.romanov@nginx.com 
2763163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
2764163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
2765163Smax.romanov@nginx.com 
2766343Smax.romanov@nginx.com         goto adjust_use;
2767163Smax.romanov@nginx.com     }
2768163Smax.romanov@nginx.com 
2769167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
2770167Smax.romanov@nginx.com               &app->name, app);
2771141Smax.romanov@nginx.com 
2772343Smax.romanov@nginx.com adjust_use:
2773343Smax.romanov@nginx.com 
2774343Smax.romanov@nginx.com     if (use_delta != 0) {
2775343Smax.romanov@nginx.com         nxt_port_use(task, port, use_delta);
2776343Smax.romanov@nginx.com     }
2777343Smax.romanov@nginx.com 
2778343Smax.romanov@nginx.com     if (ra_use_delta != 0) {
2779343Smax.romanov@nginx.com         nxt_port_use(task, ra->app_port, ra_use_delta);
2780343Smax.romanov@nginx.com     }
2781141Smax.romanov@nginx.com }
2782141Smax.romanov@nginx.com 
2783141Smax.romanov@nginx.com 
2784343Smax.romanov@nginx.com void
2785343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
2786141Smax.romanov@nginx.com {
2787163Smax.romanov@nginx.com     nxt_app_t   *app;
2788343Smax.romanov@nginx.com     nxt_bool_t  unchain, start_worker;
2789141Smax.romanov@nginx.com 
2790141Smax.romanov@nginx.com     app = port->app;
2791343Smax.romanov@nginx.com 
2792343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2793141Smax.romanov@nginx.com 
2794141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2795141Smax.romanov@nginx.com 
2796343Smax.romanov@nginx.com     unchain = port->app_link.next != NULL;
2797343Smax.romanov@nginx.com 
2798343Smax.romanov@nginx.com     if (unchain) {
2799163Smax.romanov@nginx.com         nxt_queue_remove(&port->app_link);
2800163Smax.romanov@nginx.com         port->app_link.next = NULL;
2801343Smax.romanov@nginx.com     }
2802343Smax.romanov@nginx.com 
2803343Smax.romanov@nginx.com     app->workers--;
2804343Smax.romanov@nginx.com 
2805343Smax.romanov@nginx.com     start_worker = app->live != 0 &&
2806343Smax.romanov@nginx.com                    nxt_queue_is_empty(&app->requests) == 0 &&
2807343Smax.romanov@nginx.com                    app->workers + app->pending_workers < app->max_workers;
2808343Smax.romanov@nginx.com 
2809343Smax.romanov@nginx.com     if (start_worker) {
2810343Smax.romanov@nginx.com         app->pending_workers++;
2811163Smax.romanov@nginx.com     }
2812141Smax.romanov@nginx.com 
2813141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2814163Smax.romanov@nginx.com 
2815343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port);
2816343Smax.romanov@nginx.com 
2817343Smax.romanov@nginx.com     if (unchain) {
2818343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2819163Smax.romanov@nginx.com     }
2820163Smax.romanov@nginx.com 
2821343Smax.romanov@nginx.com     if (start_worker) {
2822343Smax.romanov@nginx.com         nxt_router_start_worker(task, app);
2823343Smax.romanov@nginx.com     }
2824141Smax.romanov@nginx.com }
2825141Smax.romanov@nginx.com 
2826141Smax.romanov@nginx.com 
2827167Smax.romanov@nginx.com static nxt_int_t
2828167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra)
2829141Smax.romanov@nginx.com {
2830343Smax.romanov@nginx.com     int                      use_delta;
2831343Smax.romanov@nginx.com     nxt_int_t                res;
2832141Smax.romanov@nginx.com     nxt_app_t                *app;
2833343Smax.romanov@nginx.com     nxt_bool_t               can_start_worker;
2834141Smax.romanov@nginx.com     nxt_conn_t               *c;
2835167Smax.romanov@nginx.com     nxt_port_t               *port;
2836318Smax.romanov@nginx.com     nxt_event_engine_t       *engine;
2837141Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
2838141Smax.romanov@nginx.com 
2839141Smax.romanov@nginx.com     port = NULL;
2840343Smax.romanov@nginx.com     use_delta = 1;
2841167Smax.romanov@nginx.com     c = ra->rc->conn;
2842141Smax.romanov@nginx.com 
2843141Smax.romanov@nginx.com     joint = c->listen->socket.data;
2844141Smax.romanov@nginx.com     app = joint->socket_conf->application;
2845141Smax.romanov@nginx.com 
2846141Smax.romanov@nginx.com     if (app == NULL) {
2847167Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500,
2848141Smax.romanov@nginx.com                              "Application is NULL in socket_conf");
2849141Smax.romanov@nginx.com         return NXT_ERROR;
2850141Smax.romanov@nginx.com     }
2851141Smax.romanov@nginx.com 
2852343Smax.romanov@nginx.com     ra->rc->app = app;
2853343Smax.romanov@nginx.com 
2854343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
2855343Smax.romanov@nginx.com 
2856318Smax.romanov@nginx.com     engine = task->thread->engine;
2857318Smax.romanov@nginx.com 
2858318Smax.romanov@nginx.com     nxt_timer_disable(engine, &c->read_timer);
2859318Smax.romanov@nginx.com 
2860318Smax.romanov@nginx.com     if (app->timeout != 0) {
2861318Smax.romanov@nginx.com         c->read_timer.handler = nxt_router_app_timeout;
2862318Smax.romanov@nginx.com         nxt_timer_add(engine, &c->read_timer, app->timeout);
2863318Smax.romanov@nginx.com     }
2864318Smax.romanov@nginx.com 
2865343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2866343Smax.romanov@nginx.com 
2867343Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)) {
2868343Smax.romanov@nginx.com         port = nxt_router_app_get_port_unsafe(app, &use_delta);
2869343Smax.romanov@nginx.com 
2870343Smax.romanov@nginx.com         can_start_worker = 0;
2871343Smax.romanov@nginx.com 
2872343Smax.romanov@nginx.com     } else {
2873343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->requests, &ra->link);
2874343Smax.romanov@nginx.com 
2875343Smax.romanov@nginx.com         can_start_worker = (app->workers + app->pending_workers) <
2876343Smax.romanov@nginx.com                               app->max_workers;
2877343Smax.romanov@nginx.com         if (can_start_worker) {
2878343Smax.romanov@nginx.com             app->pending_workers++;
2879343Smax.romanov@nginx.com         }
2880343Smax.romanov@nginx.com 
2881343Smax.romanov@nginx.com         port = NULL;
2882343Smax.romanov@nginx.com     }
2883343Smax.romanov@nginx.com 
2884343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2885141Smax.romanov@nginx.com 
2886141Smax.romanov@nginx.com     if (port != NULL) {
2887343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
2888163Smax.romanov@nginx.com 
2889167Smax.romanov@nginx.com         ra->app_port = port;
2890343Smax.romanov@nginx.com 
2891343Smax.romanov@nginx.com         if (use_delta != 0) {
2892343Smax.romanov@nginx.com             nxt_port_use(task, port, use_delta);
2893343Smax.romanov@nginx.com         }
2894141Smax.romanov@nginx.com         return NXT_OK;
2895141Smax.romanov@nginx.com     }
2896141Smax.romanov@nginx.com 
2897343Smax.romanov@nginx.com     if (!can_start_worker) {
2898343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending workers",
2899343Smax.romanov@nginx.com                   &app->name, app);
2900343Smax.romanov@nginx.com 
2901343Smax.romanov@nginx.com         return NXT_AGAIN;
2902343Smax.romanov@nginx.com     }
2903343Smax.romanov@nginx.com 
2904343Smax.romanov@nginx.com     res = nxt_router_start_worker(task, app);
2905343Smax.romanov@nginx.com 
2906343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
2907343Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to start worker");
2908343Smax.romanov@nginx.com 
2909141Smax.romanov@nginx.com         return NXT_ERROR;
2910141Smax.romanov@nginx.com     }
2911141Smax.romanov@nginx.com 
2912141Smax.romanov@nginx.com     return NXT_AGAIN;
291388Smax.romanov@nginx.com }
291488Smax.romanov@nginx.com 
291588Smax.romanov@nginx.com 
291688Smax.romanov@nginx.com static void
291753Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data)
291853Sigor@sysoev.ru {
2919206Smax.romanov@nginx.com     size_t                    size;
292053Sigor@sysoev.ru     nxt_int_t                 ret;
2921206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
292262Sigor@sysoev.ru     nxt_conn_t                *c;
2923268Sigor@sysoev.ru     nxt_sockaddr_t            *local;
292488Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
2925206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
292653Sigor@sysoev.ru     nxt_socket_conf_joint_t   *joint;
292788Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
292853Sigor@sysoev.ru 
292953Sigor@sysoev.ru     c = obj;
293088Smax.romanov@nginx.com     ap = data;
2931206Smax.romanov@nginx.com     buf = c->read;
2932206Smax.romanov@nginx.com     joint = c->listen->socket.data;
293353Sigor@sysoev.ru 
293453Sigor@sysoev.ru     nxt_debug(task, "router conn http header parse");
293553Sigor@sysoev.ru 
293688Smax.romanov@nginx.com     if (ap == NULL) {
2937319Smax.romanov@nginx.com         ap = nxt_app_http_req_init(task);
293888Smax.romanov@nginx.com         if (nxt_slow_path(ap == NULL)) {
2939319Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 500,
2940319Smax.romanov@nginx.com                                  "Failed to allocate parse context");
294161Sigor@sysoev.ru             return;
294261Sigor@sysoev.ru         }
294388Smax.romanov@nginx.com 
294488Smax.romanov@nginx.com         c->socket.data = ap;
2945113Smax.romanov@nginx.com 
2946113Smax.romanov@nginx.com         ap->r.remote.start = nxt_sockaddr_address(c->remote);
2947113Smax.romanov@nginx.com         ap->r.remote.length = c->remote->address_length;
2948206Smax.romanov@nginx.com 
2949268Sigor@sysoev.ru         local = joint->socket_conf->sockaddr;
2950268Sigor@sysoev.ru         ap->r.local.start = nxt_sockaddr_address(local);
2951268Sigor@sysoev.ru         ap->r.local.length = local->address_length;
2952268Sigor@sysoev.ru 
2953206Smax.romanov@nginx.com         ap->r.header.buf = buf;
295453Sigor@sysoev.ru     }
295553Sigor@sysoev.ru 
295688Smax.romanov@nginx.com     h = &ap->r.header;
2957206Smax.romanov@nginx.com     b = &ap->r.body;
2958206Smax.romanov@nginx.com 
2959206Smax.romanov@nginx.com     ret = nxt_app_http_req_header_parse(task, ap, buf);
2960206Smax.romanov@nginx.com 
2961206Smax.romanov@nginx.com     nxt_debug(task, "http parse request header: %d", ret);
296253Sigor@sysoev.ru 
296353Sigor@sysoev.ru     switch (nxt_expect(NXT_DONE, ret)) {
296453Sigor@sysoev.ru 
296553Sigor@sysoev.ru     case NXT_DONE:
296688Smax.romanov@nginx.com         nxt_debug(task, "router request header parsing complete, "
296788Smax.romanov@nginx.com                   "content length: %O, preread: %uz",
2968206Smax.romanov@nginx.com                   h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem));
2969206Smax.romanov@nginx.com 
2970206Smax.romanov@nginx.com         if (b->done) {
2971206Smax.romanov@nginx.com             nxt_router_process_http_request(task, c, ap);
2972206Smax.romanov@nginx.com 
2973206Smax.romanov@nginx.com             return;
2974206Smax.romanov@nginx.com         }
2975206Smax.romanov@nginx.com 
2976277Sigor@sysoev.ru         if (joint->socket_conf->max_body_size > 0
2977277Sigor@sysoev.ru             && (size_t) h->parsed_content_length
2978277Sigor@sysoev.ru                > joint->socket_conf->max_body_size)
2979277Sigor@sysoev.ru         {
2980206Smax.romanov@nginx.com             nxt_router_gen_error(task, c, 413, "Content-Length too big");
2981206Smax.romanov@nginx.com             return;
2982206Smax.romanov@nginx.com         }
2983206Smax.romanov@nginx.com 
2984206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
2985206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
2986206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length);
2987206Smax.romanov@nginx.com 
2988206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2989206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
2990206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
2991206Smax.romanov@nginx.com                                      "buffer for request body");
2992206Smax.romanov@nginx.com                 return;
2993206Smax.romanov@nginx.com             }
2994206Smax.romanov@nginx.com 
2995206Smax.romanov@nginx.com             c->read = buf->next;
2996206Smax.romanov@nginx.com 
2997206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
2998206Smax.romanov@nginx.com         }
2999206Smax.romanov@nginx.com 
3000206Smax.romanov@nginx.com         if (b->buf == NULL) {
3001206Smax.romanov@nginx.com             b->buf = c->read;
3002206Smax.romanov@nginx.com         }
3003206Smax.romanov@nginx.com 
3004206Smax.romanov@nginx.com         c->read_state = &nxt_router_conn_read_body_state;
3005206Smax.romanov@nginx.com         break;
3006206Smax.romanov@nginx.com 
3007206Smax.romanov@nginx.com     case NXT_ERROR:
3008206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 400, "Request header parse error");
3009206Smax.romanov@nginx.com         return;
3010206Smax.romanov@nginx.com 
3011206Smax.romanov@nginx.com     default:  /* NXT_AGAIN */
3012206Smax.romanov@nginx.com 
3013206Smax.romanov@nginx.com         if (c->read->mem.free == c->read->mem.end) {
3014206Smax.romanov@nginx.com             size = joint->socket_conf->large_header_buffer_size;
3015206Smax.romanov@nginx.com 
3016277Sigor@sysoev.ru             if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem)
3017277Sigor@sysoev.ru                 || ap->r.header.bufs
3018277Sigor@sysoev.ru                    >= joint->socket_conf->large_header_buffers)
3019277Sigor@sysoev.ru             {
3020206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 413,
3021206Smax.romanov@nginx.com                                      "Too long request headers");
3022206Smax.romanov@nginx.com                 return;
3023206Smax.romanov@nginx.com             }
3024206Smax.romanov@nginx.com 
3025206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
3026206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
3027206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500,
3028206Smax.romanov@nginx.com                                      "Failed to allocate large header "
3029206Smax.romanov@nginx.com                                      "buffer");
3030206Smax.romanov@nginx.com                 return;
3031206Smax.romanov@nginx.com             }
3032206Smax.romanov@nginx.com 
3033206Smax.romanov@nginx.com             ap->r.header.bufs++;
3034206Smax.romanov@nginx.com 
3035206Smax.romanov@nginx.com             size = c->read->mem.free - c->read->mem.pos;
3036206Smax.romanov@nginx.com 
3037206Smax.romanov@nginx.com             c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size);
3038206Smax.romanov@nginx.com         }
3039206Smax.romanov@nginx.com 
3040206Smax.romanov@nginx.com     }
3041206Smax.romanov@nginx.com 
3042206Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
3043206Smax.romanov@nginx.com }
3044206Smax.romanov@nginx.com 
3045206Smax.romanov@nginx.com 
3046206Smax.romanov@nginx.com static void
3047206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data)
3048206Smax.romanov@nginx.com {
3049206Smax.romanov@nginx.com     size_t                    size;
3050206Smax.romanov@nginx.com     nxt_int_t                 ret;
3051206Smax.romanov@nginx.com     nxt_buf_t                 *buf;
3052206Smax.romanov@nginx.com     nxt_conn_t                *c;
3053206Smax.romanov@nginx.com     nxt_app_parse_ctx_t       *ap;
3054206Smax.romanov@nginx.com     nxt_app_request_body_t    *b;
3055206Smax.romanov@nginx.com     nxt_socket_conf_joint_t   *joint;
3056206Smax.romanov@nginx.com     nxt_app_request_header_t  *h;
3057206Smax.romanov@nginx.com 
3058206Smax.romanov@nginx.com     c = obj;
3059206Smax.romanov@nginx.com     ap = data;
3060206Smax.romanov@nginx.com     buf = c->read;
3061206Smax.romanov@nginx.com 
3062206Smax.romanov@nginx.com     nxt_debug(task, "router conn http body read");
3063206Smax.romanov@nginx.com 
3064206Smax.romanov@nginx.com     nxt_assert(ap != NULL);
3065206Smax.romanov@nginx.com 
3066206Smax.romanov@nginx.com     b = &ap->r.body;
3067206Smax.romanov@nginx.com     h = &ap->r.header;
3068206Smax.romanov@nginx.com 
3069206Smax.romanov@nginx.com     ret = nxt_app_http_req_body_read(task, ap, buf);
3070206Smax.romanov@nginx.com 
3071206Smax.romanov@nginx.com     nxt_debug(task, "http read request body: %d", ret);
3072206Smax.romanov@nginx.com 
3073206Smax.romanov@nginx.com     switch (nxt_expect(NXT_DONE, ret)) {
3074206Smax.romanov@nginx.com 
3075206Smax.romanov@nginx.com     case NXT_DONE:
307688Smax.romanov@nginx.com         nxt_router_process_http_request(task, c, ap);
307788Smax.romanov@nginx.com         return;
307853Sigor@sysoev.ru 
307953Sigor@sysoev.ru     case NXT_ERROR:
3080206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Read body error");
308153Sigor@sysoev.ru         return;
308253Sigor@sysoev.ru 
308353Sigor@sysoev.ru     default:  /* NXT_AGAIN */
308453Sigor@sysoev.ru 
3085206Smax.romanov@nginx.com         if (nxt_buf_mem_free_size(&buf->mem) == 0) {
3086206Smax.romanov@nginx.com             joint = c->listen->socket.data;
3087206Smax.romanov@nginx.com 
3088206Smax.romanov@nginx.com             b->preread_size += nxt_buf_mem_used_size(&buf->mem);
3089206Smax.romanov@nginx.com 
3090206Smax.romanov@nginx.com             size = nxt_min(joint->socket_conf->body_buffer_size,
3091206Smax.romanov@nginx.com                            (size_t) h->parsed_content_length - b->preread_size);
3092206Smax.romanov@nginx.com 
3093206Smax.romanov@nginx.com             buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0);
3094206Smax.romanov@nginx.com             if (nxt_slow_path(buf->next == NULL)) {
3095206Smax.romanov@nginx.com                 nxt_router_gen_error(task, c, 500, "Failed to allocate "
3096206Smax.romanov@nginx.com                                      "buffer for request body");
3097206Smax.romanov@nginx.com                 return;
309888Smax.romanov@nginx.com             }
3099206Smax.romanov@nginx.com 
3100206Smax.romanov@nginx.com             c->read = buf->next;
310188Smax.romanov@nginx.com         }
310288Smax.romanov@nginx.com 
3103206Smax.romanov@nginx.com         nxt_debug(task, "router request body read again, rest: %uz",
3104206Smax.romanov@nginx.com                   h->parsed_content_length - b->preread_size);
310588Smax.romanov@nginx.com     }
310688Smax.romanov@nginx.com 
310788Smax.romanov@nginx.com     nxt_conn_read(task->thread->engine, c);
310888Smax.romanov@nginx.com }
310988Smax.romanov@nginx.com 
311088Smax.romanov@nginx.com 
311188Smax.romanov@nginx.com static void
311288Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c,
311388Smax.romanov@nginx.com     nxt_app_parse_ctx_t *ap)
311488Smax.romanov@nginx.com {
3115122Smax.romanov@nginx.com     nxt_int_t            res;
3116167Smax.romanov@nginx.com     nxt_port_t           *port;
311788Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
3118167Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
311988Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
312088Smax.romanov@nginx.com 
312188Smax.romanov@nginx.com     engine = task->thread->engine;
312288Smax.romanov@nginx.com 
3123318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
3124318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
3125318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
3126318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
3127122Smax.romanov@nginx.com 
312888Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
3129141Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Failed to allocate "
3130141Smax.romanov@nginx.com                              "req->conn link");
3131141Smax.romanov@nginx.com 
3132141Smax.romanov@nginx.com         return;
313388Smax.romanov@nginx.com     }
313488Smax.romanov@nginx.com 
3135318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
3136318Smax.romanov@nginx.com     rc->conn = c;
3137318Smax.romanov@nginx.com 
3138318Smax.romanov@nginx.com     nxt_queue_insert_tail(&c->requests, &rc->link);
3139318Smax.romanov@nginx.com 
3140318Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD linked to conn %p at engine %p",
3141318Smax.romanov@nginx.com               rc->stream, c, engine);
314253Sigor@sysoev.ru 
3143167Smax.romanov@nginx.com     ra = nxt_router_ra_create(task, rc);
3144167Smax.romanov@nginx.com 
3145167Smax.romanov@nginx.com     ra->ap = ap;
3146167Smax.romanov@nginx.com 
3147167Smax.romanov@nginx.com     res = nxt_router_app_port(task, ra);
3148141Smax.romanov@nginx.com 
3149141Smax.romanov@nginx.com     if (res != NXT_OK) {
3150141Smax.romanov@nginx.com         return;
3151141Smax.romanov@nginx.com     }
3152141Smax.romanov@nginx.com 
3153167Smax.romanov@nginx.com     port = ra->app_port;
3154141Smax.romanov@nginx.com 
3155141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
3156318Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 500, "Application port not found");
3157141Smax.romanov@nginx.com         return;
3158141Smax.romanov@nginx.com     }
3159141Smax.romanov@nginx.com 
3160318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
3161318Smax.romanov@nginx.com 
3162343Smax.romanov@nginx.com     nxt_router_process_http_request_mp(task, ra);
3163167Smax.romanov@nginx.com }
3164167Smax.romanov@nginx.com 
3165167Smax.romanov@nginx.com 
3166167Smax.romanov@nginx.com static void
3167343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra)
3168167Smax.romanov@nginx.com {
3169343Smax.romanov@nginx.com     uint32_t             request_failed;
3170167Smax.romanov@nginx.com     nxt_int_t            res;
3171343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
3172167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
3173167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
3174167Smax.romanov@nginx.com 
3175343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3176343Smax.romanov@nginx.com 
3177343Smax.romanov@nginx.com     port = ra->app_port;
3178167Smax.romanov@nginx.com     reply_port = ra->reply_port;
3179167Smax.romanov@nginx.com     ap = ra->ap;
3180141Smax.romanov@nginx.com 
3181343Smax.romanov@nginx.com     request_failed = 1;
3182343Smax.romanov@nginx.com 
3183141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
3184141Smax.romanov@nginx.com                                              reply_port->id);
3185141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
3186141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
3187122Smax.romanov@nginx.com 
3188122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
3189*345Smax.romanov@nginx.com             nxt_router_ra_error(task, ra, 500,
3190*345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
3191*345Smax.romanov@nginx.com             ra = NULL;
3192343Smax.romanov@nginx.com             goto release_port;
3193122Smax.romanov@nginx.com         }
3194122Smax.romanov@nginx.com 
3195141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
319688Smax.romanov@nginx.com     }
319788Smax.romanov@nginx.com 
319888Smax.romanov@nginx.com     wmsg.port = port;
319988Smax.romanov@nginx.com     wmsg.write = NULL;
320088Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
3201318Smax.romanov@nginx.com     wmsg.stream = ra->stream;
3202167Smax.romanov@nginx.com 
3203216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
3204122Smax.romanov@nginx.com 
3205122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3206*345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3207*345Smax.romanov@nginx.com                             "Failed to prepare message for application");
3208*345Smax.romanov@nginx.com         ra = NULL;
3209343Smax.romanov@nginx.com         goto release_port;
3210122Smax.romanov@nginx.com     }
321188Smax.romanov@nginx.com 
321288Smax.romanov@nginx.com     nxt_debug(task, "about to send %d bytes buffer to worker port %d",
321388Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
321488Smax.romanov@nginx.com                     wmsg.port->socket.fd);
321588Smax.romanov@nginx.com 
3216343Smax.romanov@nginx.com     request_failed = 0;
3217343Smax.romanov@nginx.com 
3218122Smax.romanov@nginx.com     res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA,
3219318Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, wmsg.write);
3220122Smax.romanov@nginx.com 
3221122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3222*345Smax.romanov@nginx.com         nxt_router_ra_error(task, ra, 500,
3223*345Smax.romanov@nginx.com                             "Failed to send message to application");
3224*345Smax.romanov@nginx.com         ra = NULL;
3225343Smax.romanov@nginx.com         goto release_port;
3226122Smax.romanov@nginx.com     }
3227343Smax.romanov@nginx.com 
3228343Smax.romanov@nginx.com release_port:
3229343Smax.romanov@nginx.com 
3230*345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
3231*345Smax.romanov@nginx.com 
3232*345Smax.romanov@nginx.com     if (ra != NULL) {
3233*345Smax.romanov@nginx.com         if (request_failed != 0) {
3234*345Smax.romanov@nginx.com             ra->app_port = 0;
3235*345Smax.romanov@nginx.com         }
3236*345Smax.romanov@nginx.com 
3237*345Smax.romanov@nginx.com         nxt_router_ra_release(task, ra, ra->work.data);
3238343Smax.romanov@nginx.com     }
323953Sigor@sysoev.ru }
324053Sigor@sysoev.ru 
324153Sigor@sysoev.ru 
3242216Sigor@sysoev.ru static nxt_int_t
3243216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3244216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3245216Sigor@sysoev.ru {
3246216Sigor@sysoev.ru     nxt_int_t                 rc;
3247216Sigor@sysoev.ru     nxt_buf_t                 *b;
3248216Sigor@sysoev.ru     nxt_http_field_t          *field;
3249216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3250216Sigor@sysoev.ru 
3251216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3252216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3253216Sigor@sysoev.ru 
3254216Sigor@sysoev.ru     h = &r->header;
3255216Sigor@sysoev.ru 
3256216Sigor@sysoev.ru #define RC(S)                                                                 \
3257216Sigor@sysoev.ru     do {                                                                      \
3258216Sigor@sysoev.ru         rc = (S);                                                             \
3259216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3260216Sigor@sysoev.ru             goto fail;                                                        \
3261216Sigor@sysoev.ru         }                                                                     \
3262216Sigor@sysoev.ru     } while(0)
3263216Sigor@sysoev.ru 
3264216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3265216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3266216Sigor@sysoev.ru 
3267216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3268216Sigor@sysoev.ru 
3269216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3270216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3271277Sigor@sysoev.ru 
3272216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3273216Sigor@sysoev.ru         NXT_WRITE(&eof);
3274277Sigor@sysoev.ru 
3275216Sigor@sysoev.ru     } else {
3276216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3277216Sigor@sysoev.ru     }
3278216Sigor@sysoev.ru 
3279216Sigor@sysoev.ru     if (h->query.start != NULL) {
3280216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3281216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3282216Sigor@sysoev.ru     } else {
3283216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3284216Sigor@sysoev.ru     }
3285216Sigor@sysoev.ru 
3286216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3287216Sigor@sysoev.ru 
3288216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3289268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3290216Sigor@sysoev.ru 
3291216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3292216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3293216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3294216Sigor@sysoev.ru 
3295216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3296216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3297216Sigor@sysoev.ru                                              &prefix, &field->name));
3298216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3299216Sigor@sysoev.ru 
3300216Sigor@sysoev.ru     } nxt_list_loop;
3301216Sigor@sysoev.ru 
3302216Sigor@sysoev.ru     /* end-of-headers mark */
3303216Sigor@sysoev.ru     NXT_WRITE(&eof);
3304216Sigor@sysoev.ru 
3305216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3306216Sigor@sysoev.ru 
3307216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3308216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3309216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3310216Sigor@sysoev.ru     }
3311216Sigor@sysoev.ru 
3312216Sigor@sysoev.ru #undef NXT_WRITE
3313216Sigor@sysoev.ru #undef RC
3314216Sigor@sysoev.ru 
3315216Sigor@sysoev.ru     return NXT_OK;
3316216Sigor@sysoev.ru 
3317216Sigor@sysoev.ru fail:
3318216Sigor@sysoev.ru 
3319216Sigor@sysoev.ru     return NXT_ERROR;
3320216Sigor@sysoev.ru }
3321216Sigor@sysoev.ru 
3322216Sigor@sysoev.ru 
3323216Sigor@sysoev.ru static nxt_int_t
3324216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3325216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3326216Sigor@sysoev.ru {
3327216Sigor@sysoev.ru     nxt_int_t                 rc;
3328216Sigor@sysoev.ru     nxt_buf_t                 *b;
3329305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
3330216Sigor@sysoev.ru     nxt_http_field_t          *field;
3331216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3332216Sigor@sysoev.ru 
3333216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3334216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3335216Sigor@sysoev.ru 
3336216Sigor@sysoev.ru     h = &r->header;
3337216Sigor@sysoev.ru 
3338216Sigor@sysoev.ru #define RC(S)                                                                 \
3339216Sigor@sysoev.ru     do {                                                                      \
3340216Sigor@sysoev.ru         rc = (S);                                                             \
3341216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3342216Sigor@sysoev.ru             goto fail;                                                        \
3343216Sigor@sysoev.ru         }                                                                     \
3344216Sigor@sysoev.ru     } while(0)
3345216Sigor@sysoev.ru 
3346216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3347216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3348216Sigor@sysoev.ru 
3349216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3350216Sigor@sysoev.ru 
3351216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3352216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3353277Sigor@sysoev.ru 
3354216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3355216Sigor@sysoev.ru         NXT_WRITE(&eof);
3356277Sigor@sysoev.ru 
3357216Sigor@sysoev.ru     } else {
3358216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3359216Sigor@sysoev.ru     }
3360216Sigor@sysoev.ru 
3361216Sigor@sysoev.ru     if (h->query.start != NULL) {
3362216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3363216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3364216Sigor@sysoev.ru     } else {
3365216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3366216Sigor@sysoev.ru     }
3367216Sigor@sysoev.ru 
3368216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3369216Sigor@sysoev.ru 
3370216Sigor@sysoev.ru     // PHP_SELF
3371216Sigor@sysoev.ru     // SCRIPT_NAME
3372216Sigor@sysoev.ru     // SCRIPT_FILENAME
3373216Sigor@sysoev.ru     // DOCUMENT_ROOT
3374216Sigor@sysoev.ru 
3375216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3376268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3377216Sigor@sysoev.ru 
3378216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3379216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3380216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3381216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3382216Sigor@sysoev.ru 
3383216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3384305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3385305Smax.romanov@nginx.com 
3386305Smax.romanov@nginx.com     method_is_post = h->method.length == 4 &&
3387305Smax.romanov@nginx.com                      h->method.start[0] == 'P' &&
3388305Smax.romanov@nginx.com                      h->method.start[1] == 'O' &&
3389305Smax.romanov@nginx.com                      h->method.start[2] == 'S' &&
3390305Smax.romanov@nginx.com                      h->method.start[3] == 'T';
3391305Smax.romanov@nginx.com 
3392305Smax.romanov@nginx.com     if (method_is_post) {
3393305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3394305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3395305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3396305Smax.romanov@nginx.com         }
3397305Smax.romanov@nginx.com     }
3398216Sigor@sysoev.ru 
3399216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3400216Sigor@sysoev.ru         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg,
3401216Sigor@sysoev.ru                                              &prefix, &field->name));
3402216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3403216Sigor@sysoev.ru 
3404216Sigor@sysoev.ru     } nxt_list_loop;
3405216Sigor@sysoev.ru 
3406216Sigor@sysoev.ru     /* end-of-headers mark */
3407216Sigor@sysoev.ru     NXT_WRITE(&eof);
3408216Sigor@sysoev.ru 
3409305Smax.romanov@nginx.com     if (!method_is_post) {
3410305Smax.romanov@nginx.com         for(b = r->body.buf; b != NULL; b = b->next) {
3411305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3412305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3413305Smax.romanov@nginx.com         }
3414216Sigor@sysoev.ru     }
3415216Sigor@sysoev.ru 
3416216Sigor@sysoev.ru #undef NXT_WRITE
3417216Sigor@sysoev.ru #undef RC
3418216Sigor@sysoev.ru 
3419216Sigor@sysoev.ru     return NXT_OK;
3420216Sigor@sysoev.ru 
3421216Sigor@sysoev.ru fail:
3422216Sigor@sysoev.ru 
3423216Sigor@sysoev.ru     return NXT_ERROR;
3424216Sigor@sysoev.ru }
3425216Sigor@sysoev.ru 
3426216Sigor@sysoev.ru 
3427216Sigor@sysoev.ru static nxt_int_t
3428216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3429216Sigor@sysoev.ru {
3430216Sigor@sysoev.ru     nxt_int_t                 rc;
3431216Sigor@sysoev.ru     nxt_buf_t                 *b;
3432216Sigor@sysoev.ru     nxt_http_field_t          *field;
3433216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3434216Sigor@sysoev.ru 
3435216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3436216Sigor@sysoev.ru 
3437216Sigor@sysoev.ru     h = &r->header;
3438216Sigor@sysoev.ru 
3439216Sigor@sysoev.ru #define RC(S)                                                                 \
3440216Sigor@sysoev.ru     do {                                                                      \
3441216Sigor@sysoev.ru         rc = (S);                                                             \
3442216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3443216Sigor@sysoev.ru             goto fail;                                                        \
3444216Sigor@sysoev.ru         }                                                                     \
3445216Sigor@sysoev.ru     } while(0)
3446216Sigor@sysoev.ru 
3447216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3448216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3449216Sigor@sysoev.ru 
3450216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3451216Sigor@sysoev.ru 
3452216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3453216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3454277Sigor@sysoev.ru 
3455216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3456216Sigor@sysoev.ru         NXT_WRITE(&eof);
3457277Sigor@sysoev.ru 
3458216Sigor@sysoev.ru     } else {
3459216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3460216Sigor@sysoev.ru     }
3461216Sigor@sysoev.ru 
3462216Sigor@sysoev.ru     if (h->query.start != NULL) {
3463216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3464216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3465216Sigor@sysoev.ru     } else {
3466216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3467216Sigor@sysoev.ru     }
3468216Sigor@sysoev.ru 
3469216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3470253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3471216Sigor@sysoev.ru 
3472216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3473216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3474216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3475216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3476216Sigor@sysoev.ru 
3477216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3478216Sigor@sysoev.ru 
3479216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3480216Sigor@sysoev.ru         NXT_WRITE(&field->name);
3481216Sigor@sysoev.ru         NXT_WRITE(&field->value);
3482216Sigor@sysoev.ru 
3483216Sigor@sysoev.ru     } nxt_list_loop;
3484216Sigor@sysoev.ru 
3485216Sigor@sysoev.ru     /* end-of-headers mark */
3486216Sigor@sysoev.ru     NXT_WRITE(&eof);
3487216Sigor@sysoev.ru 
3488216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3489216Sigor@sysoev.ru 
3490216Sigor@sysoev.ru     for(b = r->body.buf; b != NULL; b = b->next) {
3491216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3492216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3493216Sigor@sysoev.ru     }
3494216Sigor@sysoev.ru 
3495216Sigor@sysoev.ru #undef NXT_WRITE
3496216Sigor@sysoev.ru #undef RC
3497216Sigor@sysoev.ru 
3498216Sigor@sysoev.ru     return NXT_OK;
3499216Sigor@sysoev.ru 
3500216Sigor@sysoev.ru fail:
3501216Sigor@sysoev.ru 
3502216Sigor@sysoev.ru     return NXT_ERROR;
3503216Sigor@sysoev.ru }
3504216Sigor@sysoev.ru 
3505216Sigor@sysoev.ru 
350662Sigor@sysoev.ru static const nxt_conn_state_t  nxt_router_conn_close_state
350753Sigor@sysoev.ru     nxt_aligned(64) =
350853Sigor@sysoev.ru {
350953Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
351053Sigor@sysoev.ru };
351153Sigor@sysoev.ru 
351253Sigor@sysoev.ru 
351353Sigor@sysoev.ru static void
351488Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data)
351588Smax.romanov@nginx.com {
351688Smax.romanov@nginx.com     nxt_buf_t         *b;
351788Smax.romanov@nginx.com     nxt_bool_t        last;
351888Smax.romanov@nginx.com     nxt_conn_t        *c;
351988Smax.romanov@nginx.com     nxt_work_queue_t  *wq;
352088Smax.romanov@nginx.com 
352188Smax.romanov@nginx.com     nxt_debug(task, "router conn ready %p", obj);
352288Smax.romanov@nginx.com 
352388Smax.romanov@nginx.com     c = obj;
352488Smax.romanov@nginx.com     b = c->write;
352588Smax.romanov@nginx.com 
352688Smax.romanov@nginx.com     wq = &task->thread->engine->fast_work_queue;
352788Smax.romanov@nginx.com 
352888Smax.romanov@nginx.com     last = 0;
352988Smax.romanov@nginx.com 
353088Smax.romanov@nginx.com     while (b != NULL) {
353188Smax.romanov@nginx.com         if (!nxt_buf_is_sync(b)) {
353288Smax.romanov@nginx.com             if (nxt_buf_used_size(b) > 0) {
353388Smax.romanov@nginx.com                 break;
353488Smax.romanov@nginx.com             }
353588Smax.romanov@nginx.com         }
353688Smax.romanov@nginx.com 
353788Smax.romanov@nginx.com         if (nxt_buf_is_last(b)) {
353888Smax.romanov@nginx.com             last = 1;
353988Smax.romanov@nginx.com         }
354088Smax.romanov@nginx.com 
354188Smax.romanov@nginx.com         nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent);
354288Smax.romanov@nginx.com 
354388Smax.romanov@nginx.com         b = b->next;
354488Smax.romanov@nginx.com     }
354588Smax.romanov@nginx.com 
354688Smax.romanov@nginx.com     c->write = b;
354788Smax.romanov@nginx.com 
354888Smax.romanov@nginx.com     if (b != NULL) {
354988Smax.romanov@nginx.com         nxt_debug(task, "router conn %p has more data to write", obj);
355088Smax.romanov@nginx.com 
355188Smax.romanov@nginx.com         nxt_conn_write(task->thread->engine, c);
3552277Sigor@sysoev.ru 
355388Smax.romanov@nginx.com     } else {
355488Smax.romanov@nginx.com         nxt_debug(task, "router conn %p no more data to write, last = %d", obj,
355588Smax.romanov@nginx.com                   last);
355688Smax.romanov@nginx.com 
355788Smax.romanov@nginx.com         if (last != 0) {
355888Smax.romanov@nginx.com             nxt_debug(task, "enqueue router conn close %p (ready handler)", c);
355988Smax.romanov@nginx.com 
356088Smax.romanov@nginx.com             nxt_work_queue_add(wq, nxt_router_conn_close, task, c,
356188Smax.romanov@nginx.com                                c->socket.data);
356288Smax.romanov@nginx.com         }
356388Smax.romanov@nginx.com     }
356488Smax.romanov@nginx.com }
356588Smax.romanov@nginx.com 
356688Smax.romanov@nginx.com 
356788Smax.romanov@nginx.com static void
356853Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data)
356953Sigor@sysoev.ru {
357062Sigor@sysoev.ru     nxt_conn_t  *c;
357153Sigor@sysoev.ru 
357253Sigor@sysoev.ru     c = obj;
357353Sigor@sysoev.ru 
357453Sigor@sysoev.ru     nxt_debug(task, "router conn close");
357553Sigor@sysoev.ru 
357653Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
357753Sigor@sysoev.ru 
357862Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
357953Sigor@sysoev.ru }
358053Sigor@sysoev.ru 
358153Sigor@sysoev.ru 
358253Sigor@sysoev.ru static void
3583164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
3584164Smax.romanov@nginx.com {
3585164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
3586164Smax.romanov@nginx.com 
3587164Smax.romanov@nginx.com     joint = obj;
3588164Smax.romanov@nginx.com 
3589164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
3590164Smax.romanov@nginx.com }
3591164Smax.romanov@nginx.com 
3592164Smax.romanov@nginx.com 
3593164Smax.romanov@nginx.com static void
359453Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
359553Sigor@sysoev.ru {
359662Sigor@sysoev.ru     nxt_conn_t               *c;
3597337Sigor@sysoev.ru     nxt_event_engine_t       *engine;
359888Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
3599319Smax.romanov@nginx.com     nxt_app_parse_ctx_t      *ap;
360053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
360153Sigor@sysoev.ru 
360253Sigor@sysoev.ru     c = obj;
3603319Smax.romanov@nginx.com     ap = data;
360453Sigor@sysoev.ru 
360553Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
360653Sigor@sysoev.ru 
3607319Smax.romanov@nginx.com     if (ap != NULL) {
3608319Smax.romanov@nginx.com         nxt_app_http_req_done(task, ap);
3609319Smax.romanov@nginx.com 
3610319Smax.romanov@nginx.com         c->socket.data = NULL;
3611319Smax.romanov@nginx.com     }
3612319Smax.romanov@nginx.com 
361388Smax.romanov@nginx.com     nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) {
361488Smax.romanov@nginx.com 
3615318Smax.romanov@nginx.com         nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream);
361688Smax.romanov@nginx.com 
3617343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3618318Smax.romanov@nginx.com 
3619318Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream);
362088Smax.romanov@nginx.com 
362188Smax.romanov@nginx.com     } nxt_queue_loop;
362288Smax.romanov@nginx.com 
3623122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
3624122Smax.romanov@nginx.com 
3625337Sigor@sysoev.ru     engine = task->thread->engine;
3626337Sigor@sysoev.ru 
3627337Sigor@sysoev.ru     nxt_sockaddr_cache_free(engine, c);
3628337Sigor@sysoev.ru 
3629131Smax.romanov@nginx.com     joint = c->listen->socket.data;
3630131Smax.romanov@nginx.com 
3631337Sigor@sysoev.ru     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup,
3632337Sigor@sysoev.ru                    &engine->task, joint, NULL);
3633164Smax.romanov@nginx.com 
3634164Smax.romanov@nginx.com     nxt_mp_release(c->mem_pool, c);
363553Sigor@sysoev.ru }
363653Sigor@sysoev.ru 
363753Sigor@sysoev.ru 
363853Sigor@sysoev.ru static void
363953Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data)
364053Sigor@sysoev.ru {
364162Sigor@sysoev.ru     nxt_conn_t  *c;
364253Sigor@sysoev.ru 
364353Sigor@sysoev.ru     c = obj;
364453Sigor@sysoev.ru 
364553Sigor@sysoev.ru     nxt_debug(task, "router conn error");
364653Sigor@sysoev.ru 
3647273Smax.romanov@nginx.com     if (c->socket.fd != -1) {
3648273Smax.romanov@nginx.com         c->write_state = &nxt_router_conn_close_state;
3649273Smax.romanov@nginx.com 
3650273Smax.romanov@nginx.com         nxt_conn_close(task->thread->engine, c);
3651273Smax.romanov@nginx.com     }
365253Sigor@sysoev.ru }
365353Sigor@sysoev.ru 
365453Sigor@sysoev.ru 
365553Sigor@sysoev.ru static void
365653Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data)
365753Sigor@sysoev.ru {
365862Sigor@sysoev.ru     nxt_conn_t   *c;
365962Sigor@sysoev.ru     nxt_timer_t  *timer;
366053Sigor@sysoev.ru 
366153Sigor@sysoev.ru     timer = obj;
366253Sigor@sysoev.ru 
366353Sigor@sysoev.ru     nxt_debug(task, "router conn timeout");
366453Sigor@sysoev.ru 
366562Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
366653Sigor@sysoev.ru 
3667206Smax.romanov@nginx.com     if (c->read_state == &nxt_router_conn_read_header_state) {
3668206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read header timeout");
3669206Smax.romanov@nginx.com 
3670206Smax.romanov@nginx.com     } else {
3671206Smax.romanov@nginx.com         nxt_router_gen_error(task, c, 408, "Read body timeout");
3672206Smax.romanov@nginx.com     }
367353Sigor@sysoev.ru }
367453Sigor@sysoev.ru 
367553Sigor@sysoev.ru 
3676318Smax.romanov@nginx.com static void
3677318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
3678318Smax.romanov@nginx.com {
3679318Smax.romanov@nginx.com     nxt_conn_t   *c;
3680318Smax.romanov@nginx.com     nxt_timer_t  *timer;
3681318Smax.romanov@nginx.com 
3682318Smax.romanov@nginx.com     timer = obj;
3683318Smax.romanov@nginx.com 
3684318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
3685318Smax.romanov@nginx.com 
3686318Smax.romanov@nginx.com     c = nxt_read_timer_conn(timer);
3687318Smax.romanov@nginx.com 
3688318Smax.romanov@nginx.com     nxt_router_gen_error(task, c, 408, "Application timeout");
3689318Smax.romanov@nginx.com }
3690318Smax.romanov@nginx.com 
3691318Smax.romanov@nginx.com 
369253Sigor@sysoev.ru static nxt_msec_t
369362Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
369453Sigor@sysoev.ru {
369553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
369653Sigor@sysoev.ru 
369753Sigor@sysoev.ru     joint = c->listen->socket.data;
369853Sigor@sysoev.ru 
369953Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
370053Sigor@sysoev.ru }
3701