xref: /unit/src/nxt_router.c (revision 510)
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>
10431Sigor@sysoev.ru #include <nxt_http.h>
1120Sigor@sysoev.ru 
1220Sigor@sysoev.ru 
13115Sigor@sysoev.ru typedef struct {
14318Smax.romanov@nginx.com     nxt_str_t         type;
15507Smax.romanov@nginx.com     uint32_t          processes;
16507Smax.romanov@nginx.com     uint32_t          max_processes;
17507Smax.romanov@nginx.com     uint32_t          spare_processes;
18318Smax.romanov@nginx.com     nxt_msec_t        timeout;
19427Smax.romanov@nginx.com     nxt_msec_t        res_timeout;
20507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
21318Smax.romanov@nginx.com     uint32_t          requests;
22318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
23507Smax.romanov@nginx.com     nxt_conf_value_t  *processes_value;
24133Sigor@sysoev.ru } nxt_router_app_conf_t;
25133Sigor@sysoev.ru 
26133Sigor@sysoev.ru 
27133Sigor@sysoev.ru typedef struct {
28133Sigor@sysoev.ru     nxt_str_t  application;
29115Sigor@sysoev.ru } nxt_router_listener_conf_t;
30115Sigor@sysoev.ru 
31115Sigor@sysoev.ru 
32423Smax.romanov@nginx.com typedef struct nxt_msg_info_s {
33423Smax.romanov@nginx.com     nxt_buf_t                 *buf;
34423Smax.romanov@nginx.com     nxt_port_mmap_tracking_t  tracking;
35423Smax.romanov@nginx.com     nxt_work_handler_t        completion_handler;
36423Smax.romanov@nginx.com } nxt_msg_info_t;
37423Smax.romanov@nginx.com 
38423Smax.romanov@nginx.com 
39167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
40141Smax.romanov@nginx.com 
41141Smax.romanov@nginx.com 
42318Smax.romanov@nginx.com typedef struct {
43431Sigor@sysoev.ru     uint32_t                 stream;
44431Sigor@sysoev.ru     nxt_app_t                *app;
45431Sigor@sysoev.ru     nxt_port_t               *app_port;
46431Sigor@sysoev.ru     nxt_app_parse_ctx_t      *ap;
47431Sigor@sysoev.ru     nxt_msg_info_t           msg_info;
48431Sigor@sysoev.ru     nxt_req_app_link_t       *ra;
49431Sigor@sysoev.ru 
50431Sigor@sysoev.ru     nxt_queue_link_t         link;     /* for nxt_conn_t.requests */
51318Smax.romanov@nginx.com } nxt_req_conn_link_t;
52318Smax.romanov@nginx.com 
53318Smax.romanov@nginx.com 
54167Smax.romanov@nginx.com struct nxt_req_app_link_s {
55318Smax.romanov@nginx.com     uint32_t             stream;
56425Smax.romanov@nginx.com     nxt_atomic_t         use_count;
57167Smax.romanov@nginx.com     nxt_port_t           *app_port;
58167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
59167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
60423Smax.romanov@nginx.com     nxt_msg_info_t       msg_info;
61167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
62167Smax.romanov@nginx.com 
63427Smax.romanov@nginx.com     nxt_nsec_t           res_time;
64427Smax.romanov@nginx.com 
65425Smax.romanov@nginx.com     nxt_queue_link_t     link_app_requests; /* for nxt_app_t.requests */
66425Smax.romanov@nginx.com     nxt_queue_link_t     link_port_pending; /* for nxt_port_t.pending_requests */
67427Smax.romanov@nginx.com     nxt_queue_link_t     link_app_pending;  /* for nxt_app_t.pending */
68167Smax.romanov@nginx.com 
69167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
70167Smax.romanov@nginx.com     nxt_work_t           work;
71345Smax.romanov@nginx.com 
72345Smax.romanov@nginx.com     int                  err_code;
73345Smax.romanov@nginx.com     const char           *err_str;
74167Smax.romanov@nginx.com };
75167Smax.romanov@nginx.com 
76167Smax.romanov@nginx.com 
77198Sigor@sysoev.ru typedef struct {
78198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
79198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
80198Sigor@sysoev.ru } nxt_socket_rpc_t;
81198Sigor@sysoev.ru 
82198Sigor@sysoev.ru 
83507Smax.romanov@nginx.com typedef struct {
84507Smax.romanov@nginx.com     nxt_app_t               *app;
85507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
86507Smax.romanov@nginx.com } nxt_app_rpc_t;
87507Smax.romanov@nginx.com 
88507Smax.romanov@nginx.com 
89427Smax.romanov@nginx.com struct nxt_port_select_state_s {
90427Smax.romanov@nginx.com     nxt_app_t           *app;
91427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
92427Smax.romanov@nginx.com 
93427Smax.romanov@nginx.com     nxt_port_t          *failed_port;
94427Smax.romanov@nginx.com     int                 failed_port_use_delta;
95427Smax.romanov@nginx.com 
96507Smax.romanov@nginx.com     uint8_t             start_process;    /* 1 bit */
97427Smax.romanov@nginx.com     nxt_req_app_link_t  *shared_ra;
98427Smax.romanov@nginx.com     nxt_port_t          *port;
99427Smax.romanov@nginx.com };
100427Smax.romanov@nginx.com 
101427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t;
102427Smax.romanov@nginx.com 
103427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task,
104427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
105427Smax.romanov@nginx.com 
106427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task,
107427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
108427Smax.romanov@nginx.com 
109507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
110343Smax.romanov@nginx.com 
111425Smax.romanov@nginx.com nxt_inline void
112425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra)
113425Smax.romanov@nginx.com {
114425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, 1);
115425Smax.romanov@nginx.com }
116425Smax.romanov@nginx.com 
117425Smax.romanov@nginx.com nxt_inline void
118425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra)
119425Smax.romanov@nginx.com {
120425Smax.romanov@nginx.com     int  c;
121425Smax.romanov@nginx.com 
122425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, -1);
123425Smax.romanov@nginx.com 
124425Smax.romanov@nginx.com     nxt_assert(c > 1);
125425Smax.romanov@nginx.com }
126425Smax.romanov@nginx.com 
127425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i);
128425Smax.romanov@nginx.com 
129139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
130198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
131198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
132139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
133139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
134139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
135139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
136193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
13753Sigor@sysoev.ru 
138115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
139115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
140133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
141133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
142133Sigor@sysoev.ru     nxt_str_t *name);
143198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
144198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
145198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
146198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
147198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
148198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
149507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
150507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
151507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
152507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
153507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
154507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
155359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
156359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
157359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
158359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
15953Sigor@sysoev.ru 
16053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
16153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
16253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
163115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
164115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
165115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
166115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
167115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
168115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
169154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
170154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
171154Sigor@sysoev.ru     nxt_work_handler_t handler);
172313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
173313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
174139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
175139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
17653Sigor@sysoev.ru 
17753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
17853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
17953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
18053Sigor@sysoev.ru     nxt_event_engine_t *engine);
181343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
182133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
18353Sigor@sysoev.ru 
184315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
185315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
186315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
187315Sigor@sysoev.ru     nxt_work_t *jobs);
18853Sigor@sysoev.ru 
18953Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
19053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
19153Sigor@sysoev.ru     void *data);
19253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
19353Sigor@sysoev.ru     void *data);
19453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
19553Sigor@sysoev.ru     void *data);
196313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
197313Sigor@sysoev.ru     void *data);
19853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
19953Sigor@sysoev.ru     void *data);
20053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
20153Sigor@sysoev.ru     void *data);
202359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
203359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
20453Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task,
20553Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint);
20653Sigor@sysoev.ru 
207343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
208343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
209343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
210343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
211343Smax.romanov@nginx.com 
212507Smax.romanov@nginx.com static void nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app);
213343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
214343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
215427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
216427Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
217141Smax.romanov@nginx.com 
218425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
219343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
220216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
221216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
222216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
223216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
224216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
225216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg);
226*510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
227*510Salexander.borisov@nginx.com     nxt_app_wmsg_t *wmsg);
228*510Salexander.borisov@nginx.com 
22953Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data);
230318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
231507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
232507Smax.romanov@nginx.com     void *data);
233507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
234507Smax.romanov@nginx.com     void *data);
235507Smax.romanov@nginx.com static void nxt_router_app_release_handler(nxt_task_t *task, void *obj,
236507Smax.romanov@nginx.com     void *data);
237431Sigor@sysoev.ru 
238431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
239431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
240141Smax.romanov@nginx.com 
241119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
24220Sigor@sysoev.ru 
243216Sigor@sysoev.ru 
244216Sigor@sysoev.ru static nxt_app_prepare_msg_t  nxt_app_prepare_msg[] = {
245216Sigor@sysoev.ru     nxt_python_prepare_msg,
246216Sigor@sysoev.ru     nxt_php_prepare_msg,
247216Sigor@sysoev.ru     nxt_go_prepare_msg,
248*510Salexander.borisov@nginx.com     nxt_perl_prepare_msg,
249216Sigor@sysoev.ru };
250216Sigor@sysoev.ru 
251216Sigor@sysoev.ru 
25220Sigor@sysoev.ru nxt_int_t
253141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
25420Sigor@sysoev.ru {
255141Smax.romanov@nginx.com     nxt_int_t      ret;
256141Smax.romanov@nginx.com     nxt_router_t   *router;
257141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
258141Smax.romanov@nginx.com 
259141Smax.romanov@nginx.com     rt = task->thread->runtime;
26053Sigor@sysoev.ru 
261431Sigor@sysoev.ru     ret = nxt_http_init(task, rt);
26288Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
26388Smax.romanov@nginx.com         return ret;
26488Smax.romanov@nginx.com     }
26588Smax.romanov@nginx.com 
26653Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
26753Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
26853Sigor@sysoev.ru         return NXT_ERROR;
26953Sigor@sysoev.ru     }
27053Sigor@sysoev.ru 
27153Sigor@sysoev.ru     nxt_queue_init(&router->engines);
27253Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
273133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
27453Sigor@sysoev.ru 
275119Smax.romanov@nginx.com     nxt_router = router;
276119Smax.romanov@nginx.com 
277115Sigor@sysoev.ru     return NXT_OK;
278115Sigor@sysoev.ru }
279115Sigor@sysoev.ru 
280115Sigor@sysoev.ru 
281343Smax.romanov@nginx.com static void
282507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
283507Smax.romanov@nginx.com     void *data)
284167Smax.romanov@nginx.com {
285343Smax.romanov@nginx.com     size_t         size;
286343Smax.romanov@nginx.com     uint32_t       stream;
287430Sigor@sysoev.ru     nxt_mp_t       *mp;
288343Smax.romanov@nginx.com     nxt_app_t      *app;
289343Smax.romanov@nginx.com     nxt_buf_t      *b;
290343Smax.romanov@nginx.com     nxt_port_t     *main_port;
291343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
292343Smax.romanov@nginx.com 
293343Smax.romanov@nginx.com     app = data;
294167Smax.romanov@nginx.com 
295167Smax.romanov@nginx.com     rt = task->thread->runtime;
296240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
297167Smax.romanov@nginx.com 
298507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
299343Smax.romanov@nginx.com 
300343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
301343Smax.romanov@nginx.com 
302343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
303343Smax.romanov@nginx.com 
304343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
305343Smax.romanov@nginx.com         goto failed;
306167Smax.romanov@nginx.com     }
307167Smax.romanov@nginx.com 
308343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
309343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
310343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
311343Smax.romanov@nginx.com 
312343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
313343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
314343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
315343Smax.romanov@nginx.com                                            -1, app);
316343Smax.romanov@nginx.com 
317343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
318430Sigor@sysoev.ru         mp = b->data;
319430Sigor@sysoev.ru         nxt_mp_free(mp, b);
320430Sigor@sysoev.ru         nxt_mp_release(mp);
321343Smax.romanov@nginx.com 
322343Smax.romanov@nginx.com         goto failed;
323343Smax.romanov@nginx.com     }
324343Smax.romanov@nginx.com 
325343Smax.romanov@nginx.com     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
326343Smax.romanov@nginx.com                           stream, port->id, b);
327343Smax.romanov@nginx.com 
328343Smax.romanov@nginx.com     return;
329343Smax.romanov@nginx.com 
330343Smax.romanov@nginx.com failed:
331343Smax.romanov@nginx.com 
332343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
333343Smax.romanov@nginx.com 
334507Smax.romanov@nginx.com     app->pending_processes--;
335343Smax.romanov@nginx.com 
336343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
337343Smax.romanov@nginx.com 
338343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
339167Smax.romanov@nginx.com }
340167Smax.romanov@nginx.com 
341167Smax.romanov@nginx.com 
342343Smax.romanov@nginx.com static nxt_int_t
343507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
344141Smax.romanov@nginx.com {
345343Smax.romanov@nginx.com     nxt_int_t      res;
346343Smax.romanov@nginx.com     nxt_port_t     *router_port;
347343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
348343Smax.romanov@nginx.com 
349343Smax.romanov@nginx.com     rt = task->thread->runtime;
350343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
351343Smax.romanov@nginx.com 
352343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
353343Smax.romanov@nginx.com 
354507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
355343Smax.romanov@nginx.com                         app);
356343Smax.romanov@nginx.com 
357343Smax.romanov@nginx.com     if (res == NXT_OK) {
358343Smax.romanov@nginx.com         return res;
359318Smax.romanov@nginx.com     }
360318Smax.romanov@nginx.com 
361343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
362343Smax.romanov@nginx.com 
363507Smax.romanov@nginx.com     app->pending_processes--;
364343Smax.romanov@nginx.com 
365343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
366343Smax.romanov@nginx.com 
367343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
368343Smax.romanov@nginx.com 
369343Smax.romanov@nginx.com     return NXT_ERROR;
370318Smax.romanov@nginx.com }
371318Smax.romanov@nginx.com 
372318Smax.romanov@nginx.com 
373351Smax.romanov@nginx.com nxt_inline void
374351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
375351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
376167Smax.romanov@nginx.com {
377318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
378351Smax.romanov@nginx.com 
379318Smax.romanov@nginx.com     engine = task->thread->engine;
380167Smax.romanov@nginx.com 
381167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
382167Smax.romanov@nginx.com 
383318Smax.romanov@nginx.com     ra->stream = rc->stream;
384425Smax.romanov@nginx.com     ra->use_count = 1;
385167Smax.romanov@nginx.com     ra->rc = rc;
386318Smax.romanov@nginx.com     rc->ra = ra;
387318Smax.romanov@nginx.com     ra->reply_port = engine->port;
388351Smax.romanov@nginx.com     ra->ap = rc->ap;
389167Smax.romanov@nginx.com 
390167Smax.romanov@nginx.com     ra->work.handler = NULL;
391318Smax.romanov@nginx.com     ra->work.task = &engine->task;
392167Smax.romanov@nginx.com     ra->work.obj = ra;
393318Smax.romanov@nginx.com     ra->work.data = engine;
394351Smax.romanov@nginx.com }
395351Smax.romanov@nginx.com 
396351Smax.romanov@nginx.com 
397351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
398351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
399351Smax.romanov@nginx.com {
400351Smax.romanov@nginx.com     nxt_mp_t            *mp;
401351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
402351Smax.romanov@nginx.com 
403425Smax.romanov@nginx.com     if (ra_src->mem_pool != NULL) {
404425Smax.romanov@nginx.com         return ra_src;
405425Smax.romanov@nginx.com     }
406425Smax.romanov@nginx.com 
407351Smax.romanov@nginx.com     mp = ra_src->ap->mem_pool;
408351Smax.romanov@nginx.com 
409430Sigor@sysoev.ru     ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t));
410351Smax.romanov@nginx.com 
411351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
412351Smax.romanov@nginx.com 
413351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
414351Smax.romanov@nginx.com         ra_src->rc = NULL;
415351Smax.romanov@nginx.com 
416351Smax.romanov@nginx.com         return NULL;
417351Smax.romanov@nginx.com     }
418351Smax.romanov@nginx.com 
419430Sigor@sysoev.ru     nxt_mp_retain(mp);
420430Sigor@sysoev.ru 
421351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
422351Smax.romanov@nginx.com 
423351Smax.romanov@nginx.com     ra->mem_pool = mp;
424167Smax.romanov@nginx.com 
425167Smax.romanov@nginx.com     return ra;
426167Smax.romanov@nginx.com }
427167Smax.romanov@nginx.com 
428167Smax.romanov@nginx.com 
429423Smax.romanov@nginx.com nxt_inline nxt_bool_t
430423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
431423Smax.romanov@nginx.com     uint32_t stream)
432423Smax.romanov@nginx.com {
433423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
434423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
435423Smax.romanov@nginx.com 
436423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
437423Smax.romanov@nginx.com         return 0;
438423Smax.romanov@nginx.com     }
439423Smax.romanov@nginx.com 
440423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
441423Smax.romanov@nginx.com                                               stream);
442423Smax.romanov@nginx.com 
443423Smax.romanov@nginx.com     if (cancelled) {
444423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
445423Smax.romanov@nginx.com     }
446423Smax.romanov@nginx.com 
447423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
448423Smax.romanov@nginx.com         next = b->next;
449423Smax.romanov@nginx.com 
450423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
451423Smax.romanov@nginx.com 
452423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
453423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
454423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
455423Smax.romanov@nginx.com         }
456423Smax.romanov@nginx.com     }
457423Smax.romanov@nginx.com 
458423Smax.romanov@nginx.com     msg_info->buf = NULL;
459423Smax.romanov@nginx.com 
460423Smax.romanov@nginx.com     return cancelled;
461423Smax.romanov@nginx.com }
462423Smax.romanov@nginx.com 
463423Smax.romanov@nginx.com 
464167Smax.romanov@nginx.com static void
465425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra);
466425Smax.romanov@nginx.com 
467425Smax.romanov@nginx.com 
468425Smax.romanov@nginx.com static void
469425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data)
470167Smax.romanov@nginx.com {
471425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
472425Smax.romanov@nginx.com 
473425Smax.romanov@nginx.com     ra = obj;
474425Smax.romanov@nginx.com 
475425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
476425Smax.romanov@nginx.com 
477425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
478425Smax.romanov@nginx.com }
479425Smax.romanov@nginx.com 
480425Smax.romanov@nginx.com 
481425Smax.romanov@nginx.com static void
482425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra)
483425Smax.romanov@nginx.com {
484343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
485343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
486318Smax.romanov@nginx.com 
487425Smax.romanov@nginx.com     engine = ra->work.data;
488318Smax.romanov@nginx.com 
489343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
490425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
491425Smax.romanov@nginx.com 
492425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_update_peer_handler;
493318Smax.romanov@nginx.com         ra->work.task = &engine->task;
494318Smax.romanov@nginx.com         ra->work.next = NULL;
495318Smax.romanov@nginx.com 
496425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post update peer to %p",
497318Smax.romanov@nginx.com                   ra->stream, engine);
498318Smax.romanov@nginx.com 
499318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
500318Smax.romanov@nginx.com 
501318Smax.romanov@nginx.com         return;
502318Smax.romanov@nginx.com     }
503318Smax.romanov@nginx.com 
504425Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD update peer", ra->stream);
505425Smax.romanov@nginx.com 
506425Smax.romanov@nginx.com     rc = ra->rc;
507425Smax.romanov@nginx.com 
508425Smax.romanov@nginx.com     if (rc != NULL && ra->app_port != NULL) {
509425Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid);
510425Smax.romanov@nginx.com     }
511425Smax.romanov@nginx.com 
512425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
513425Smax.romanov@nginx.com }
514425Smax.romanov@nginx.com 
515425Smax.romanov@nginx.com 
516425Smax.romanov@nginx.com static void
517425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra)
518425Smax.romanov@nginx.com {
519431Sigor@sysoev.ru     nxt_mp_t                *mp;
520431Sigor@sysoev.ru     nxt_req_conn_link_t     *rc;
521425Smax.romanov@nginx.com 
522425Smax.romanov@nginx.com     nxt_assert(task->thread->engine == ra->work.data);
523425Smax.romanov@nginx.com     nxt_assert(ra->use_count == 0);
524425Smax.romanov@nginx.com 
525343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
526343Smax.romanov@nginx.com 
527343Smax.romanov@nginx.com     rc = ra->rc;
528343Smax.romanov@nginx.com 
529343Smax.romanov@nginx.com     if (rc != NULL) {
530423Smax.romanov@nginx.com         if (nxt_slow_path(ra->err_code != 0)) {
531431Sigor@sysoev.ru             nxt_http_request_error(task, rc->ap->request, ra->err_code);
532423Smax.romanov@nginx.com 
533423Smax.romanov@nginx.com         } else {
534423Smax.romanov@nginx.com             rc->app_port = ra->app_port;
535423Smax.romanov@nginx.com             rc->msg_info = ra->msg_info;
536423Smax.romanov@nginx.com 
537425Smax.romanov@nginx.com             if (rc->app->timeout != 0) {
538431Sigor@sysoev.ru                 rc->ap->timer.handler = nxt_router_app_timeout;
539431Sigor@sysoev.ru                 nxt_timer_add(task->thread->engine, &rc->ap->timer,
540425Smax.romanov@nginx.com                               rc->app->timeout);
541425Smax.romanov@nginx.com             }
542425Smax.romanov@nginx.com 
543423Smax.romanov@nginx.com             ra->app_port = NULL;
544423Smax.romanov@nginx.com             ra->msg_info.buf = NULL;
545423Smax.romanov@nginx.com         }
546343Smax.romanov@nginx.com 
547343Smax.romanov@nginx.com         rc->ra = NULL;
548343Smax.romanov@nginx.com         ra->rc = NULL;
549343Smax.romanov@nginx.com     }
550343Smax.romanov@nginx.com 
551343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
552343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
553343Smax.romanov@nginx.com 
554343Smax.romanov@nginx.com         ra->app_port = NULL;
555167Smax.romanov@nginx.com     }
556167Smax.romanov@nginx.com 
557423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
558423Smax.romanov@nginx.com 
559430Sigor@sysoev.ru     mp = ra->mem_pool;
560430Sigor@sysoev.ru 
561430Sigor@sysoev.ru     if (mp != NULL) {
562430Sigor@sysoev.ru         nxt_mp_free(mp, ra);
563430Sigor@sysoev.ru         nxt_mp_release(mp);
564351Smax.romanov@nginx.com     }
565167Smax.romanov@nginx.com }
566167Smax.romanov@nginx.com 
567167Smax.romanov@nginx.com 
568425Smax.romanov@nginx.com static void
569425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data)
570425Smax.romanov@nginx.com {
571425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
572425Smax.romanov@nginx.com 
573425Smax.romanov@nginx.com     ra = obj;
574425Smax.romanov@nginx.com 
575425Smax.romanov@nginx.com     nxt_assert(ra->work.data == data);
576425Smax.romanov@nginx.com 
577425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, -1);
578425Smax.romanov@nginx.com 
579425Smax.romanov@nginx.com     nxt_router_ra_release(task, ra);
580425Smax.romanov@nginx.com }
581425Smax.romanov@nginx.com 
582425Smax.romanov@nginx.com 
583425Smax.romanov@nginx.com static void
584425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i)
585425Smax.romanov@nginx.com {
586425Smax.romanov@nginx.com     int                 c;
587425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
588425Smax.romanov@nginx.com 
589425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, i);
590425Smax.romanov@nginx.com 
591425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
592425Smax.romanov@nginx.com         engine = ra->work.data;
593425Smax.romanov@nginx.com 
594425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
595425Smax.romanov@nginx.com             nxt_router_ra_release(task, ra);
596425Smax.romanov@nginx.com 
597425Smax.romanov@nginx.com             return;
598425Smax.romanov@nginx.com         }
599425Smax.romanov@nginx.com 
600425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
601425Smax.romanov@nginx.com 
602425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release_handler;
603425Smax.romanov@nginx.com         ra->work.task = &engine->task;
604425Smax.romanov@nginx.com         ra->work.next = NULL;
605425Smax.romanov@nginx.com 
606425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
607425Smax.romanov@nginx.com                   ra->stream, engine);
608425Smax.romanov@nginx.com 
609425Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
610425Smax.romanov@nginx.com     }
611425Smax.romanov@nginx.com }
612425Smax.romanov@nginx.com 
613425Smax.romanov@nginx.com 
614423Smax.romanov@nginx.com nxt_inline void
615423Smax.romanov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char* str)
616345Smax.romanov@nginx.com {
617423Smax.romanov@nginx.com     ra->app_port = NULL;
618423Smax.romanov@nginx.com     ra->err_code = code;
619423Smax.romanov@nginx.com     ra->err_str = str;
620345Smax.romanov@nginx.com }
621345Smax.romanov@nginx.com 
622345Smax.romanov@nginx.com 
623427Smax.romanov@nginx.com nxt_inline void
624427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
625427Smax.romanov@nginx.com {
626427Smax.romanov@nginx.com     nxt_queue_insert_tail(&ra->app_port->pending_requests,
627427Smax.romanov@nginx.com                           &ra->link_port_pending);
628427Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &ra->link_app_pending);
629427Smax.romanov@nginx.com 
630427Smax.romanov@nginx.com     nxt_router_ra_inc_use(ra);
631427Smax.romanov@nginx.com 
632427Smax.romanov@nginx.com     ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout;
633427Smax.romanov@nginx.com 
634427Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream);
635427Smax.romanov@nginx.com }
636427Smax.romanov@nginx.com 
637427Smax.romanov@nginx.com 
638425Smax.romanov@nginx.com nxt_inline nxt_bool_t
639425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
640425Smax.romanov@nginx.com {
641425Smax.romanov@nginx.com     if (lnk->next != NULL) {
642425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
643425Smax.romanov@nginx.com 
644425Smax.romanov@nginx.com         lnk->next = NULL;
645425Smax.romanov@nginx.com 
646425Smax.romanov@nginx.com         return 1;
647425Smax.romanov@nginx.com     }
648425Smax.romanov@nginx.com 
649425Smax.romanov@nginx.com     return 0;
650425Smax.romanov@nginx.com }
651425Smax.romanov@nginx.com 
652425Smax.romanov@nginx.com 
653343Smax.romanov@nginx.com nxt_inline void
654343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
655343Smax.romanov@nginx.com {
656425Smax.romanov@nginx.com     int                 ra_use_delta;
657343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
658343Smax.romanov@nginx.com 
659343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
660343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
661343Smax.romanov@nginx.com 
662343Smax.romanov@nginx.com         rc->app_port = NULL;
663343Smax.romanov@nginx.com     }
664343Smax.romanov@nginx.com 
665423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &rc->msg_info, rc->stream);
666423Smax.romanov@nginx.com 
667343Smax.romanov@nginx.com     ra = rc->ra;
668343Smax.romanov@nginx.com 
669343Smax.romanov@nginx.com     if (ra != NULL) {
670343Smax.romanov@nginx.com         rc->ra = NULL;
671343Smax.romanov@nginx.com         ra->rc = NULL;
672343Smax.romanov@nginx.com 
673425Smax.romanov@nginx.com         ra_use_delta = 0;
674425Smax.romanov@nginx.com 
675343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
676343Smax.romanov@nginx.com 
677425Smax.romanov@nginx.com         if (ra->link_app_requests.next == NULL
678427Smax.romanov@nginx.com             && ra->link_port_pending.next == NULL
679427Smax.romanov@nginx.com             && ra->link_app_pending.next == NULL)
680425Smax.romanov@nginx.com         {
681425Smax.romanov@nginx.com             ra = NULL;
682343Smax.romanov@nginx.com 
683343Smax.romanov@nginx.com         } else {
684425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests);
685425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending);
686427Smax.romanov@nginx.com             nxt_queue_chk_remove(&ra->link_app_pending);
687343Smax.romanov@nginx.com         }
688343Smax.romanov@nginx.com 
689343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
690425Smax.romanov@nginx.com 
691425Smax.romanov@nginx.com         if (ra != NULL) {
692425Smax.romanov@nginx.com             nxt_router_ra_use(task, ra, ra_use_delta);
693425Smax.romanov@nginx.com         }
694343Smax.romanov@nginx.com     }
695343Smax.romanov@nginx.com 
696343Smax.romanov@nginx.com     if (rc->app != NULL) {
697343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
698343Smax.romanov@nginx.com 
699343Smax.romanov@nginx.com         rc->app = NULL;
700343Smax.romanov@nginx.com     }
701343Smax.romanov@nginx.com 
702346Smax.romanov@nginx.com     if (rc->ap != NULL) {
703346Smax.romanov@nginx.com         nxt_app_http_req_done(task, rc->ap);
704346Smax.romanov@nginx.com 
705346Smax.romanov@nginx.com         rc->ap = NULL;
706346Smax.romanov@nginx.com     }
707343Smax.romanov@nginx.com }
708343Smax.romanov@nginx.com 
709343Smax.romanov@nginx.com 
710141Smax.romanov@nginx.com void
711141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
712141Smax.romanov@nginx.com {
713141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
714141Smax.romanov@nginx.com 
715192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
716141Smax.romanov@nginx.com         return;
717141Smax.romanov@nginx.com     }
718141Smax.romanov@nginx.com 
719426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
720426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
721347Smax.romanov@nginx.com     {
722192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
723141Smax.romanov@nginx.com     }
724192Smax.romanov@nginx.com 
725192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
726141Smax.romanov@nginx.com }
727141Smax.romanov@nginx.com 
728141Smax.romanov@nginx.com 
729139Sigor@sysoev.ru void
730139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
731115Sigor@sysoev.ru {
732198Sigor@sysoev.ru     nxt_int_t               ret;
733139Sigor@sysoev.ru     nxt_buf_t               *b;
734139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
735139Sigor@sysoev.ru 
736139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
737139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
738139Sigor@sysoev.ru         return;
73953Sigor@sysoev.ru     }
74053Sigor@sysoev.ru 
741494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
742423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
743493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
744423Smax.romanov@nginx.com 
745352Smax.romanov@nginx.com     b = nxt_buf_chk_make_plain(tmcf->conf->mem_pool, msg->buf, msg->size);
746352Smax.romanov@nginx.com 
747352Smax.romanov@nginx.com     nxt_assert(b != NULL);
748352Smax.romanov@nginx.com 
749139Sigor@sysoev.ru     tmcf->conf->router = nxt_router;
750139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
751139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
752198Sigor@sysoev.ru                                        msg->port_msg.pid,
753198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
754198Sigor@sysoev.ru 
755198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
756198Sigor@sysoev.ru 
757198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
758198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
759198Sigor@sysoev.ru 
760198Sigor@sysoev.ru     } else {
761198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
762139Sigor@sysoev.ru     }
76353Sigor@sysoev.ru }
76453Sigor@sysoev.ru 
76553Sigor@sysoev.ru 
766347Smax.romanov@nginx.com static void
767507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
768507Smax.romanov@nginx.com     void *data)
769347Smax.romanov@nginx.com {
770347Smax.romanov@nginx.com     union {
771347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
772347Smax.romanov@nginx.com         void       *data;
773347Smax.romanov@nginx.com     } u;
774347Smax.romanov@nginx.com 
775347Smax.romanov@nginx.com     u.data = data;
776347Smax.romanov@nginx.com 
777347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
778347Smax.romanov@nginx.com }
779347Smax.romanov@nginx.com 
780347Smax.romanov@nginx.com 
781192Smax.romanov@nginx.com void
782192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
783192Smax.romanov@nginx.com {
784347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
785318Smax.romanov@nginx.com 
786192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
787192Smax.romanov@nginx.com 
788192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
789192Smax.romanov@nginx.com         return;
790192Smax.romanov@nginx.com     }
791192Smax.romanov@nginx.com 
792318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
793318Smax.romanov@nginx.com     {
794507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
795347Smax.romanov@nginx.com                       msg->u.data);
796318Smax.romanov@nginx.com     }
797318Smax.romanov@nginx.com     nxt_queue_loop;
798318Smax.romanov@nginx.com 
799192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
800192Smax.romanov@nginx.com 
801192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
802192Smax.romanov@nginx.com }
803192Smax.romanov@nginx.com 
804192Smax.romanov@nginx.com 
80553Sigor@sysoev.ru static nxt_router_temp_conf_t *
806139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
80753Sigor@sysoev.ru {
80865Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
80953Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
81053Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
81153Sigor@sysoev.ru 
81265Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
81353Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
81453Sigor@sysoev.ru         return NULL;
81553Sigor@sysoev.ru     }
81653Sigor@sysoev.ru 
81765Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
81853Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
81953Sigor@sysoev.ru         goto fail;
82053Sigor@sysoev.ru     }
82153Sigor@sysoev.ru 
82253Sigor@sysoev.ru     rtcf->mem_pool = mp;
82353Sigor@sysoev.ru 
82465Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
82553Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
82653Sigor@sysoev.ru         goto fail;
82753Sigor@sysoev.ru     }
82853Sigor@sysoev.ru 
82965Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
83053Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
83153Sigor@sysoev.ru         goto temp_fail;
83253Sigor@sysoev.ru     }
83353Sigor@sysoev.ru 
83453Sigor@sysoev.ru     tmcf->mem_pool = tmp;
83553Sigor@sysoev.ru     tmcf->conf = rtcf;
836139Sigor@sysoev.ru     tmcf->count = 1;
837139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
83853Sigor@sysoev.ru 
83953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
84053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
84153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
84253Sigor@sysoev.ru         goto temp_fail;
84353Sigor@sysoev.ru     }
84453Sigor@sysoev.ru 
84553Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
84653Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
84753Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
84853Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
84953Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
850416Smax.romanov@nginx.com 
851133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
852133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
85353Sigor@sysoev.ru 
85453Sigor@sysoev.ru     return tmcf;
85553Sigor@sysoev.ru 
85653Sigor@sysoev.ru temp_fail:
85753Sigor@sysoev.ru 
85865Sigor@sysoev.ru     nxt_mp_destroy(tmp);
85953Sigor@sysoev.ru 
86053Sigor@sysoev.ru fail:
86153Sigor@sysoev.ru 
86265Sigor@sysoev.ru     nxt_mp_destroy(mp);
86353Sigor@sysoev.ru 
86453Sigor@sysoev.ru     return NULL;
86553Sigor@sysoev.ru }
86653Sigor@sysoev.ru 
86753Sigor@sysoev.ru 
868507Smax.romanov@nginx.com nxt_inline nxt_bool_t
869507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
870507Smax.romanov@nginx.com {
871507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
872507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
873507Smax.romanov@nginx.com }
874507Smax.romanov@nginx.com 
875507Smax.romanov@nginx.com 
876507Smax.romanov@nginx.com nxt_inline nxt_bool_t
877507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
878507Smax.romanov@nginx.com {
879507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
880507Smax.romanov@nginx.com             < app->spare_processes;
881507Smax.romanov@nginx.com }
882507Smax.romanov@nginx.com 
883507Smax.romanov@nginx.com 
884198Sigor@sysoev.ru static void
885198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
886139Sigor@sysoev.ru {
887139Sigor@sysoev.ru     nxt_int_t                    ret;
888507Smax.romanov@nginx.com     nxt_app_t                    *app;
889139Sigor@sysoev.ru     nxt_router_t                 *router;
890139Sigor@sysoev.ru     nxt_runtime_t                *rt;
891198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
892198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
893198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
894139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
895139Sigor@sysoev.ru 
896198Sigor@sysoev.ru     tmcf = obj;
897198Sigor@sysoev.ru 
898198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
899198Sigor@sysoev.ru 
900198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
901198Sigor@sysoev.ru         nxt_queue_remove(qlk);
902198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
903198Sigor@sysoev.ru 
904198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
905198Sigor@sysoev.ru 
906198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
907198Sigor@sysoev.ru 
908198Sigor@sysoev.ru         return;
909139Sigor@sysoev.ru     }
910139Sigor@sysoev.ru 
911507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
912507Smax.romanov@nginx.com 
913507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
914507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
915507Smax.romanov@nginx.com             return;
916507Smax.romanov@nginx.com         }
917507Smax.romanov@nginx.com 
918507Smax.romanov@nginx.com     } nxt_queue_loop;
919507Smax.romanov@nginx.com 
920139Sigor@sysoev.ru     rt = task->thread->runtime;
921139Sigor@sysoev.ru 
922139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
923139Sigor@sysoev.ru 
924198Sigor@sysoev.ru     router = tmcf->conf->router;
925198Sigor@sysoev.ru 
926139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
927139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
928198Sigor@sysoev.ru         goto fail;
929139Sigor@sysoev.ru     }
930139Sigor@sysoev.ru 
931139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
932139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
933198Sigor@sysoev.ru         goto fail;
934139Sigor@sysoev.ru     }
935139Sigor@sysoev.ru 
936343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
937139Sigor@sysoev.ru 
938315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
939139Sigor@sysoev.ru 
940139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
941139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
942139Sigor@sysoev.ru 
943198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
944198Sigor@sysoev.ru 
945198Sigor@sysoev.ru     return;
946198Sigor@sysoev.ru 
947198Sigor@sysoev.ru fail:
948198Sigor@sysoev.ru 
949198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
950198Sigor@sysoev.ru 
951198Sigor@sysoev.ru     return;
952139Sigor@sysoev.ru }
953139Sigor@sysoev.ru 
954139Sigor@sysoev.ru 
955139Sigor@sysoev.ru static void
956139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
957139Sigor@sysoev.ru {
958153Sigor@sysoev.ru     nxt_joint_job_t  *job;
959153Sigor@sysoev.ru 
960153Sigor@sysoev.ru     job = obj;
961153Sigor@sysoev.ru 
962198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
963139Sigor@sysoev.ru }
964139Sigor@sysoev.ru 
965139Sigor@sysoev.ru 
966139Sigor@sysoev.ru static void
967198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
968139Sigor@sysoev.ru {
969139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
970139Sigor@sysoev.ru 
971139Sigor@sysoev.ru     if (--tmcf->count == 0) {
972193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
973139Sigor@sysoev.ru     }
974139Sigor@sysoev.ru }
975139Sigor@sysoev.ru 
976139Sigor@sysoev.ru 
977139Sigor@sysoev.ru static void
978139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
979139Sigor@sysoev.ru {
980507Smax.romanov@nginx.com     nxt_app_t          *app;
981148Sigor@sysoev.ru     nxt_socket_t       s;
982149Sigor@sysoev.ru     nxt_router_t       *router;
983148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
984148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
985148Sigor@sysoev.ru 
986198Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf");
987198Sigor@sysoev.ru 
988148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
989148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
990148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
991148Sigor@sysoev.ru     {
992148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
993359Sigor@sysoev.ru         s = skcf->listen->socket;
994148Sigor@sysoev.ru 
995148Sigor@sysoev.ru         if (s != -1) {
996148Sigor@sysoev.ru             nxt_socket_close(task, s);
997148Sigor@sysoev.ru         }
998148Sigor@sysoev.ru 
999359Sigor@sysoev.ru         nxt_free(skcf->listen);
1000148Sigor@sysoev.ru     }
1001148Sigor@sysoev.ru 
1002507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1003507Smax.romanov@nginx.com 
1004507Smax.romanov@nginx.com         nxt_router_app_quit(task, app);
1005507Smax.romanov@nginx.com 
1006507Smax.romanov@nginx.com     } nxt_queue_loop;
1007507Smax.romanov@nginx.com 
1008149Sigor@sysoev.ru     router = tmcf->conf->router;
1009149Sigor@sysoev.ru 
1010149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1011149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1012149Sigor@sysoev.ru 
1013416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1014416Smax.romanov@nginx.com 
1015148Sigor@sysoev.ru     // TODO: new engines and threads
1016148Sigor@sysoev.ru 
1017139Sigor@sysoev.ru     nxt_mp_destroy(tmcf->conf->mem_pool);
1018139Sigor@sysoev.ru 
1019193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1020139Sigor@sysoev.ru }
1021139Sigor@sysoev.ru 
1022139Sigor@sysoev.ru 
1023139Sigor@sysoev.ru static void
1024139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1025193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1026139Sigor@sysoev.ru {
1027193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1028139Sigor@sysoev.ru }
1029139Sigor@sysoev.ru 
1030139Sigor@sysoev.ru 
1031115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1032115Sigor@sysoev.ru     {
1033133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1034115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1035115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1036115Sigor@sysoev.ru     },
1037115Sigor@sysoev.ru };
1038115Sigor@sysoev.ru 
1039115Sigor@sysoev.ru 
1040133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1041115Sigor@sysoev.ru     {
1042133Sigor@sysoev.ru         nxt_string("type"),
1043115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1044133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1045115Sigor@sysoev.ru     },
1046115Sigor@sysoev.ru 
1047115Sigor@sysoev.ru     {
1048507Smax.romanov@nginx.com         nxt_string("limits"),
1049507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1050507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1051133Sigor@sysoev.ru     },
1052318Smax.romanov@nginx.com 
1053318Smax.romanov@nginx.com     {
1054507Smax.romanov@nginx.com         nxt_string("processes"),
1055507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1056507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1057507Smax.romanov@nginx.com     },
1058507Smax.romanov@nginx.com 
1059507Smax.romanov@nginx.com     {
1060507Smax.romanov@nginx.com         nxt_string("processes"),
1061318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1062507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1063318Smax.romanov@nginx.com     },
1064318Smax.romanov@nginx.com };
1065318Smax.romanov@nginx.com 
1066318Smax.romanov@nginx.com 
1067318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1068318Smax.romanov@nginx.com     {
1069318Smax.romanov@nginx.com         nxt_string("timeout"),
1070318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1071318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1072318Smax.romanov@nginx.com     },
1073318Smax.romanov@nginx.com 
1074318Smax.romanov@nginx.com     {
1075427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1076427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1077427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1078427Smax.romanov@nginx.com     },
1079427Smax.romanov@nginx.com 
1080427Smax.romanov@nginx.com     {
1081318Smax.romanov@nginx.com         nxt_string("requests"),
1082318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1083318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1084318Smax.romanov@nginx.com     },
1085133Sigor@sysoev.ru };
1086133Sigor@sysoev.ru 
1087133Sigor@sysoev.ru 
1088507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1089507Smax.romanov@nginx.com     {
1090507Smax.romanov@nginx.com         nxt_string("spare"),
1091507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1092507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1093507Smax.romanov@nginx.com     },
1094507Smax.romanov@nginx.com 
1095507Smax.romanov@nginx.com     {
1096507Smax.romanov@nginx.com         nxt_string("max"),
1097507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1098507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1099507Smax.romanov@nginx.com     },
1100507Smax.romanov@nginx.com 
1101507Smax.romanov@nginx.com     {
1102507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1103507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1104507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1105507Smax.romanov@nginx.com     },
1106507Smax.romanov@nginx.com };
1107507Smax.romanov@nginx.com 
1108507Smax.romanov@nginx.com 
1109133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1110133Sigor@sysoev.ru     {
1111133Sigor@sysoev.ru         nxt_string("application"),
1112133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1113133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1114115Sigor@sysoev.ru     },
1115115Sigor@sysoev.ru };
1116115Sigor@sysoev.ru 
1117115Sigor@sysoev.ru 
1118115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1119115Sigor@sysoev.ru     {
1120115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1121115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1122115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1123115Sigor@sysoev.ru     },
1124115Sigor@sysoev.ru 
1125115Sigor@sysoev.ru     {
1126115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1127115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1128115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1129115Sigor@sysoev.ru     },
1130115Sigor@sysoev.ru 
1131115Sigor@sysoev.ru     {
1132206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1133206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1134206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1135206Smax.romanov@nginx.com     },
1136206Smax.romanov@nginx.com 
1137206Smax.romanov@nginx.com     {
1138206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1139206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1140206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1141206Smax.romanov@nginx.com     },
1142206Smax.romanov@nginx.com 
1143206Smax.romanov@nginx.com     {
1144206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1145206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1146206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1147206Smax.romanov@nginx.com     },
1148206Smax.romanov@nginx.com 
1149206Smax.romanov@nginx.com     {
1150431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1151431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1152431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1153431Sigor@sysoev.ru     },
1154431Sigor@sysoev.ru 
1155431Sigor@sysoev.ru     {
1156115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1157115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1158115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1159115Sigor@sysoev.ru     },
1160206Smax.romanov@nginx.com 
1161206Smax.romanov@nginx.com     {
1162206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1163206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1164206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1165206Smax.romanov@nginx.com     },
1166431Sigor@sysoev.ru 
1167431Sigor@sysoev.ru     {
1168431Sigor@sysoev.ru         nxt_string("send_timeout"),
1169431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1170431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1171431Sigor@sysoev.ru     },
1172115Sigor@sysoev.ru };
1173115Sigor@sysoev.ru 
1174115Sigor@sysoev.ru 
117553Sigor@sysoev.ru static nxt_int_t
1176115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1177115Sigor@sysoev.ru     u_char *start, u_char *end)
117853Sigor@sysoev.ru {
1179133Sigor@sysoev.ru     u_char                      *p;
1180133Sigor@sysoev.ru     size_t                      size;
1181115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1182115Sigor@sysoev.ru     uint32_t                    next;
1183115Sigor@sysoev.ru     nxt_int_t                   ret;
1184115Sigor@sysoev.ru     nxt_str_t                   name;
1185133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1186359Sigor@sysoev.ru     nxt_router_t                *router;
1187133Sigor@sysoev.ru     nxt_conf_value_t            *conf, *http;
1188133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1189133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1190115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1191507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1192216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1193133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1194115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1195115Sigor@sysoev.ru 
1196115Sigor@sysoev.ru     static nxt_str_t  http_path = nxt_string("/http");
1197133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1198115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1199115Sigor@sysoev.ru 
1200208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1201115Sigor@sysoev.ru     if (conf == NULL) {
1202115Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
1203115Sigor@sysoev.ru         return NXT_ERROR;
1204115Sigor@sysoev.ru     }
1205115Sigor@sysoev.ru 
1206213Svbart@nginx.com     mp = tmcf->conf->mem_pool;
1207213Svbart@nginx.com 
1208213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1209136Svbart@nginx.com                               nxt_nitems(nxt_router_conf), tmcf->conf);
1210115Sigor@sysoev.ru     if (ret != NXT_OK) {
1211133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
1212115Sigor@sysoev.ru         return NXT_ERROR;
1213115Sigor@sysoev.ru     }
1214115Sigor@sysoev.ru 
1215117Sigor@sysoev.ru     if (tmcf->conf->threads == 0) {
1216117Sigor@sysoev.ru         tmcf->conf->threads = nxt_ncpu;
1217117Sigor@sysoev.ru     }
1218117Sigor@sysoev.ru 
1219133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1220133Sigor@sysoev.ru     if (applications == NULL) {
1221133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block");
1222115Sigor@sysoev.ru         return NXT_ERROR;
1223115Sigor@sysoev.ru     }
1224115Sigor@sysoev.ru 
1225359Sigor@sysoev.ru     router = tmcf->conf->router;
1226359Sigor@sysoev.ru 
1227133Sigor@sysoev.ru     next = 0;
1228133Sigor@sysoev.ru 
1229133Sigor@sysoev.ru     for ( ;; ) {
1230133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1231133Sigor@sysoev.ru         if (application == NULL) {
1232133Sigor@sysoev.ru             break;
1233133Sigor@sysoev.ru         }
1234133Sigor@sysoev.ru 
1235133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1236133Sigor@sysoev.ru 
1237144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1238144Smax.romanov@nginx.com 
1239144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1240133Sigor@sysoev.ru         if (app == NULL) {
1241133Sigor@sysoev.ru             goto fail;
1242133Sigor@sysoev.ru         }
1243133Sigor@sysoev.ru 
1244144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1245144Smax.romanov@nginx.com 
1246144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1247144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1248133Sigor@sysoev.ru 
1249133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1250133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1251133Sigor@sysoev.ru 
1252144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1253144Smax.romanov@nginx.com 
1254133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1255133Sigor@sysoev.ru 
1256359Sigor@sysoev.ru         prev = nxt_router_app_find(&router->apps, &name);
1257133Sigor@sysoev.ru 
1258133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1259133Sigor@sysoev.ru             nxt_free(app);
1260133Sigor@sysoev.ru 
1261133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1262133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1263133Sigor@sysoev.ru             continue;
1264133Sigor@sysoev.ru         }
1265133Sigor@sysoev.ru 
1266507Smax.romanov@nginx.com         apcf.processes = 1;
1267507Smax.romanov@nginx.com         apcf.max_processes = 1;
1268507Smax.romanov@nginx.com         apcf.spare_processes = 1;
1269318Smax.romanov@nginx.com         apcf.timeout = 0;
1270427Smax.romanov@nginx.com         apcf.res_timeout = 1000;
1271507Smax.romanov@nginx.com         apcf.idle_timeout = 15000;
1272318Smax.romanov@nginx.com         apcf.requests = 0;
1273318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1274507Smax.romanov@nginx.com         apcf.processes_value = NULL;
1275263Smax.romanov@nginx.com 
1276213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1277136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1278133Sigor@sysoev.ru         if (ret != NXT_OK) {
1279133Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "application map error");
1280133Sigor@sysoev.ru             goto app_fail;
1281133Sigor@sysoev.ru         }
1282115Sigor@sysoev.ru 
1283318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1284318Smax.romanov@nginx.com 
1285318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1286318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits is not object");
1287318Smax.romanov@nginx.com                 goto app_fail;
1288318Smax.romanov@nginx.com             }
1289318Smax.romanov@nginx.com 
1290318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1291318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1292318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1293318Smax.romanov@nginx.com                                       &apcf);
1294318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1295318Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application limits map error");
1296318Smax.romanov@nginx.com                 goto app_fail;
1297318Smax.romanov@nginx.com             }
1298318Smax.romanov@nginx.com         }
1299318Smax.romanov@nginx.com 
1300507Smax.romanov@nginx.com         if (apcf.processes_value != NULL
1301507Smax.romanov@nginx.com             && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1302507Smax.romanov@nginx.com         {
1303507Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.processes_value,
1304507Smax.romanov@nginx.com                                       nxt_router_app_processes_conf,
1305507Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_processes_conf),
1306507Smax.romanov@nginx.com                                       &apcf);
1307507Smax.romanov@nginx.com             if (ret != NXT_OK) {
1308507Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_CRIT, "application processes map error");
1309507Smax.romanov@nginx.com                 goto app_fail;
1310507Smax.romanov@nginx.com             }
1311507Smax.romanov@nginx.com 
1312507Smax.romanov@nginx.com         } else {
1313507Smax.romanov@nginx.com             apcf.max_processes = apcf.processes;
1314507Smax.romanov@nginx.com             apcf.spare_processes = apcf.processes;
1315507Smax.romanov@nginx.com         }
1316507Smax.romanov@nginx.com 
1317133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1318507Smax.romanov@nginx.com         nxt_debug(task, "application processes: %D", apcf.processes);
1319507Smax.romanov@nginx.com         nxt_debug(task, "application request timeout: %M", apcf.timeout);
1320507Smax.romanov@nginx.com         nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout);
1321318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1322133Sigor@sysoev.ru 
1323216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1324216Sigor@sysoev.ru 
1325216Sigor@sysoev.ru         if (lang == NULL) {
1326141Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"",
1327141Smax.romanov@nginx.com                     &apcf.type);
1328141Smax.romanov@nginx.com             goto app_fail;
1329141Smax.romanov@nginx.com         }
1330141Smax.romanov@nginx.com 
1331216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1332216Sigor@sysoev.ru 
1333133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1334133Sigor@sysoev.ru         if (ret != NXT_OK) {
1335133Sigor@sysoev.ru             goto app_fail;
1336133Sigor@sysoev.ru         }
1337133Sigor@sysoev.ru 
1338141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1339507Smax.romanov@nginx.com         nxt_queue_init(&app->spare_ports);
1340507Smax.romanov@nginx.com         nxt_queue_init(&app->idle_ports);
1341141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1342427Smax.romanov@nginx.com         nxt_queue_init(&app->pending);
1343141Smax.romanov@nginx.com 
1344144Smax.romanov@nginx.com         app->name.length = name.length;
1345144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1346144Smax.romanov@nginx.com 
1347356Svbart@nginx.com         app->type = lang->type;
1348507Smax.romanov@nginx.com         app->max_processes = apcf.max_processes;
1349507Smax.romanov@nginx.com         app->spare_processes = apcf.spare_processes;
1350507Smax.romanov@nginx.com         app->max_pending_processes = apcf.spare_processes
1351507Smax.romanov@nginx.com                                       ? apcf.spare_processes : 1;
1352318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1353427Smax.romanov@nginx.com         app->res_timeout = apcf.res_timeout * 1000000;
1354507Smax.romanov@nginx.com         app->idle_timeout = apcf.idle_timeout;
1355133Sigor@sysoev.ru         app->live = 1;
1356343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1357428Smax.romanov@nginx.com         app->max_requests = apcf.requests;
1358356Svbart@nginx.com         app->prepare_msg = nxt_app_prepare_msg[lang->type];
1359133Sigor@sysoev.ru 
1360507Smax.romanov@nginx.com         engine = task->thread->engine;
1361507Smax.romanov@nginx.com 
1362507Smax.romanov@nginx.com         app->engine = engine;
1363507Smax.romanov@nginx.com 
1364507Smax.romanov@nginx.com         app->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION;
1365507Smax.romanov@nginx.com         app->idle_timer.work_queue = &engine->fast_work_queue;
1366507Smax.romanov@nginx.com         app->idle_timer.handler = nxt_router_app_idle_timeout;
1367507Smax.romanov@nginx.com         app->idle_timer.task = &engine->task;
1368507Smax.romanov@nginx.com         app->idle_timer.log = app->idle_timer.task->log;
1369507Smax.romanov@nginx.com 
1370507Smax.romanov@nginx.com         app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1371507Smax.romanov@nginx.com         app->adjust_idle_work.task = &engine->task;
1372507Smax.romanov@nginx.com         app->adjust_idle_work.obj = app;
1373507Smax.romanov@nginx.com 
1374133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1375343Smax.romanov@nginx.com 
1376343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1377133Sigor@sysoev.ru     }
1378133Sigor@sysoev.ru 
1379133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1380133Sigor@sysoev.ru #if 0
1381133Sigor@sysoev.ru     if (http == NULL) {
1382133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"http\" block");
1383133Sigor@sysoev.ru         return NXT_ERROR;
1384133Sigor@sysoev.ru     }
1385133Sigor@sysoev.ru #endif
1386133Sigor@sysoev.ru 
1387133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1388115Sigor@sysoev.ru     if (listeners == NULL) {
1389133Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block");
1390115Sigor@sysoev.ru         return NXT_ERROR;
1391115Sigor@sysoev.ru     }
139253Sigor@sysoev.ru 
1393133Sigor@sysoev.ru     next = 0;
139453Sigor@sysoev.ru 
1395115Sigor@sysoev.ru     for ( ;; ) {
1396115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1397115Sigor@sysoev.ru         if (listener == NULL) {
1398115Sigor@sysoev.ru             break;
1399115Sigor@sysoev.ru         }
140053Sigor@sysoev.ru 
1401359Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, tmcf, &name);
1402115Sigor@sysoev.ru         if (skcf == NULL) {
1403133Sigor@sysoev.ru             goto fail;
1404115Sigor@sysoev.ru         }
140553Sigor@sysoev.ru 
1406213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1407136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1408115Sigor@sysoev.ru         if (ret != NXT_OK) {
1409115Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "listener map error");
1410133Sigor@sysoev.ru             goto fail;
1411115Sigor@sysoev.ru         }
141253Sigor@sysoev.ru 
1413133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1414133Sigor@sysoev.ru 
1415133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1416133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1417133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1418206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1419206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1420206Smax.romanov@nginx.com         skcf->max_body_size = 2 * 1024 * 1024;
1421431Sigor@sysoev.ru         skcf->idle_timeout = 65000;
1422133Sigor@sysoev.ru         skcf->header_read_timeout = 5000;
1423206Smax.romanov@nginx.com         skcf->body_read_timeout = 5000;
1424431Sigor@sysoev.ru         skcf->send_timeout = 5000;
142553Sigor@sysoev.ru 
1426133Sigor@sysoev.ru         if (http != NULL) {
1427213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1428136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1429133Sigor@sysoev.ru             if (ret != NXT_OK) {
1430133Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "http map error");
1431133Sigor@sysoev.ru                 goto fail;
1432133Sigor@sysoev.ru             }
1433115Sigor@sysoev.ru         }
1434115Sigor@sysoev.ru 
1435431Sigor@sysoev.ru         skcf->listen->handler = nxt_http_conn_init;
1436115Sigor@sysoev.ru         skcf->router_conf = tmcf->conf;
1437160Sigor@sysoev.ru         skcf->router_conf->count++;
1438133Sigor@sysoev.ru         skcf->application = nxt_router_listener_application(tmcf,
1439133Sigor@sysoev.ru                                                             &lscf.application);
1440115Sigor@sysoev.ru     }
144153Sigor@sysoev.ru 
1442359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1443359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1444198Sigor@sysoev.ru 
144553Sigor@sysoev.ru     return NXT_OK;
1446133Sigor@sysoev.ru 
1447133Sigor@sysoev.ru app_fail:
1448133Sigor@sysoev.ru 
1449133Sigor@sysoev.ru     nxt_free(app);
1450133Sigor@sysoev.ru 
1451133Sigor@sysoev.ru fail:
1452133Sigor@sysoev.ru 
1453141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1454141Smax.romanov@nginx.com 
1455141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1456133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1457133Sigor@sysoev.ru         nxt_free(app);
1458141Smax.romanov@nginx.com 
1459141Smax.romanov@nginx.com     } nxt_queue_loop;
1460133Sigor@sysoev.ru 
1461133Sigor@sysoev.ru     return NXT_ERROR;
1462133Sigor@sysoev.ru }
1463133Sigor@sysoev.ru 
1464133Sigor@sysoev.ru 
1465133Sigor@sysoev.ru static nxt_app_t *
1466133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1467133Sigor@sysoev.ru {
1468141Smax.romanov@nginx.com     nxt_app_t  *app;
1469141Smax.romanov@nginx.com 
1470141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1471133Sigor@sysoev.ru 
1472133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1473133Sigor@sysoev.ru             return app;
1474133Sigor@sysoev.ru         }
1475141Smax.romanov@nginx.com 
1476141Smax.romanov@nginx.com     } nxt_queue_loop;
1477133Sigor@sysoev.ru 
1478133Sigor@sysoev.ru     return NULL;
1479133Sigor@sysoev.ru }
1480133Sigor@sysoev.ru 
1481133Sigor@sysoev.ru 
1482133Sigor@sysoev.ru static nxt_app_t *
1483133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1484133Sigor@sysoev.ru {
1485133Sigor@sysoev.ru     nxt_app_t  *app;
1486133Sigor@sysoev.ru 
1487133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1488133Sigor@sysoev.ru 
1489133Sigor@sysoev.ru     if (app == NULL) {
1490134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1491133Sigor@sysoev.ru     }
1492133Sigor@sysoev.ru 
1493133Sigor@sysoev.ru     return app;
149453Sigor@sysoev.ru }
149553Sigor@sysoev.ru 
149653Sigor@sysoev.ru 
149753Sigor@sysoev.ru static nxt_socket_conf_t *
1498359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1499359Sigor@sysoev.ru     nxt_str_t *name)
150053Sigor@sysoev.ru {
1501359Sigor@sysoev.ru     size_t               size;
1502359Sigor@sysoev.ru     nxt_int_t            ret;
1503359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1504359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1505359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1506359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1507359Sigor@sysoev.ru 
1508359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1509359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1510359Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", name);
1511359Sigor@sysoev.ru         return NULL;
1512359Sigor@sysoev.ru     }
1513359Sigor@sysoev.ru 
1514359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1515359Sigor@sysoev.ru 
1516359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1517493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1518359Sigor@sysoev.ru 
1519359Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->conf->mem_pool, sizeof(nxt_socket_conf_t));
1520163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
152153Sigor@sysoev.ru         return NULL;
152253Sigor@sysoev.ru     }
152353Sigor@sysoev.ru 
1524359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1525359Sigor@sysoev.ru 
1526359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1527359Sigor@sysoev.ru 
1528359Sigor@sysoev.ru     if (ret != NXT_OK) {
1529359Sigor@sysoev.ru 
1530359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1531359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1532359Sigor@sysoev.ru             return NULL;
1533359Sigor@sysoev.ru         }
1534359Sigor@sysoev.ru 
1535359Sigor@sysoev.ru         skcf->listen = ls;
1536359Sigor@sysoev.ru 
1537359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1538359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1539359Sigor@sysoev.ru 
1540359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1541359Sigor@sysoev.ru 
1542359Sigor@sysoev.ru         ls->socket = -1;
1543359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1544359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1545359Sigor@sysoev.ru         ls->read_after_accept = 1;
1546359Sigor@sysoev.ru     }
1547359Sigor@sysoev.ru 
1548359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1549359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1550359Sigor@sysoev.ru     case AF_UNIX:
1551359Sigor@sysoev.ru         wildcard = 0;
1552359Sigor@sysoev.ru         break;
1553359Sigor@sysoev.ru #endif
1554359Sigor@sysoev.ru #if (NXT_INET6)
1555359Sigor@sysoev.ru     case AF_INET6:
1556359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1557359Sigor@sysoev.ru         break;
1558359Sigor@sysoev.ru #endif
1559359Sigor@sysoev.ru     case AF_INET:
1560359Sigor@sysoev.ru     default:
1561359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1562359Sigor@sysoev.ru         break;
1563359Sigor@sysoev.ru     }
1564359Sigor@sysoev.ru 
1565359Sigor@sysoev.ru     if (!wildcard) {
1566359Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->conf->mem_pool, size);
1567359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1568359Sigor@sysoev.ru             return NULL;
1569359Sigor@sysoev.ru         }
1570359Sigor@sysoev.ru 
1571359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1572359Sigor@sysoev.ru     }
1573163Smax.romanov@nginx.com 
1574163Smax.romanov@nginx.com     return skcf;
157553Sigor@sysoev.ru }
157653Sigor@sysoev.ru 
157753Sigor@sysoev.ru 
1578359Sigor@sysoev.ru static nxt_int_t
1579359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1580359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
158153Sigor@sysoev.ru {
1582359Sigor@sysoev.ru     nxt_router_t       *router;
1583359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1584359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1585359Sigor@sysoev.ru 
1586359Sigor@sysoev.ru     router = tmcf->conf->router;
1587359Sigor@sysoev.ru 
1588359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
1589359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
1590359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
159153Sigor@sysoev.ru     {
1592359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1593359Sigor@sysoev.ru 
1594359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
1595359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
1596359Sigor@sysoev.ru 
1597359Sigor@sysoev.ru             nxt_queue_remove(qlk);
1598359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
1599359Sigor@sysoev.ru 
1600359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
1601359Sigor@sysoev.ru 
1602359Sigor@sysoev.ru             return NXT_OK;
160353Sigor@sysoev.ru         }
160453Sigor@sysoev.ru     }
160553Sigor@sysoev.ru 
1606359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
1607359Sigor@sysoev.ru 
1608359Sigor@sysoev.ru     return NXT_DECLINED;
160953Sigor@sysoev.ru }
161053Sigor@sysoev.ru 
161153Sigor@sysoev.ru 
1612198Sigor@sysoev.ru static void
1613198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1614198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1615198Sigor@sysoev.ru {
1616358Sigor@sysoev.ru     size_t            size;
1617198Sigor@sysoev.ru     uint32_t          stream;
1618198Sigor@sysoev.ru     nxt_buf_t         *b;
1619198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1620198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1621198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1622198Sigor@sysoev.ru 
1623198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1624198Sigor@sysoev.ru     if (rpc == NULL) {
1625198Sigor@sysoev.ru         goto fail;
1626198Sigor@sysoev.ru     }
1627198Sigor@sysoev.ru 
1628198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1629198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1630198Sigor@sysoev.ru 
1631359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
1632358Sigor@sysoev.ru 
1633358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1634198Sigor@sysoev.ru     if (b == NULL) {
1635198Sigor@sysoev.ru         goto fail;
1636198Sigor@sysoev.ru     }
1637198Sigor@sysoev.ru 
1638359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
1639198Sigor@sysoev.ru 
1640198Sigor@sysoev.ru     rt = task->thread->runtime;
1641240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1642198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1643198Sigor@sysoev.ru 
1644198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1645198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1646198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1647198Sigor@sysoev.ru                                            main_port->pid, rpc);
1648198Sigor@sysoev.ru     if (stream == 0) {
1649198Sigor@sysoev.ru         goto fail;
1650198Sigor@sysoev.ru     }
1651198Sigor@sysoev.ru 
1652198Sigor@sysoev.ru     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1653198Sigor@sysoev.ru                           stream, router_port->id, b);
1654198Sigor@sysoev.ru 
1655198Sigor@sysoev.ru     return;
1656198Sigor@sysoev.ru 
1657198Sigor@sysoev.ru fail:
1658198Sigor@sysoev.ru 
1659198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1660198Sigor@sysoev.ru }
1661198Sigor@sysoev.ru 
1662198Sigor@sysoev.ru 
1663198Sigor@sysoev.ru static void
1664198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1665198Sigor@sysoev.ru     void *data)
166653Sigor@sysoev.ru {
1667359Sigor@sysoev.ru     nxt_int_t         ret;
1668359Sigor@sysoev.ru     nxt_socket_t      s;
1669359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
167053Sigor@sysoev.ru 
1671198Sigor@sysoev.ru     rpc = data;
1672198Sigor@sysoev.ru 
1673198Sigor@sysoev.ru     s = msg->fd;
1674198Sigor@sysoev.ru 
1675198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1676198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1677198Sigor@sysoev.ru         goto fail;
167853Sigor@sysoev.ru     }
167953Sigor@sysoev.ru 
1680359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
1681198Sigor@sysoev.ru 
1682198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1683198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1684198Sigor@sysoev.ru         goto fail;
1685198Sigor@sysoev.ru     }
1686198Sigor@sysoev.ru 
1687359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
1688198Sigor@sysoev.ru 
1689198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1690198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1691198Sigor@sysoev.ru 
1692198Sigor@sysoev.ru     return;
1693148Sigor@sysoev.ru 
1694148Sigor@sysoev.ru fail:
1695148Sigor@sysoev.ru 
1696148Sigor@sysoev.ru     nxt_socket_close(task, s);
1697148Sigor@sysoev.ru 
1698198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1699198Sigor@sysoev.ru }
1700198Sigor@sysoev.ru 
1701198Sigor@sysoev.ru 
1702198Sigor@sysoev.ru static void
1703198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1704198Sigor@sysoev.ru     void *data)
1705198Sigor@sysoev.ru {
1706198Sigor@sysoev.ru     u_char                  *p;
1707198Sigor@sysoev.ru     size_t                  size;
1708198Sigor@sysoev.ru     uint8_t                 error;
1709198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1710198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1711198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1712198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1713198Sigor@sysoev.ru 
1714198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1715198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1716198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1717198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1718198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1719198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1720198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1721198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1722198Sigor@sysoev.ru     };
1723198Sigor@sysoev.ru 
1724198Sigor@sysoev.ru     rpc = data;
1725359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
1726352Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
1727352Smax.romanov@nginx.com 
1728352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
1729352Smax.romanov@nginx.com 
1730352Smax.romanov@nginx.com     nxt_assert(in != NULL);
1731352Smax.romanov@nginx.com 
1732198Sigor@sysoev.ru     p = in->mem.pos;
1733198Sigor@sysoev.ru 
1734198Sigor@sysoev.ru     error = *p++;
1735198Sigor@sysoev.ru 
1736198Sigor@sysoev.ru     size = sizeof("listen socket error: ") - 1
1737198Sigor@sysoev.ru            + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1
1738198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1739198Sigor@sysoev.ru 
1740198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1741198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1742198Sigor@sysoev.ru         return;
1743198Sigor@sysoev.ru     }
1744198Sigor@sysoev.ru 
1745198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1746198Sigor@sysoev.ru                         "listen socket error: "
1747198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1748493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
1749198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1750198Sigor@sysoev.ru 
1751198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1752198Sigor@sysoev.ru 
1753198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
175453Sigor@sysoev.ru }
175553Sigor@sysoev.ru 
175653Sigor@sysoev.ru 
1757507Smax.romanov@nginx.com static void
1758507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
1759507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
1760507Smax.romanov@nginx.com {
1761507Smax.romanov@nginx.com     size_t         size;
1762507Smax.romanov@nginx.com     uint32_t       stream;
1763507Smax.romanov@nginx.com     nxt_buf_t      *b;
1764507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
1765507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1766507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
1767507Smax.romanov@nginx.com 
1768507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
1769507Smax.romanov@nginx.com     if (rpc == NULL) {
1770507Smax.romanov@nginx.com         goto fail;
1771507Smax.romanov@nginx.com     }
1772507Smax.romanov@nginx.com 
1773507Smax.romanov@nginx.com     rpc->app = app;
1774507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
1775507Smax.romanov@nginx.com 
1776507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
1777507Smax.romanov@nginx.com 
1778507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
1779507Smax.romanov@nginx.com 
1780507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1781507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1782507Smax.romanov@nginx.com         goto fail;
1783507Smax.romanov@nginx.com     }
1784507Smax.romanov@nginx.com 
1785507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
1786507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
1787507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1788507Smax.romanov@nginx.com 
1789507Smax.romanov@nginx.com     rt = task->thread->runtime;
1790507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1791507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1792507Smax.romanov@nginx.com 
1793507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
1794507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
1795507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
1796507Smax.romanov@nginx.com                                            -1, rpc);
1797507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
1798507Smax.romanov@nginx.com         goto fail;
1799507Smax.romanov@nginx.com     }
1800507Smax.romanov@nginx.com 
1801507Smax.romanov@nginx.com     app->pending_processes++;
1802507Smax.romanov@nginx.com 
1803507Smax.romanov@nginx.com     nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
1804507Smax.romanov@nginx.com                           stream, router_port->id, b);
1805507Smax.romanov@nginx.com 
1806507Smax.romanov@nginx.com     return;
1807507Smax.romanov@nginx.com 
1808507Smax.romanov@nginx.com fail:
1809507Smax.romanov@nginx.com 
1810507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
1811507Smax.romanov@nginx.com }
1812507Smax.romanov@nginx.com 
1813507Smax.romanov@nginx.com 
1814507Smax.romanov@nginx.com static void
1815507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1816507Smax.romanov@nginx.com     void *data)
1817507Smax.romanov@nginx.com {
1818507Smax.romanov@nginx.com     nxt_app_t           *app;
1819507Smax.romanov@nginx.com     nxt_port_t          *port;
1820507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
1821507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
1822507Smax.romanov@nginx.com 
1823507Smax.romanov@nginx.com     rpc = data;
1824507Smax.romanov@nginx.com     app = rpc->app;
1825507Smax.romanov@nginx.com 
1826507Smax.romanov@nginx.com     port = msg->u.new_port;
1827507Smax.romanov@nginx.com     port->app = app;
1828507Smax.romanov@nginx.com 
1829507Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
1830507Smax.romanov@nginx.com 
1831507Smax.romanov@nginx.com     app->pending_processes--;
1832507Smax.romanov@nginx.com     app->processes++;
1833507Smax.romanov@nginx.com     app->idle_processes++;
1834507Smax.romanov@nginx.com 
1835507Smax.romanov@nginx.com     engine = task->thread->engine;
1836507Smax.romanov@nginx.com 
1837507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
1838507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
1839507Smax.romanov@nginx.com 
1840507Smax.romanov@nginx.com     port->idle_start = 0;
1841507Smax.romanov@nginx.com 
1842507Smax.romanov@nginx.com     nxt_port_inc_use(port);
1843507Smax.romanov@nginx.com 
1844507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
1845507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1846507Smax.romanov@nginx.com }
1847507Smax.romanov@nginx.com 
1848507Smax.romanov@nginx.com 
1849507Smax.romanov@nginx.com static void
1850507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1851507Smax.romanov@nginx.com     void *data)
1852507Smax.romanov@nginx.com {
1853507Smax.romanov@nginx.com     nxt_app_t               *app;
1854507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
1855507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
1856507Smax.romanov@nginx.com 
1857507Smax.romanov@nginx.com     rpc = data;
1858507Smax.romanov@nginx.com     app = rpc->app;
1859507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
1860507Smax.romanov@nginx.com 
1861507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
1862507Smax.romanov@nginx.com             &app->name);
1863507Smax.romanov@nginx.com 
1864507Smax.romanov@nginx.com     app->pending_processes--;
1865507Smax.romanov@nginx.com 
1866507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
1867507Smax.romanov@nginx.com }
1868507Smax.romanov@nginx.com 
1869507Smax.romanov@nginx.com 
187053Sigor@sysoev.ru static nxt_int_t
187153Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
187253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
187353Sigor@sysoev.ru {
187453Sigor@sysoev.ru     nxt_int_t                 ret;
187553Sigor@sysoev.ru     nxt_uint_t                n, threads;
187653Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
187753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
187853Sigor@sysoev.ru 
187953Sigor@sysoev.ru     threads = tmcf->conf->threads;
188053Sigor@sysoev.ru 
188153Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
188253Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
188353Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
188453Sigor@sysoev.ru         return NXT_ERROR;
188553Sigor@sysoev.ru     }
188653Sigor@sysoev.ru 
188753Sigor@sysoev.ru     n = 0;
188853Sigor@sysoev.ru 
188953Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
189053Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
189153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
189253Sigor@sysoev.ru     {
189353Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
189453Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
189553Sigor@sysoev.ru             return NXT_ERROR;
189653Sigor@sysoev.ru         }
189753Sigor@sysoev.ru 
1898115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
189953Sigor@sysoev.ru 
190053Sigor@sysoev.ru         if (n < threads) {
1901315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
1902115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
190353Sigor@sysoev.ru 
190453Sigor@sysoev.ru         } else {
1905315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
1906115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
190753Sigor@sysoev.ru         }
190853Sigor@sysoev.ru 
190953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
191053Sigor@sysoev.ru             return ret;
191153Sigor@sysoev.ru         }
191253Sigor@sysoev.ru 
191353Sigor@sysoev.ru         n++;
191453Sigor@sysoev.ru     }
191553Sigor@sysoev.ru 
191653Sigor@sysoev.ru     tmcf->new_threads = n;
191753Sigor@sysoev.ru 
191853Sigor@sysoev.ru     while (n < threads) {
191953Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
192053Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
192153Sigor@sysoev.ru             return NXT_ERROR;
192253Sigor@sysoev.ru         }
192353Sigor@sysoev.ru 
1924315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
1925315Sigor@sysoev.ru 
192653Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
192753Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
192853Sigor@sysoev.ru             return NXT_ERROR;
192953Sigor@sysoev.ru         }
193053Sigor@sysoev.ru 
1931115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
193253Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
193353Sigor@sysoev.ru             return ret;
193453Sigor@sysoev.ru         }
193553Sigor@sysoev.ru 
193653Sigor@sysoev.ru         n++;
193753Sigor@sysoev.ru     }
193853Sigor@sysoev.ru 
193953Sigor@sysoev.ru     return NXT_OK;
194053Sigor@sysoev.ru }
194153Sigor@sysoev.ru 
194253Sigor@sysoev.ru 
194353Sigor@sysoev.ru static nxt_int_t
1944115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
1945115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
194653Sigor@sysoev.ru {
1947359Sigor@sysoev.ru     nxt_int_t  ret;
194853Sigor@sysoev.ru 
1949154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1950154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
1951115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1952115Sigor@sysoev.ru         return ret;
1953115Sigor@sysoev.ru     }
1954115Sigor@sysoev.ru 
1955154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1956154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
195753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
195853Sigor@sysoev.ru         return ret;
195953Sigor@sysoev.ru     }
196053Sigor@sysoev.ru 
1961115Sigor@sysoev.ru     return ret;
196253Sigor@sysoev.ru }
196353Sigor@sysoev.ru 
196453Sigor@sysoev.ru 
196553Sigor@sysoev.ru static nxt_int_t
1966115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
1967115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
196853Sigor@sysoev.ru {
1969359Sigor@sysoev.ru     nxt_int_t  ret;
197053Sigor@sysoev.ru 
1971154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
1972154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
197353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
197453Sigor@sysoev.ru         return ret;
197553Sigor@sysoev.ru     }
197653Sigor@sysoev.ru 
1977154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
1978154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
197953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
198053Sigor@sysoev.ru         return ret;
198153Sigor@sysoev.ru     }
198253Sigor@sysoev.ru 
1983139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
1984115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1985115Sigor@sysoev.ru         return ret;
1986115Sigor@sysoev.ru     }
1987115Sigor@sysoev.ru 
1988115Sigor@sysoev.ru     return ret;
198953Sigor@sysoev.ru }
199053Sigor@sysoev.ru 
199153Sigor@sysoev.ru 
199253Sigor@sysoev.ru static nxt_int_t
1993115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
1994115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
199553Sigor@sysoev.ru {
199653Sigor@sysoev.ru     nxt_int_t  ret;
199753Sigor@sysoev.ru 
1998313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
1999313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2000313Sigor@sysoev.ru         return ret;
2001313Sigor@sysoev.ru     }
2002313Sigor@sysoev.ru 
2003139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
200453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
200553Sigor@sysoev.ru         return ret;
200653Sigor@sysoev.ru     }
200753Sigor@sysoev.ru 
2008139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
200953Sigor@sysoev.ru }
201053Sigor@sysoev.ru 
201153Sigor@sysoev.ru 
201253Sigor@sysoev.ru static nxt_int_t
2013154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2014154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
201553Sigor@sysoev.ru     nxt_work_handler_t handler)
201653Sigor@sysoev.ru {
2017153Sigor@sysoev.ru     nxt_joint_job_t          *job;
201853Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2019155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
202053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
202153Sigor@sysoev.ru 
202253Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
202353Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
202453Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
202553Sigor@sysoev.ru     {
2026154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2027153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2028139Sigor@sysoev.ru             return NXT_ERROR;
2029139Sigor@sysoev.ru         }
2030139Sigor@sysoev.ru 
2031154Sigor@sysoev.ru         job->work.next = recf->jobs;
2032154Sigor@sysoev.ru         recf->jobs = &job->work;
2033154Sigor@sysoev.ru 
2034153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2035153Sigor@sysoev.ru         job->work.handler = handler;
2036153Sigor@sysoev.ru         job->work.task = &job->task;
2037153Sigor@sysoev.ru         job->work.obj = job;
2038153Sigor@sysoev.ru         job->tmcf = tmcf;
203953Sigor@sysoev.ru 
2040154Sigor@sysoev.ru         tmcf->count++;
2041154Sigor@sysoev.ru 
2042154Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->conf->mem_pool,
2043154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
204453Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
204553Sigor@sysoev.ru             return NXT_ERROR;
204653Sigor@sysoev.ru         }
204753Sigor@sysoev.ru 
2048153Sigor@sysoev.ru         job->work.data = joint;
204953Sigor@sysoev.ru 
205053Sigor@sysoev.ru         joint->count = 1;
2051155Sigor@sysoev.ru 
2052155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2053155Sigor@sysoev.ru         skcf->count++;
2054155Sigor@sysoev.ru         joint->socket_conf = skcf;
2055155Sigor@sysoev.ru 
205688Smax.romanov@nginx.com         joint->engine = recf->engine;
205753Sigor@sysoev.ru     }
205853Sigor@sysoev.ru 
205920Sigor@sysoev.ru     return NXT_OK;
206020Sigor@sysoev.ru }
206120Sigor@sysoev.ru 
206220Sigor@sysoev.ru 
206320Sigor@sysoev.ru static nxt_int_t
2064313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2065313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2066313Sigor@sysoev.ru {
2067313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2068313Sigor@sysoev.ru 
2069313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2070313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2071313Sigor@sysoev.ru         return NXT_ERROR;
2072313Sigor@sysoev.ru     }
2073313Sigor@sysoev.ru 
2074313Sigor@sysoev.ru     job->work.next = recf->jobs;
2075313Sigor@sysoev.ru     recf->jobs = &job->work;
2076313Sigor@sysoev.ru 
2077313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2078313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2079313Sigor@sysoev.ru     job->work.task = &job->task;
2080313Sigor@sysoev.ru     job->work.obj = NULL;
2081313Sigor@sysoev.ru     job->work.data = NULL;
2082313Sigor@sysoev.ru     job->tmcf = NULL;
2083313Sigor@sysoev.ru 
2084313Sigor@sysoev.ru     return NXT_OK;
2085313Sigor@sysoev.ru }
2086313Sigor@sysoev.ru 
2087313Sigor@sysoev.ru 
2088313Sigor@sysoev.ru static nxt_int_t
2089139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2090139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
209120Sigor@sysoev.ru {
2092153Sigor@sysoev.ru     nxt_joint_job_t   *job;
209353Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
209420Sigor@sysoev.ru 
209553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
209653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
209753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
209853Sigor@sysoev.ru     {
2099154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2100153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2101139Sigor@sysoev.ru             return NXT_ERROR;
2102139Sigor@sysoev.ru         }
2103139Sigor@sysoev.ru 
2104154Sigor@sysoev.ru         job->work.next = recf->jobs;
2105154Sigor@sysoev.ru         recf->jobs = &job->work;
2106154Sigor@sysoev.ru 
2107153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2108153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2109153Sigor@sysoev.ru         job->work.task = &job->task;
2110153Sigor@sysoev.ru         job->work.obj = job;
2111153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2112153Sigor@sysoev.ru         job->tmcf = tmcf;
2113154Sigor@sysoev.ru 
2114154Sigor@sysoev.ru         tmcf->count++;
211520Sigor@sysoev.ru     }
211620Sigor@sysoev.ru 
211753Sigor@sysoev.ru     return NXT_OK;
211853Sigor@sysoev.ru }
211920Sigor@sysoev.ru 
212020Sigor@sysoev.ru 
212153Sigor@sysoev.ru static nxt_int_t
212253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
212353Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
212453Sigor@sysoev.ru {
212553Sigor@sysoev.ru     nxt_int_t                 ret;
212653Sigor@sysoev.ru     nxt_uint_t                i, threads;
212753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
212820Sigor@sysoev.ru 
212953Sigor@sysoev.ru     recf = tmcf->engines->elts;
213053Sigor@sysoev.ru     threads = tmcf->conf->threads;
213120Sigor@sysoev.ru 
213253Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
213353Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
213453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
213553Sigor@sysoev.ru             return ret;
213653Sigor@sysoev.ru         }
213720Sigor@sysoev.ru     }
213820Sigor@sysoev.ru 
213920Sigor@sysoev.ru     return NXT_OK;
214020Sigor@sysoev.ru }
214153Sigor@sysoev.ru 
214253Sigor@sysoev.ru 
214353Sigor@sysoev.ru static nxt_int_t
214453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
214553Sigor@sysoev.ru     nxt_event_engine_t *engine)
214653Sigor@sysoev.ru {
214753Sigor@sysoev.ru     nxt_int_t            ret;
214853Sigor@sysoev.ru     nxt_thread_link_t    *link;
214953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
215053Sigor@sysoev.ru 
215153Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
215253Sigor@sysoev.ru 
215353Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
215453Sigor@sysoev.ru         return NXT_ERROR;
215553Sigor@sysoev.ru     }
215653Sigor@sysoev.ru 
215753Sigor@sysoev.ru     link->start = nxt_router_thread_start;
215853Sigor@sysoev.ru     link->engine = engine;
215953Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
216053Sigor@sysoev.ru     link->work.task = task;
216153Sigor@sysoev.ru     link->work.data = link;
216253Sigor@sysoev.ru 
216353Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
216453Sigor@sysoev.ru 
216553Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
216653Sigor@sysoev.ru 
216753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
216853Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
216953Sigor@sysoev.ru     }
217053Sigor@sysoev.ru 
217153Sigor@sysoev.ru     return ret;
217253Sigor@sysoev.ru }
217353Sigor@sysoev.ru 
217453Sigor@sysoev.ru 
217553Sigor@sysoev.ru static void
2176343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2177343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2178133Sigor@sysoev.ru {
2179507Smax.romanov@nginx.com     nxt_app_t  *app;
2180141Smax.romanov@nginx.com 
2181141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2182133Sigor@sysoev.ru 
2183507Smax.romanov@nginx.com         nxt_router_app_quit(task, app);
2184343Smax.romanov@nginx.com 
2185141Smax.romanov@nginx.com     } nxt_queue_loop;
2186133Sigor@sysoev.ru 
2187133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2188133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2189133Sigor@sysoev.ru }
2190133Sigor@sysoev.ru 
2191133Sigor@sysoev.ru 
2192133Sigor@sysoev.ru static void
2193315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
219453Sigor@sysoev.ru {
219553Sigor@sysoev.ru     nxt_uint_t                n;
2196315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
219753Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
219853Sigor@sysoev.ru 
219953Sigor@sysoev.ru     recf = tmcf->engines->elts;
220053Sigor@sysoev.ru 
220153Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2202315Sigor@sysoev.ru         engine = recf->engine;
2203315Sigor@sysoev.ru 
2204315Sigor@sysoev.ru         switch (recf->action) {
2205315Sigor@sysoev.ru 
2206315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2207315Sigor@sysoev.ru             break;
2208315Sigor@sysoev.ru 
2209315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2210315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2211315Sigor@sysoev.ru             break;
2212315Sigor@sysoev.ru 
2213315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2214315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2215315Sigor@sysoev.ru             break;
2216315Sigor@sysoev.ru         }
2217315Sigor@sysoev.ru 
2218316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2219316Sigor@sysoev.ru 
222053Sigor@sysoev.ru         recf++;
222153Sigor@sysoev.ru     }
222253Sigor@sysoev.ru }
222353Sigor@sysoev.ru 
222453Sigor@sysoev.ru 
222553Sigor@sysoev.ru static void
2226315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
222753Sigor@sysoev.ru {
2228154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2229154Sigor@sysoev.ru 
2230315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2231154Sigor@sysoev.ru         next = work->next;
2232154Sigor@sysoev.ru         work->next = NULL;
2233154Sigor@sysoev.ru 
2234315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
223553Sigor@sysoev.ru     }
223653Sigor@sysoev.ru }
223753Sigor@sysoev.ru 
223853Sigor@sysoev.ru 
2239320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2240320Smax.romanov@nginx.com     .mmap = nxt_port_mmap_handler,
2241320Smax.romanov@nginx.com     .data = nxt_port_rpc_handler,
224288Smax.romanov@nginx.com };
224388Smax.romanov@nginx.com 
224488Smax.romanov@nginx.com 
224588Smax.romanov@nginx.com static void
224653Sigor@sysoev.ru nxt_router_thread_start(void *data)
224753Sigor@sysoev.ru {
2248141Smax.romanov@nginx.com     nxt_int_t           ret;
2249141Smax.romanov@nginx.com     nxt_port_t          *port;
225088Smax.romanov@nginx.com     nxt_task_t          *task;
225153Sigor@sysoev.ru     nxt_thread_t        *thread;
225253Sigor@sysoev.ru     nxt_thread_link_t   *link;
225353Sigor@sysoev.ru     nxt_event_engine_t  *engine;
225453Sigor@sysoev.ru 
225553Sigor@sysoev.ru     link = data;
225653Sigor@sysoev.ru     engine = link->engine;
225788Smax.romanov@nginx.com     task = &engine->task;
225853Sigor@sysoev.ru 
225953Sigor@sysoev.ru     thread = nxt_thread();
226053Sigor@sysoev.ru 
2261165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2262165Smax.romanov@nginx.com 
226353Sigor@sysoev.ru     /* STUB */
226453Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
226553Sigor@sysoev.ru 
226653Sigor@sysoev.ru     engine->task.thread = thread;
226753Sigor@sysoev.ru     engine->task.log = thread->log;
226853Sigor@sysoev.ru     thread->engine = engine;
226963Sigor@sysoev.ru     thread->task = &engine->task;
2270326Svbart@nginx.com #if 0
227153Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2272326Svbart@nginx.com #endif
227353Sigor@sysoev.ru 
227463Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2275337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2276337Sigor@sysoev.ru         return;
2277337Sigor@sysoev.ru     }
227853Sigor@sysoev.ru 
2279197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2280197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2281141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2282141Smax.romanov@nginx.com         return;
2283141Smax.romanov@nginx.com     }
2284141Smax.romanov@nginx.com 
2285141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2286141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2287343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2288141Smax.romanov@nginx.com         return;
2289141Smax.romanov@nginx.com     }
2290141Smax.romanov@nginx.com 
2291141Smax.romanov@nginx.com     engine->port = port;
2292141Smax.romanov@nginx.com 
2293320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2294141Smax.romanov@nginx.com 
229553Sigor@sysoev.ru     nxt_event_engine_start(engine);
229653Sigor@sysoev.ru }
229753Sigor@sysoev.ru 
229853Sigor@sysoev.ru 
229953Sigor@sysoev.ru static void
230053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
230153Sigor@sysoev.ru {
2302153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2303359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2304359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
230553Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2306359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
230753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
230853Sigor@sysoev.ru 
2309153Sigor@sysoev.ru     job = obj;
231053Sigor@sysoev.ru     joint = data;
231153Sigor@sysoev.ru 
2312159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2313159Sigor@sysoev.ru 
2314359Sigor@sysoev.ru     skcf = joint->socket_conf;
2315359Sigor@sysoev.ru     ls = skcf->listen;
2316359Sigor@sysoev.ru 
2317359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2318359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2319359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
232053Sigor@sysoev.ru         return;
232153Sigor@sysoev.ru     }
232253Sigor@sysoev.ru 
2323359Sigor@sysoev.ru     lev->socket.data = joint;
2324359Sigor@sysoev.ru 
2325359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2326359Sigor@sysoev.ru 
2327359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2328359Sigor@sysoev.ru     ls->count++;
2329359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2330139Sigor@sysoev.ru 
2331153Sigor@sysoev.ru     job->work.next = NULL;
2332153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2333153Sigor@sysoev.ru 
2334153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
233553Sigor@sysoev.ru }
233653Sigor@sysoev.ru 
233753Sigor@sysoev.ru 
233853Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
233953Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
234053Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
234153Sigor@sysoev.ru {
2342115Sigor@sysoev.ru     nxt_socket_t        fd;
2343115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2344359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2345359Sigor@sysoev.ru 
2346359Sigor@sysoev.ru     fd = skcf->listen->socket;
234753Sigor@sysoev.ru 
2348115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2349115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2350115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
235153Sigor@sysoev.ru     {
2352359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2353359Sigor@sysoev.ru 
2354359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2355359Sigor@sysoev.ru             return lev;
235653Sigor@sysoev.ru         }
235753Sigor@sysoev.ru     }
235853Sigor@sysoev.ru 
235953Sigor@sysoev.ru     return NULL;
236053Sigor@sysoev.ru }
236153Sigor@sysoev.ru 
236253Sigor@sysoev.ru 
236353Sigor@sysoev.ru static void
236453Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
236553Sigor@sysoev.ru {
2366153Sigor@sysoev.ru     nxt_joint_job_t          *job;
236753Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2368359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
236953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
237053Sigor@sysoev.ru 
2371153Sigor@sysoev.ru     job = obj;
237253Sigor@sysoev.ru     joint = data;
237353Sigor@sysoev.ru 
2374139Sigor@sysoev.ru     engine = task->thread->engine;
2375139Sigor@sysoev.ru 
2376159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2377159Sigor@sysoev.ru 
2378359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2379359Sigor@sysoev.ru                                   joint->socket_conf);
2380359Sigor@sysoev.ru 
2381359Sigor@sysoev.ru     old = lev->socket.data;
2382359Sigor@sysoev.ru     lev->socket.data = joint;
2383359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
238453Sigor@sysoev.ru 
2385153Sigor@sysoev.ru     job->work.next = NULL;
2386153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2387153Sigor@sysoev.ru 
2388153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2389139Sigor@sysoev.ru 
2390181Smax.romanov@nginx.com     /*
2391181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2392181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2393181Smax.romanov@nginx.com      */
2394181Smax.romanov@nginx.com 
2395181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
239653Sigor@sysoev.ru }
239753Sigor@sysoev.ru 
239853Sigor@sysoev.ru 
239953Sigor@sysoev.ru static void
240053Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
240153Sigor@sysoev.ru {
2402153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2403153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2404359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2405153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2406153Sigor@sysoev.ru 
2407153Sigor@sysoev.ru     job = obj;
240853Sigor@sysoev.ru     skcf = data;
240953Sigor@sysoev.ru 
2410139Sigor@sysoev.ru     engine = task->thread->engine;
2411139Sigor@sysoev.ru 
2412359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2413359Sigor@sysoev.ru 
2414359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
241553Sigor@sysoev.ru 
2416163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2417359Sigor@sysoev.ru               lev->socket.fd);
2418359Sigor@sysoev.ru 
2419359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2420359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2421359Sigor@sysoev.ru 
2422359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2423139Sigor@sysoev.ru 
2424153Sigor@sysoev.ru     job->work.next = NULL;
2425153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2426153Sigor@sysoev.ru 
2427153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
242853Sigor@sysoev.ru }
242953Sigor@sysoev.ru 
243053Sigor@sysoev.ru 
243153Sigor@sysoev.ru static void
2432313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2433313Sigor@sysoev.ru {
2434313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2435313Sigor@sysoev.ru 
2436313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2437313Sigor@sysoev.ru 
2438313Sigor@sysoev.ru     engine = task->thread->engine;
2439313Sigor@sysoev.ru 
2440313Sigor@sysoev.ru     engine->shutdown = 1;
2441313Sigor@sysoev.ru 
2442313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2443313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2444313Sigor@sysoev.ru     }
2445313Sigor@sysoev.ru }
2446313Sigor@sysoev.ru 
2447313Sigor@sysoev.ru 
2448313Sigor@sysoev.ru static void
244953Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
245053Sigor@sysoev.ru {
245153Sigor@sysoev.ru     nxt_timer_t              *timer;
2452359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
245353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
245453Sigor@sysoev.ru 
245553Sigor@sysoev.ru     timer = obj;
2456359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
2457359Sigor@sysoev.ru     joint = lev->socket.data;
245853Sigor@sysoev.ru 
2459163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2460359Sigor@sysoev.ru               lev->socket.fd);
2461359Sigor@sysoev.ru 
2462359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2463359Sigor@sysoev.ru 
2464359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2465123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2466123Smax.romanov@nginx.com 
2467359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2468359Sigor@sysoev.ru 
2469359Sigor@sysoev.ru     nxt_free(lev);
2470359Sigor@sysoev.ru 
2471359Sigor@sysoev.ru     nxt_router_conf_release(task, joint);
247253Sigor@sysoev.ru }
247353Sigor@sysoev.ru 
247453Sigor@sysoev.ru 
247553Sigor@sysoev.ru static void
2476359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
247753Sigor@sysoev.ru {
2478359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
247953Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
248053Sigor@sysoev.ru 
2481359Sigor@sysoev.ru     ls = skcf->listen;
2482118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
248353Sigor@sysoev.ru 
248453Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
248553Sigor@sysoev.ru 
2486359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2487359Sigor@sysoev.ru               task->thread->engine, ls->count);
2488359Sigor@sysoev.ru 
2489359Sigor@sysoev.ru     if (--ls->count != 0) {
2490359Sigor@sysoev.ru         ls = NULL;
249153Sigor@sysoev.ru     }
249253Sigor@sysoev.ru 
249353Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
249453Sigor@sysoev.ru 
2495359Sigor@sysoev.ru     if (ls != NULL) {
2496359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
2497359Sigor@sysoev.ru         nxt_free(ls);
249853Sigor@sysoev.ru     }
249953Sigor@sysoev.ru }
250053Sigor@sysoev.ru 
250153Sigor@sysoev.ru 
250253Sigor@sysoev.ru static void
250353Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
250453Sigor@sysoev.ru {
2505156Sigor@sysoev.ru     nxt_bool_t             exit;
250653Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
250753Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
2508313Sigor@sysoev.ru     nxt_event_engine_t     *engine;
250953Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
251053Sigor@sysoev.ru 
2511163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
251253Sigor@sysoev.ru 
251353Sigor@sysoev.ru     if (--joint->count != 0) {
251453Sigor@sysoev.ru         return;
251553Sigor@sysoev.ru     }
251653Sigor@sysoev.ru 
251753Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
251853Sigor@sysoev.ru 
251953Sigor@sysoev.ru     skcf = joint->socket_conf;
252053Sigor@sysoev.ru     rtcf = skcf->router_conf;
252153Sigor@sysoev.ru     lock = &rtcf->router->lock;
252253Sigor@sysoev.ru 
252353Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
252453Sigor@sysoev.ru 
2525163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2526163Smax.romanov@nginx.com               rtcf, rtcf->count);
2527163Smax.romanov@nginx.com 
252853Sigor@sysoev.ru     if (--skcf->count != 0) {
252953Sigor@sysoev.ru         rtcf = NULL;
253053Sigor@sysoev.ru 
253153Sigor@sysoev.ru     } else {
253253Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
253353Sigor@sysoev.ru 
253453Sigor@sysoev.ru         if (--rtcf->count != 0) {
253553Sigor@sysoev.ru             rtcf = NULL;
253653Sigor@sysoev.ru         }
253753Sigor@sysoev.ru     }
253853Sigor@sysoev.ru 
253953Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
254053Sigor@sysoev.ru 
2541141Smax.romanov@nginx.com     /* TODO remove engine->port */
2542141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2543141Smax.romanov@nginx.com 
2544156Sigor@sysoev.ru     /* The joint content can be used before memory pool destruction. */
2545313Sigor@sysoev.ru     engine = joint->engine;
2546313Sigor@sysoev.ru     exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints));
2547156Sigor@sysoev.ru 
254853Sigor@sysoev.ru     if (rtcf != NULL) {
2549115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2550131Smax.romanov@nginx.com 
2551131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2552131Smax.romanov@nginx.com 
255365Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
255453Sigor@sysoev.ru     }
255553Sigor@sysoev.ru 
2556156Sigor@sysoev.ru     if (exit) {
255753Sigor@sysoev.ru         nxt_thread_exit(task->thread);
255853Sigor@sysoev.ru     }
255953Sigor@sysoev.ru }
256053Sigor@sysoev.ru 
256153Sigor@sysoev.ru 
256253Sigor@sysoev.ru static void
256353Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
256453Sigor@sysoev.ru {
2565141Smax.romanov@nginx.com     nxt_port_t           *port;
256653Sigor@sysoev.ru     nxt_thread_link_t    *link;
256753Sigor@sysoev.ru     nxt_event_engine_t   *engine;
256853Sigor@sysoev.ru     nxt_thread_handle_t  handle;
256953Sigor@sysoev.ru 
257058Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
257153Sigor@sysoev.ru     link = data;
257253Sigor@sysoev.ru 
257353Sigor@sysoev.ru     nxt_thread_wait(handle);
257453Sigor@sysoev.ru 
257553Sigor@sysoev.ru     engine = link->engine;
257653Sigor@sysoev.ru 
257753Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
257853Sigor@sysoev.ru 
2579141Smax.romanov@nginx.com     port = engine->port;
2580141Smax.romanov@nginx.com 
2581141Smax.romanov@nginx.com     // TODO notify all apps
2582141Smax.romanov@nginx.com 
2583343Smax.romanov@nginx.com     port->engine = task->thread->engine;
2584163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
2585343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
2586163Smax.romanov@nginx.com 
2587163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
258863Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
258953Sigor@sysoev.ru 
259053Sigor@sysoev.ru     nxt_event_engine_free(engine);
259153Sigor@sysoev.ru 
259253Sigor@sysoev.ru     nxt_free(link);
259353Sigor@sysoev.ru }
259453Sigor@sysoev.ru 
259553Sigor@sysoev.ru 
259653Sigor@sysoev.ru static void
2597318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2598318Smax.romanov@nginx.com     void *data)
259988Smax.romanov@nginx.com {
260088Smax.romanov@nginx.com     size_t               dump_size;
2601431Sigor@sysoev.ru     nxt_int_t            ret;
2602194Smax.romanov@nginx.com     nxt_buf_t            *b, *last;
2603431Sigor@sysoev.ru     nxt_http_request_t   *r;
260488Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2605431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
260688Smax.romanov@nginx.com 
260788Smax.romanov@nginx.com     b = msg->buf;
2608318Smax.romanov@nginx.com     rc = data;
260988Smax.romanov@nginx.com 
261088Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
261188Smax.romanov@nginx.com 
261288Smax.romanov@nginx.com     if (dump_size > 300) {
261388Smax.romanov@nginx.com         dump_size = 300;
261488Smax.romanov@nginx.com     }
261588Smax.romanov@nginx.com 
2616494Spluknet@nginx.com     nxt_debug(task, "%srouter app data (%uz): %*s",
261788Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
261888Smax.romanov@nginx.com               b->mem.pos);
261988Smax.romanov@nginx.com 
262088Smax.romanov@nginx.com     if (msg->size == 0) {
262188Smax.romanov@nginx.com         b = NULL;
262288Smax.romanov@nginx.com     }
262388Smax.romanov@nginx.com 
2624431Sigor@sysoev.ru     ar = rc->ap;
2625425Smax.romanov@nginx.com 
262688Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
262788Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
262888Smax.romanov@nginx.com 
2629431Sigor@sysoev.ru         last = nxt_http_request_last_buffer(task, ar->request);
263088Smax.romanov@nginx.com         if (nxt_slow_path(last == NULL)) {
2631431Sigor@sysoev.ru             nxt_app_http_req_done(task, ar);
2632431Sigor@sysoev.ru             nxt_router_rc_unlink(task, rc);
2633431Sigor@sysoev.ru             return;
263488Smax.romanov@nginx.com         }
263588Smax.romanov@nginx.com 
263688Smax.romanov@nginx.com         nxt_buf_chain_add(&b, last);
2637167Smax.romanov@nginx.com 
2638343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
2639425Smax.romanov@nginx.com 
2640425Smax.romanov@nginx.com     } else {
2641425Smax.romanov@nginx.com         if (rc->app->timeout != 0) {
2642431Sigor@sysoev.ru             ar->timer.handler = nxt_router_app_timeout;
2643431Sigor@sysoev.ru             nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout);
2644425Smax.romanov@nginx.com         }
264588Smax.romanov@nginx.com     }
264688Smax.romanov@nginx.com 
264788Smax.romanov@nginx.com     if (b == NULL) {
264888Smax.romanov@nginx.com         return;
264988Smax.romanov@nginx.com     }
265088Smax.romanov@nginx.com 
2651206Smax.romanov@nginx.com     if (msg->buf == b) {
2652206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
2653206Smax.romanov@nginx.com         msg->buf = NULL;
2654206Smax.romanov@nginx.com     }
2655194Smax.romanov@nginx.com 
2656431Sigor@sysoev.ru     r = ar->request;
2657431Sigor@sysoev.ru 
2658431Sigor@sysoev.ru     if (r->header_sent) {
2659431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
2660431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
2661277Sigor@sysoev.ru 
266288Smax.romanov@nginx.com     } else {
2663431Sigor@sysoev.ru         ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem);
2664431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_DONE)) {
2665431Sigor@sysoev.ru             goto fail;
2666431Sigor@sysoev.ru         }
2667431Sigor@sysoev.ru 
2668431Sigor@sysoev.ru         r->resp.fields = ar->resp_parser.fields;
2669431Sigor@sysoev.ru 
2670431Sigor@sysoev.ru         ret = nxt_http_fields_process(r->resp.fields,
2671431Sigor@sysoev.ru                                       &nxt_response_fields_hash, r);
2672431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
2673431Sigor@sysoev.ru             goto fail;
2674431Sigor@sysoev.ru         }
2675431Sigor@sysoev.ru 
2676435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
2677435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2678435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
2679507Smax.romanov@nginx.com 
2680435Sigor@sysoev.ru         } else {
2681431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
2682431Sigor@sysoev.ru         }
2683431Sigor@sysoev.ru 
2684431Sigor@sysoev.ru         r->state = &nxt_http_request_send_state;
2685431Sigor@sysoev.ru 
2686431Sigor@sysoev.ru         nxt_http_request_header_send(task, r);
2687431Sigor@sysoev.ru     }
2688431Sigor@sysoev.ru 
2689431Sigor@sysoev.ru     return;
2690431Sigor@sysoev.ru 
2691431Sigor@sysoev.ru fail:
2692431Sigor@sysoev.ru 
2693431Sigor@sysoev.ru     nxt_app_http_req_done(task, ar);
2694431Sigor@sysoev.ru     nxt_router_rc_unlink(task, rc);
2695431Sigor@sysoev.ru 
2696431Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
2697431Sigor@sysoev.ru }
2698431Sigor@sysoev.ru 
2699431Sigor@sysoev.ru 
2700431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
2701431Sigor@sysoev.ru     nxt_aligned(64) =
2702431Sigor@sysoev.ru {
2703431Sigor@sysoev.ru     .ready_handler = nxt_http_request_send_body,
2704431Sigor@sysoev.ru     .error_handler = nxt_http_request_close_handler,
2705431Sigor@sysoev.ru };
2706431Sigor@sysoev.ru 
2707431Sigor@sysoev.ru 
2708431Sigor@sysoev.ru static void
2709431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
2710431Sigor@sysoev.ru {
2711431Sigor@sysoev.ru     nxt_buf_t           *out;
2712431Sigor@sysoev.ru     nxt_http_request_t  *r;
2713431Sigor@sysoev.ru 
2714431Sigor@sysoev.ru     r = obj;
2715431Sigor@sysoev.ru 
2716431Sigor@sysoev.ru     out = r->out;
2717431Sigor@sysoev.ru 
2718431Sigor@sysoev.ru     if (out != NULL) {
2719431Sigor@sysoev.ru         r->out = NULL;
2720431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
272188Smax.romanov@nginx.com     }
272288Smax.romanov@nginx.com }
272388Smax.romanov@nginx.com 
2724277Sigor@sysoev.ru 
2725318Smax.romanov@nginx.com static void
2726318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2727318Smax.romanov@nginx.com     void *data)
2728318Smax.romanov@nginx.com {
2729425Smax.romanov@nginx.com     nxt_int_t            res;
2730425Smax.romanov@nginx.com     nxt_port_t           *port;
2731425Smax.romanov@nginx.com     nxt_bool_t           cancelled;
2732425Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
2733318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
2734318Smax.romanov@nginx.com 
2735318Smax.romanov@nginx.com     rc = data;
2736318Smax.romanov@nginx.com 
2737425Smax.romanov@nginx.com     ra = rc->ra;
2738425Smax.romanov@nginx.com 
2739425Smax.romanov@nginx.com     if (ra != NULL) {
2740425Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
2741425Smax.romanov@nginx.com 
2742425Smax.romanov@nginx.com         if (cancelled) {
2743425Smax.romanov@nginx.com             nxt_router_ra_inc_use(ra);
2744425Smax.romanov@nginx.com 
2745427Smax.romanov@nginx.com             res = nxt_router_app_port(task, rc->app, ra);
2746425Smax.romanov@nginx.com 
2747425Smax.romanov@nginx.com             if (res == NXT_OK) {
2748425Smax.romanov@nginx.com                 port = ra->app_port;
2749425Smax.romanov@nginx.com 
2750425Smax.romanov@nginx.com                 nxt_assert(port != NULL);
2751425Smax.romanov@nginx.com 
2752425Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc,
2753425Smax.romanov@nginx.com                                          port->pid);
2754425Smax.romanov@nginx.com 
2755425Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, ra);
2756425Smax.romanov@nginx.com             }
2757425Smax.romanov@nginx.com 
2758425Smax.romanov@nginx.com             msg->port_msg.last = 0;
2759425Smax.romanov@nginx.com 
2760425Smax.romanov@nginx.com             return;
2761425Smax.romanov@nginx.com         }
2762425Smax.romanov@nginx.com     }
2763425Smax.romanov@nginx.com 
2764431Sigor@sysoev.ru     nxt_http_request_error(task, rc->ap->request, NXT_HTTP_SERVICE_UNAVAILABLE);
2765318Smax.romanov@nginx.com 
2766343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
2767318Smax.romanov@nginx.com }
2768318Smax.romanov@nginx.com 
2769318Smax.romanov@nginx.com 
2770141Smax.romanov@nginx.com static void
2771343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2772343Smax.romanov@nginx.com     void *data)
2773192Smax.romanov@nginx.com {
2774343Smax.romanov@nginx.com     nxt_app_t   *app;
2775343Smax.romanov@nginx.com     nxt_port_t  *port;
2776343Smax.romanov@nginx.com 
2777343Smax.romanov@nginx.com     app = data;
2778347Smax.romanov@nginx.com     port = msg->u.new_port;
2779343Smax.romanov@nginx.com 
2780343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2781343Smax.romanov@nginx.com     nxt_assert(port != NULL);
2782343Smax.romanov@nginx.com 
2783343Smax.romanov@nginx.com     port->app = app;
2784343Smax.romanov@nginx.com 
2785343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2786343Smax.romanov@nginx.com 
2787507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
2788507Smax.romanov@nginx.com 
2789507Smax.romanov@nginx.com     app->pending_processes--;
2790507Smax.romanov@nginx.com     app->processes++;
2791343Smax.romanov@nginx.com 
2792343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2793343Smax.romanov@nginx.com 
2794507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
2795507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
2796343Smax.romanov@nginx.com 
2797343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
2798192Smax.romanov@nginx.com }
2799192Smax.romanov@nginx.com 
2800192Smax.romanov@nginx.com 
2801192Smax.romanov@nginx.com static void
2802343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2803343Smax.romanov@nginx.com     void *data)
2804192Smax.romanov@nginx.com {
2805318Smax.romanov@nginx.com     nxt_app_t           *app;
2806318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
2807318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
2808343Smax.romanov@nginx.com 
2809343Smax.romanov@nginx.com     app = data;
2810343Smax.romanov@nginx.com 
2811343Smax.romanov@nginx.com     nxt_assert(app != NULL);
2812343Smax.romanov@nginx.com 
2813343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
2814343Smax.romanov@nginx.com 
2815343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2816343Smax.romanov@nginx.com 
2817507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
2818507Smax.romanov@nginx.com 
2819507Smax.romanov@nginx.com     app->pending_processes--;
2820318Smax.romanov@nginx.com 
2821318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
2822318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
2823318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
2824343Smax.romanov@nginx.com         lnk->next = NULL;
2825318Smax.romanov@nginx.com 
2826425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
2827318Smax.romanov@nginx.com 
2828343Smax.romanov@nginx.com     } else {
2829343Smax.romanov@nginx.com         ra = NULL;
2830343Smax.romanov@nginx.com     }
2831343Smax.romanov@nginx.com 
2832343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2833343Smax.romanov@nginx.com 
2834343Smax.romanov@nginx.com     if (ra != NULL) {
2835318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
2836318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
2837318Smax.romanov@nginx.com 
2838507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start application process");
2839425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
2840318Smax.romanov@nginx.com     }
2841192Smax.romanov@nginx.com 
2842343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
2843192Smax.romanov@nginx.com }
2844192Smax.romanov@nginx.com 
2845192Smax.romanov@nginx.com 
2846343Smax.romanov@nginx.com void
2847343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
2848141Smax.romanov@nginx.com {
2849343Smax.romanov@nginx.com     int  c;
2850343Smax.romanov@nginx.com 
2851343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
2852343Smax.romanov@nginx.com 
2853343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
2854343Smax.romanov@nginx.com 
2855343Smax.romanov@nginx.com         nxt_assert(app->live == 0);
2856507Smax.romanov@nginx.com         nxt_assert(app->processes == 0);
2857507Smax.romanov@nginx.com         nxt_assert(app->idle_processes == 0);
2858507Smax.romanov@nginx.com         nxt_assert(app->pending_processes == 0);
2859343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->requests) != 0);
2860343Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->ports) != 0);
2861507Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->spare_ports) != 0);
2862507Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->idle_ports) != 0);
2863343Smax.romanov@nginx.com 
2864163Smax.romanov@nginx.com         nxt_thread_mutex_destroy(&app->mutex);
2865163Smax.romanov@nginx.com         nxt_free(app);
2866163Smax.romanov@nginx.com     }
2867343Smax.romanov@nginx.com }
2868343Smax.romanov@nginx.com 
2869343Smax.romanov@nginx.com 
2870424Smax.romanov@nginx.com nxt_inline nxt_bool_t
2871424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
2872424Smax.romanov@nginx.com {
2873424Smax.romanov@nginx.com     nxt_port_t        *port;
2874424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2875424Smax.romanov@nginx.com 
2876424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
2877424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2878424Smax.romanov@nginx.com 
2879424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
2880424Smax.romanov@nginx.com }
2881424Smax.romanov@nginx.com 
2882424Smax.romanov@nginx.com 
2883343Smax.romanov@nginx.com nxt_inline nxt_port_t *
2884427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
2885343Smax.romanov@nginx.com {
2886343Smax.romanov@nginx.com     nxt_port_t        *port;
2887343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
2888343Smax.romanov@nginx.com 
2889343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
2890343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
2891343Smax.romanov@nginx.com 
2892343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
2893343Smax.romanov@nginx.com 
2894424Smax.romanov@nginx.com     port->app_pending_responses++;
2895424Smax.romanov@nginx.com 
2896507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
2897507Smax.romanov@nginx.com         app->idle_processes--;
2898507Smax.romanov@nginx.com 
2899507Smax.romanov@nginx.com         if (port->idle_start == 0) {
2900507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
2901507Smax.romanov@nginx.com 
2902507Smax.romanov@nginx.com         } else {
2903507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
2904507Smax.romanov@nginx.com 
2905507Smax.romanov@nginx.com             port->idle_start = 0;
2906507Smax.romanov@nginx.com         }
2907507Smax.romanov@nginx.com     }
2908507Smax.romanov@nginx.com 
2909428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
2910428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
2911428Smax.romanov@nginx.com         && (app->max_requests == 0
2912428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
2913428Smax.romanov@nginx.com                 < app->max_requests))
2914277Sigor@sysoev.ru     {
2915343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
2916343Smax.romanov@nginx.com 
2917425Smax.romanov@nginx.com         nxt_port_inc_use(port);
2918425Smax.romanov@nginx.com 
2919343Smax.romanov@nginx.com     } else {
2920343Smax.romanov@nginx.com         lnk->next = NULL;
2921167Smax.romanov@nginx.com     }
2922167Smax.romanov@nginx.com 
2923343Smax.romanov@nginx.com     return port;
2924163Smax.romanov@nginx.com }
2925163Smax.romanov@nginx.com 
2926163Smax.romanov@nginx.com 
2927507Smax.romanov@nginx.com nxt_inline nxt_port_t *
2928507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
2929141Smax.romanov@nginx.com {
2930343Smax.romanov@nginx.com     nxt_port_t  *port;
2931141Smax.romanov@nginx.com 
2932141Smax.romanov@nginx.com     port = NULL;
2933141Smax.romanov@nginx.com 
2934141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
2935141Smax.romanov@nginx.com 
2936343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
2937343Smax.romanov@nginx.com 
2938424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
2939343Smax.romanov@nginx.com             port = NULL;
2940343Smax.romanov@nginx.com 
2941343Smax.romanov@nginx.com             continue;
2942343Smax.romanov@nginx.com         }
2943343Smax.romanov@nginx.com 
2944507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
2945507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
2946507Smax.romanov@nginx.com 
2947507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
2948507Smax.romanov@nginx.com             app->idle_processes--;
2949507Smax.romanov@nginx.com         }
2950507Smax.romanov@nginx.com 
2951507Smax.romanov@nginx.com         /* Caller is responsible to decrease app use count. */
2952507Smax.romanov@nginx.com         port->app = NULL;
2953507Smax.romanov@nginx.com         app->processes--;
2954343Smax.romanov@nginx.com 
2955343Smax.romanov@nginx.com         break;
2956343Smax.romanov@nginx.com 
2957343Smax.romanov@nginx.com     } nxt_queue_loop;
2958141Smax.romanov@nginx.com 
2959141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
2960141Smax.romanov@nginx.com 
2961141Smax.romanov@nginx.com     return port;
2962141Smax.romanov@nginx.com }
2963141Smax.romanov@nginx.com 
2964141Smax.romanov@nginx.com 
2965141Smax.romanov@nginx.com static void
2966507Smax.romanov@nginx.com nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app)
2967507Smax.romanov@nginx.com {
2968507Smax.romanov@nginx.com     nxt_port_t  *port;
2969507Smax.romanov@nginx.com 
2970507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
2971507Smax.romanov@nginx.com 
2972507Smax.romanov@nginx.com     app->live = 0;
2973507Smax.romanov@nginx.com 
2974507Smax.romanov@nginx.com     for ( ;; ) {
2975507Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
2976507Smax.romanov@nginx.com         if (port == NULL) {
2977507Smax.romanov@nginx.com             break;
2978507Smax.romanov@nginx.com         }
2979507Smax.romanov@nginx.com 
2980507Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
2981507Smax.romanov@nginx.com 
2982507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
2983507Smax.romanov@nginx.com 
2984507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2985507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
2986507Smax.romanov@nginx.com     }
2987507Smax.romanov@nginx.com 
2988507Smax.romanov@nginx.com     if (nxt_timer_is_in_tree(&app->idle_timer)) {
2989507Smax.romanov@nginx.com         nxt_assert(app->engine == task->thread->engine);
2990507Smax.romanov@nginx.com 
2991507Smax.romanov@nginx.com         app->idle_timer.handler = nxt_router_app_release_handler;
2992507Smax.romanov@nginx.com         nxt_timer_add(app->engine, &app->idle_timer, 0);
2993507Smax.romanov@nginx.com 
2994507Smax.romanov@nginx.com     } else {
2995507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
2996507Smax.romanov@nginx.com     }
2997507Smax.romanov@nginx.com }
2998507Smax.romanov@nginx.com 
2999507Smax.romanov@nginx.com 
3000507Smax.romanov@nginx.com static void
3001343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
3002141Smax.romanov@nginx.com {
3003343Smax.romanov@nginx.com     nxt_app_t           *app;
3004343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3005343Smax.romanov@nginx.com 
3006343Smax.romanov@nginx.com     app = obj;
3007343Smax.romanov@nginx.com     ra = data;
3008141Smax.romanov@nginx.com 
3009141Smax.romanov@nginx.com     nxt_assert(app != NULL);
3010343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
3011343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3012343Smax.romanov@nginx.com 
3013343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
3014343Smax.romanov@nginx.com               &app->name, app, ra->stream);
3015343Smax.romanov@nginx.com 
3016425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
3017343Smax.romanov@nginx.com }
3018343Smax.romanov@nginx.com 
3019343Smax.romanov@nginx.com 
3020343Smax.romanov@nginx.com static void
3021343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
3022343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
3023343Smax.romanov@nginx.com {
3024427Smax.romanov@nginx.com     nxt_app_t                *app;
3025507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
3026507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
3027427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
3028427Smax.romanov@nginx.com     nxt_req_app_link_t       *ra, *pending_ra, *re_ra;
3029427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
3030343Smax.romanov@nginx.com 
3031343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3032343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
3033343Smax.romanov@nginx.com 
3034427Smax.romanov@nginx.com     ra = NULL;
3035427Smax.romanov@nginx.com 
3036343Smax.romanov@nginx.com     app = port->app;
3037343Smax.romanov@nginx.com 
3038343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3039343Smax.romanov@nginx.com 
3040424Smax.romanov@nginx.com     port->app_pending_responses -= request_failed + got_response;
3041343Smax.romanov@nginx.com     port->app_responses += got_response;
3042343Smax.romanov@nginx.com 
3043427Smax.romanov@nginx.com     if (nxt_slow_path(app->live == 0)) {
3044427Smax.romanov@nginx.com         goto app_dead;
3045427Smax.romanov@nginx.com     }
3046427Smax.romanov@nginx.com 
3047427Smax.romanov@nginx.com     if (port->pair[1] != -1
3048426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
3049428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3050428Smax.romanov@nginx.com         && (app->max_requests == 0
3051428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3052428Smax.romanov@nginx.com                 < app->max_requests))
3053343Smax.romanov@nginx.com     {
3054424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
3055424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
3056424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
3057424Smax.romanov@nginx.com 
3058424Smax.romanov@nginx.com             } else {
3059424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3060424Smax.romanov@nginx.com             }
3061424Smax.romanov@nginx.com 
3062425Smax.romanov@nginx.com             nxt_port_inc_use(port);
3063424Smax.romanov@nginx.com 
3064424Smax.romanov@nginx.com         } else {
3065424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
3066424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
3067424Smax.romanov@nginx.com             {
3068424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
3069424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3070424Smax.romanov@nginx.com             }
3071424Smax.romanov@nginx.com         }
3072141Smax.romanov@nginx.com     }
3073141Smax.romanov@nginx.com 
3074427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
3075426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
3076343Smax.romanov@nginx.com     {
3077141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
3078141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3079343Smax.romanov@nginx.com         lnk->next = NULL;
3080141Smax.romanov@nginx.com 
3081425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3082425Smax.romanov@nginx.com 
3083427Smax.romanov@nginx.com         ra->app_port = nxt_router_pop_first_port(app);
3084425Smax.romanov@nginx.com 
3085425Smax.romanov@nginx.com         if (ra->app_port->app_pending_responses > 1) {
3086427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
3087425Smax.romanov@nginx.com         }
3088425Smax.romanov@nginx.com     }
3089425Smax.romanov@nginx.com 
3090427Smax.romanov@nginx.com app_dead:
3091427Smax.romanov@nginx.com 
3092427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
3093425Smax.romanov@nginx.com     if ((request_failed > 0 || got_response > 0)
3094425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
3095425Smax.romanov@nginx.com     {
3096425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
3097425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3098425Smax.romanov@nginx.com         lnk->next = NULL;
3099425Smax.romanov@nginx.com 
3100427Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
3101427Smax.romanov@nginx.com                                          link_port_pending);
3102427Smax.romanov@nginx.com 
3103427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
3104427Smax.romanov@nginx.com 
3105427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
3106427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
3107425Smax.romanov@nginx.com 
3108425Smax.romanov@nginx.com     } else {
3109427Smax.romanov@nginx.com         pending_ra = NULL;
3110141Smax.romanov@nginx.com     }
3111141Smax.romanov@nginx.com 
3112427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
3113427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
3114427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
3115427Smax.romanov@nginx.com 
3116427Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending);
3117427Smax.romanov@nginx.com 
3118427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
3119427Smax.romanov@nginx.com 
3120427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
3121427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
3122427Smax.romanov@nginx.com 
3123427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
3124427Smax.romanov@nginx.com                                               re_ra->stream);
3125427Smax.romanov@nginx.com 
3126427Smax.romanov@nginx.com             if (cancelled) {
3127427Smax.romanov@nginx.com                 nxt_router_ra_inc_use(re_ra);
3128427Smax.romanov@nginx.com 
3129427Smax.romanov@nginx.com                 state.ra = re_ra;
3130427Smax.romanov@nginx.com                 state.app = app;
3131427Smax.romanov@nginx.com 
3132427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
3133427Smax.romanov@nginx.com 
3134427Smax.romanov@nginx.com                 goto re_ra_cancelled;
3135427Smax.romanov@nginx.com             }
3136427Smax.romanov@nginx.com         }
3137427Smax.romanov@nginx.com     }
3138427Smax.romanov@nginx.com 
3139427Smax.romanov@nginx.com     re_ra = NULL;
3140427Smax.romanov@nginx.com 
3141427Smax.romanov@nginx.com re_ra_cancelled:
3142427Smax.romanov@nginx.com 
3143507Smax.romanov@nginx.com     send_quit = (app->live == 0 && port->app_pending_responses == 0)
3144428Smax.romanov@nginx.com                 || (app->max_requests > 0 && port->app_pending_responses == 0
3145428Smax.romanov@nginx.com                     && port->app_responses >= app->max_requests);
3146367Smax.romanov@nginx.com 
3147507Smax.romanov@nginx.com     if (send_quit) {
3148507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
3149507Smax.romanov@nginx.com 
3150507Smax.romanov@nginx.com         port->app = NULL;
3151507Smax.romanov@nginx.com         app->processes--;
3152507Smax.romanov@nginx.com 
3153507Smax.romanov@nginx.com     } else {
3154507Smax.romanov@nginx.com         port_unchained = 0;
3155507Smax.romanov@nginx.com     }
3156507Smax.romanov@nginx.com 
3157507Smax.romanov@nginx.com     adjust_idle_timer = 0;
3158507Smax.romanov@nginx.com 
3159507Smax.romanov@nginx.com     if (!send_quit && port->app_pending_responses == 0) {
3160507Smax.romanov@nginx.com         nxt_assert(port->idle_link.next == NULL);
3161507Smax.romanov@nginx.com 
3162507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
3163507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
3164507Smax.romanov@nginx.com         {
3165507Smax.romanov@nginx.com             adjust_idle_timer = 1;
3166507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
3167507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
3168507Smax.romanov@nginx.com         }
3169507Smax.romanov@nginx.com 
3170507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
3171507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
3172507Smax.romanov@nginx.com 
3173507Smax.romanov@nginx.com         } else {
3174507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
3175507Smax.romanov@nginx.com 
3176507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
3177507Smax.romanov@nginx.com         }
3178507Smax.romanov@nginx.com 
3179507Smax.romanov@nginx.com         app->idle_processes++;
3180507Smax.romanov@nginx.com     }
3181507Smax.romanov@nginx.com 
3182343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3183343Smax.romanov@nginx.com 
3184507Smax.romanov@nginx.com     if (adjust_idle_timer) {
3185507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
3186507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
3187507Smax.romanov@nginx.com     }
3188507Smax.romanov@nginx.com 
3189427Smax.romanov@nginx.com     if (pending_ra != NULL) {
3190427Smax.romanov@nginx.com         nxt_router_ra_use(task, pending_ra, -1);
3191427Smax.romanov@nginx.com     }
3192427Smax.romanov@nginx.com 
3193427Smax.romanov@nginx.com     if (re_ra != NULL) {
3194427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
3195427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3196427Smax.romanov@nginx.com                                nxt_router_app_process_request,
3197427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
3198427Smax.romanov@nginx.com         }
3199425Smax.romanov@nginx.com     }
3200425Smax.romanov@nginx.com 
3201343Smax.romanov@nginx.com     if (ra != NULL) {
3202425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3203425Smax.romanov@nginx.com 
3204343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3205343Smax.romanov@nginx.com                            nxt_router_app_process_request,
3206343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
3207343Smax.romanov@nginx.com 
3208343Smax.romanov@nginx.com         goto adjust_use;
3209343Smax.romanov@nginx.com     }
3210343Smax.romanov@nginx.com 
3211343Smax.romanov@nginx.com     /* ? */
3212163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
3213343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
3214343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
3215343Smax.romanov@nginx.com 
3216343Smax.romanov@nginx.com         goto adjust_use;
3217163Smax.romanov@nginx.com     }
3218163Smax.romanov@nginx.com 
3219367Smax.romanov@nginx.com     if (send_quit) {
3220507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
3221167Smax.romanov@nginx.com                   &app->name, app);
3222163Smax.romanov@nginx.com 
3223163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
3224163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
3225163Smax.romanov@nginx.com 
3226507Smax.romanov@nginx.com         if (port_unchained) {
3227507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
3228507Smax.romanov@nginx.com         }
3229507Smax.romanov@nginx.com 
3230507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
3231507Smax.romanov@nginx.com 
3232343Smax.romanov@nginx.com         goto adjust_use;
3233163Smax.romanov@nginx.com     }
3234163Smax.romanov@nginx.com 
3235167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
3236167Smax.romanov@nginx.com               &app->name, app);
3237141Smax.romanov@nginx.com 
3238343Smax.romanov@nginx.com adjust_use:
3239343Smax.romanov@nginx.com 
3240425Smax.romanov@nginx.com     if (request_failed > 0 || got_response > 0) {
3241425Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3242343Smax.romanov@nginx.com     }
3243141Smax.romanov@nginx.com }
3244141Smax.romanov@nginx.com 
3245141Smax.romanov@nginx.com 
3246343Smax.romanov@nginx.com void
3247343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
3248141Smax.romanov@nginx.com {
3249507Smax.romanov@nginx.com     nxt_app_t         *app;
3250507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
3251507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
3252507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
3253141Smax.romanov@nginx.com 
3254141Smax.romanov@nginx.com     app = port->app;
3255343Smax.romanov@nginx.com 
3256343Smax.romanov@nginx.com     nxt_assert(app != NULL);
3257141Smax.romanov@nginx.com 
3258141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3259141Smax.romanov@nginx.com 
3260507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
3261507Smax.romanov@nginx.com 
3262507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3263507Smax.romanov@nginx.com         app->idle_processes--;
3264507Smax.romanov@nginx.com 
3265507Smax.romanov@nginx.com         if (port->idle_start == 0
3266507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
3267507Smax.romanov@nginx.com         {
3268507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
3269507Smax.romanov@nginx.com 
3270507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
3271507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
3272507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
3273507Smax.romanov@nginx.com 
3274507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
3275507Smax.romanov@nginx.com 
3276507Smax.romanov@nginx.com             idle_port->idle_start = 0;
3277507Smax.romanov@nginx.com         }
3278343Smax.romanov@nginx.com     }
3279343Smax.romanov@nginx.com 
3280507Smax.romanov@nginx.com     app->processes--;
3281507Smax.romanov@nginx.com 
3282507Smax.romanov@nginx.com     start_process = app->live != 0
3283507Smax.romanov@nginx.com                     && !task->thread->engine->shutdown
3284507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
3285507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
3286507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
3287507Smax.romanov@nginx.com 
3288507Smax.romanov@nginx.com     if (start_process) {
3289507Smax.romanov@nginx.com         app->pending_processes++;
3290163Smax.romanov@nginx.com     }
3291141Smax.romanov@nginx.com 
3292141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3293163Smax.romanov@nginx.com 
3294507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
3295343Smax.romanov@nginx.com 
3296343Smax.romanov@nginx.com     if (unchain) {
3297343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3298163Smax.romanov@nginx.com     }
3299163Smax.romanov@nginx.com 
3300507Smax.romanov@nginx.com     if (start_process) {
3301507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
3302507Smax.romanov@nginx.com     }
3303507Smax.romanov@nginx.com }
3304507Smax.romanov@nginx.com 
3305507Smax.romanov@nginx.com 
3306507Smax.romanov@nginx.com static void
3307507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
3308507Smax.romanov@nginx.com {
3309507Smax.romanov@nginx.com     nxt_app_t           *app;
3310507Smax.romanov@nginx.com     nxt_bool_t          queued;
3311507Smax.romanov@nginx.com     nxt_port_t          *port;
3312507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
3313507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
3314507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
3315507Smax.romanov@nginx.com 
3316507Smax.romanov@nginx.com     app = obj;
3317507Smax.romanov@nginx.com     queued = (data == app);
3318507Smax.romanov@nginx.com 
3319507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
3320507Smax.romanov@nginx.com               &app->name, queued);
3321507Smax.romanov@nginx.com 
3322507Smax.romanov@nginx.com     engine = task->thread->engine;
3323507Smax.romanov@nginx.com 
3324507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
3325507Smax.romanov@nginx.com 
3326507Smax.romanov@nginx.com     threshold = engine->timers.now + app->idle_timer.precision;
3327507Smax.romanov@nginx.com     timeout = 0;
3328507Smax.romanov@nginx.com 
3329507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3330507Smax.romanov@nginx.com 
3331507Smax.romanov@nginx.com     if (queued) {
3332507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
3333343Smax.romanov@nginx.com     }
3334507Smax.romanov@nginx.com 
3335507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
3336507Smax.romanov@nginx.com 
3337507Smax.romanov@nginx.com         nxt_assert(nxt_queue_is_empty(&app->idle_ports) == 0);
3338507Smax.romanov@nginx.com 
3339507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
3340507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
3341507Smax.romanov@nginx.com 
3342507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
3343507Smax.romanov@nginx.com 
3344507Smax.romanov@nginx.com         if (timeout > threshold) {
3345507Smax.romanov@nginx.com             break;
3346507Smax.romanov@nginx.com         }
3347507Smax.romanov@nginx.com 
3348507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3349507Smax.romanov@nginx.com         lnk->next = NULL;
3350507Smax.romanov@nginx.com 
3351507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
3352507Smax.romanov@nginx.com 
3353507Smax.romanov@nginx.com         app->idle_processes--;
3354507Smax.romanov@nginx.com         app->processes--;
3355507Smax.romanov@nginx.com         port->app = NULL;
3356507Smax.romanov@nginx.com 
3357507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
3358507Smax.romanov@nginx.com 
3359507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
3360507Smax.romanov@nginx.com                   &app->name, port->pid);
3361507Smax.romanov@nginx.com 
3362507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3363507Smax.romanov@nginx.com 
3364507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3365507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
3366507Smax.romanov@nginx.com 
3367507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
3368507Smax.romanov@nginx.com     }
3369507Smax.romanov@nginx.com 
3370507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3371507Smax.romanov@nginx.com 
3372507Smax.romanov@nginx.com     if (timeout > threshold) {
3373507Smax.romanov@nginx.com         nxt_timer_add(engine, &app->idle_timer, timeout - threshold);
3374507Smax.romanov@nginx.com 
3375507Smax.romanov@nginx.com     } else {
3376507Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->idle_timer);
3377507Smax.romanov@nginx.com     }
3378507Smax.romanov@nginx.com 
3379507Smax.romanov@nginx.com     if (queued) {
3380507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
3381507Smax.romanov@nginx.com     }
3382507Smax.romanov@nginx.com }
3383507Smax.romanov@nginx.com 
3384507Smax.romanov@nginx.com 
3385507Smax.romanov@nginx.com static void
3386507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
3387507Smax.romanov@nginx.com {
3388507Smax.romanov@nginx.com     nxt_app_t    *app;
3389507Smax.romanov@nginx.com     nxt_timer_t  *timer;
3390507Smax.romanov@nginx.com 
3391507Smax.romanov@nginx.com     timer = obj;
3392507Smax.romanov@nginx.com     app = nxt_container_of(timer, nxt_app_t, idle_timer);
3393507Smax.romanov@nginx.com 
3394507Smax.romanov@nginx.com     nxt_router_adjust_idle_timer(task, app, NULL);
3395507Smax.romanov@nginx.com }
3396507Smax.romanov@nginx.com 
3397507Smax.romanov@nginx.com 
3398507Smax.romanov@nginx.com static void
3399507Smax.romanov@nginx.com nxt_router_app_release_handler(nxt_task_t *task, void *obj, void *data)
3400507Smax.romanov@nginx.com {
3401507Smax.romanov@nginx.com     nxt_app_t    *app;
3402507Smax.romanov@nginx.com     nxt_timer_t  *timer;
3403507Smax.romanov@nginx.com 
3404507Smax.romanov@nginx.com     timer = obj;
3405507Smax.romanov@nginx.com     app = nxt_container_of(timer, nxt_app_t, idle_timer);
3406507Smax.romanov@nginx.com 
3407507Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
3408141Smax.romanov@nginx.com }
3409141Smax.romanov@nginx.com 
3410141Smax.romanov@nginx.com 
3411427Smax.romanov@nginx.com static void
3412427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
3413141Smax.romanov@nginx.com {
3414427Smax.romanov@nginx.com     nxt_app_t           *app;
3415507Smax.romanov@nginx.com     nxt_bool_t          can_start_process;
3416427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3417427Smax.romanov@nginx.com 
3418427Smax.romanov@nginx.com     ra = state->ra;
3419427Smax.romanov@nginx.com     app = state->app;
3420427Smax.romanov@nginx.com 
3421427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
3422343Smax.romanov@nginx.com 
3423425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_app_requests))
3424425Smax.romanov@nginx.com     {
3425425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
3426425Smax.romanov@nginx.com     }
3427425Smax.romanov@nginx.com 
3428425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_port_pending))
3429425Smax.romanov@nginx.com     {
3430427Smax.romanov@nginx.com         nxt_assert(ra->link_app_pending.next != NULL);
3431427Smax.romanov@nginx.com 
3432427Smax.romanov@nginx.com         nxt_queue_remove(&ra->link_app_pending);
3433427Smax.romanov@nginx.com         ra->link_app_pending.next = NULL;
3434427Smax.romanov@nginx.com 
3435425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
3436425Smax.romanov@nginx.com     }
3437425Smax.romanov@nginx.com 
3438427Smax.romanov@nginx.com     state->failed_port = ra->app_port;
3439427Smax.romanov@nginx.com 
3440425Smax.romanov@nginx.com     if (ra->app_port != NULL) {
3441427Smax.romanov@nginx.com         state->failed_port_use_delta--;
3442427Smax.romanov@nginx.com 
3443427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
3444427Smax.romanov@nginx.com 
3445427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
3446427Smax.romanov@nginx.com             state->failed_port_use_delta--;
3447427Smax.romanov@nginx.com         }
3448427Smax.romanov@nginx.com 
3449427Smax.romanov@nginx.com         ra->app_port = NULL;
3450427Smax.romanov@nginx.com     }
3451427Smax.romanov@nginx.com 
3452507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
3453507Smax.romanov@nginx.com 
3454427Smax.romanov@nginx.com     state->port = NULL;
3455507Smax.romanov@nginx.com     state->start_process = 0;
3456427Smax.romanov@nginx.com 
3457427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
3458507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
3459427Smax.romanov@nginx.com     {
3460427Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
3461427Smax.romanov@nginx.com 
3462427Smax.romanov@nginx.com         if (nxt_slow_path(ra == NULL)) {
3463427Smax.romanov@nginx.com             goto fail;
3464427Smax.romanov@nginx.com         }
3465427Smax.romanov@nginx.com 
3466427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
3467427Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests, &ra->link_app_requests);
3468427Smax.romanov@nginx.com 
3469427Smax.romanov@nginx.com         } else {
3470427Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link_app_requests);
3471427Smax.romanov@nginx.com         }
3472427Smax.romanov@nginx.com 
3473427Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
3474427Smax.romanov@nginx.com 
3475427Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream);
3476427Smax.romanov@nginx.com 
3477507Smax.romanov@nginx.com         if (can_start_process) {
3478507Smax.romanov@nginx.com             app->pending_processes++;
3479507Smax.romanov@nginx.com             state->start_process = 1;
3480425Smax.romanov@nginx.com         }
3481425Smax.romanov@nginx.com 
3482425Smax.romanov@nginx.com     } else {
3483427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
3484427Smax.romanov@nginx.com 
3485427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
3486427Smax.romanov@nginx.com             ra = nxt_router_ra_create(task, ra);
3487427Smax.romanov@nginx.com 
3488427Smax.romanov@nginx.com             if (nxt_slow_path(ra == NULL)) {
3489427Smax.romanov@nginx.com                 goto fail;
3490351Smax.romanov@nginx.com             }
3491427Smax.romanov@nginx.com 
3492427Smax.romanov@nginx.com             ra->app_port = state->port;
3493427Smax.romanov@nginx.com 
3494427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
3495425Smax.romanov@nginx.com         }
3496507Smax.romanov@nginx.com 
3497507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
3498507Smax.romanov@nginx.com             app->pending_processes++;
3499507Smax.romanov@nginx.com             state->start_process = 1;
3500507Smax.romanov@nginx.com         }
3501343Smax.romanov@nginx.com     }
3502343Smax.romanov@nginx.com 
3503427Smax.romanov@nginx.com fail:
3504427Smax.romanov@nginx.com 
3505427Smax.romanov@nginx.com     state->shared_ra = ra;
3506427Smax.romanov@nginx.com }
3507427Smax.romanov@nginx.com 
3508427Smax.romanov@nginx.com 
3509427Smax.romanov@nginx.com static nxt_int_t
3510427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
3511427Smax.romanov@nginx.com {
3512427Smax.romanov@nginx.com     nxt_int_t           res;
3513427Smax.romanov@nginx.com     nxt_app_t           *app;
3514427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3515427Smax.romanov@nginx.com 
3516427Smax.romanov@nginx.com     ra = state->shared_ra;
3517427Smax.romanov@nginx.com     app = state->app;
3518427Smax.romanov@nginx.com 
3519427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
3520427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
3521425Smax.romanov@nginx.com     }
3522425Smax.romanov@nginx.com 
3523351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
3524427Smax.romanov@nginx.com         if (state->port != NULL) {
3525427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
3526425Smax.romanov@nginx.com         }
3527425Smax.romanov@nginx.com 
3528427Smax.romanov@nginx.com         nxt_router_ra_error(state->ra, 500,
3529427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
3530427Smax.romanov@nginx.com         nxt_router_ra_use(task, state->ra, -1);
3531427Smax.romanov@nginx.com 
3532351Smax.romanov@nginx.com         return NXT_ERROR;
3533351Smax.romanov@nginx.com     }
3534351Smax.romanov@nginx.com 
3535427Smax.romanov@nginx.com     if (state->port != NULL) {
3536343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
3537163Smax.romanov@nginx.com 
3538427Smax.romanov@nginx.com         ra->app_port = state->port;
3539343Smax.romanov@nginx.com 
3540507Smax.romanov@nginx.com         if (state->start_process) {
3541507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
3542507Smax.romanov@nginx.com         }
3543507Smax.romanov@nginx.com 
3544141Smax.romanov@nginx.com         return NXT_OK;
3545141Smax.romanov@nginx.com     }
3546141Smax.romanov@nginx.com 
3547507Smax.romanov@nginx.com     if (!state->start_process) {
3548507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
3549343Smax.romanov@nginx.com                   &app->name, app);
3550343Smax.romanov@nginx.com 
3551343Smax.romanov@nginx.com         return NXT_AGAIN;
3552343Smax.romanov@nginx.com     }
3553343Smax.romanov@nginx.com 
3554507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
3555343Smax.romanov@nginx.com 
3556343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3557507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start app process");
3558427Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3559343Smax.romanov@nginx.com 
3560141Smax.romanov@nginx.com         return NXT_ERROR;
3561141Smax.romanov@nginx.com     }
3562141Smax.romanov@nginx.com 
3563141Smax.romanov@nginx.com     return NXT_AGAIN;
356488Smax.romanov@nginx.com }
356588Smax.romanov@nginx.com 
356688Smax.romanov@nginx.com 
3567427Smax.romanov@nginx.com static nxt_int_t
3568427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
3569427Smax.romanov@nginx.com {
3570427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
3571427Smax.romanov@nginx.com 
3572427Smax.romanov@nginx.com     state.ra = ra;
3573427Smax.romanov@nginx.com     state.app = app;
3574427Smax.romanov@nginx.com 
3575427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3576427Smax.romanov@nginx.com 
3577427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
3578427Smax.romanov@nginx.com 
3579427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3580427Smax.romanov@nginx.com 
3581427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
3582427Smax.romanov@nginx.com }
3583427Smax.romanov@nginx.com 
3584427Smax.romanov@nginx.com 
3585431Sigor@sysoev.ru void
3586431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar)
358753Sigor@sysoev.ru {
3588431Sigor@sysoev.ru     nxt_int_t            res;
3589431Sigor@sysoev.ru     nxt_app_t            *app;
3590431Sigor@sysoev.ru     nxt_port_t           *port;
3591431Sigor@sysoev.ru     nxt_event_engine_t   *engine;
3592431Sigor@sysoev.ru     nxt_http_request_t   *r;
3593431Sigor@sysoev.ru     nxt_req_app_link_t   ra_local, *ra;
3594431Sigor@sysoev.ru     nxt_req_conn_link_t  *rc;
3595431Sigor@sysoev.ru 
3596431Sigor@sysoev.ru     r = ar->request;
3597431Sigor@sysoev.ru     app = r->socket_conf->application;
3598425Smax.romanov@nginx.com 
3599425Smax.romanov@nginx.com     if (app == NULL) {
3600431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
3601425Smax.romanov@nginx.com         return;
3602425Smax.romanov@nginx.com     }
360388Smax.romanov@nginx.com 
360488Smax.romanov@nginx.com     engine = task->thread->engine;
360588Smax.romanov@nginx.com 
3606318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
3607318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
3608318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
3609318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
3610122Smax.romanov@nginx.com 
361188Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
3612431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
3613141Smax.romanov@nginx.com         return;
361488Smax.romanov@nginx.com     }
361588Smax.romanov@nginx.com 
3616318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
3617425Smax.romanov@nginx.com     rc->app = app;
3618425Smax.romanov@nginx.com 
3619425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
3620425Smax.romanov@nginx.com 
3621431Sigor@sysoev.ru     rc->ap = ar;
3622346Smax.romanov@nginx.com 
3623351Smax.romanov@nginx.com     ra = &ra_local;
3624351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
3625167Smax.romanov@nginx.com 
3626427Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, ra);
3627141Smax.romanov@nginx.com 
3628141Smax.romanov@nginx.com     if (res != NXT_OK) {
3629141Smax.romanov@nginx.com         return;
3630141Smax.romanov@nginx.com     }
3631141Smax.romanov@nginx.com 
3632425Smax.romanov@nginx.com     ra = rc->ra;
3633167Smax.romanov@nginx.com     port = ra->app_port;
3634141Smax.romanov@nginx.com 
3635425Smax.romanov@nginx.com     nxt_assert(port != NULL);
3636141Smax.romanov@nginx.com 
3637318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
3638318Smax.romanov@nginx.com 
3639425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
3640167Smax.romanov@nginx.com }
3641167Smax.romanov@nginx.com 
3642167Smax.romanov@nginx.com 
3643167Smax.romanov@nginx.com static void
3644423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
3645423Smax.romanov@nginx.com {
3646423Smax.romanov@nginx.com }
3647423Smax.romanov@nginx.com 
3648423Smax.romanov@nginx.com 
3649423Smax.romanov@nginx.com static void
3650425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
3651167Smax.romanov@nginx.com {
3652343Smax.romanov@nginx.com     uint32_t             request_failed;
3653423Smax.romanov@nginx.com     nxt_buf_t            *b;
3654167Smax.romanov@nginx.com     nxt_int_t            res;
3655343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
3656167Smax.romanov@nginx.com     nxt_app_wmsg_t       wmsg;
3657167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
3658167Smax.romanov@nginx.com 
3659343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3660343Smax.romanov@nginx.com 
3661343Smax.romanov@nginx.com     port = ra->app_port;
3662167Smax.romanov@nginx.com     reply_port = ra->reply_port;
3663167Smax.romanov@nginx.com     ap = ra->ap;
3664141Smax.romanov@nginx.com 
3665343Smax.romanov@nginx.com     request_failed = 1;
3666343Smax.romanov@nginx.com 
3667141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
3668141Smax.romanov@nginx.com                                              reply_port->id);
3669141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
3670141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
3671122Smax.romanov@nginx.com 
3672122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
3673423Smax.romanov@nginx.com             nxt_router_ra_error(ra, 500,
3674345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
3675343Smax.romanov@nginx.com             goto release_port;
3676122Smax.romanov@nginx.com         }
3677122Smax.romanov@nginx.com 
3678141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
367988Smax.romanov@nginx.com     }
368088Smax.romanov@nginx.com 
368188Smax.romanov@nginx.com     wmsg.port = port;
368288Smax.romanov@nginx.com     wmsg.write = NULL;
368388Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
3684318Smax.romanov@nginx.com     wmsg.stream = ra->stream;
3685167Smax.romanov@nginx.com 
3686216Sigor@sysoev.ru     res = port->app->prepare_msg(task, &ap->r, &wmsg);
3687122Smax.romanov@nginx.com 
3688122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3689423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
3690345Smax.romanov@nginx.com                             "Failed to prepare message for application");
3691343Smax.romanov@nginx.com         goto release_port;
3692122Smax.romanov@nginx.com     }
369388Smax.romanov@nginx.com 
3694507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
369588Smax.romanov@nginx.com                     nxt_buf_used_size(wmsg.write),
369688Smax.romanov@nginx.com                     wmsg.port->socket.fd);
369788Smax.romanov@nginx.com 
3698343Smax.romanov@nginx.com     request_failed = 0;
3699343Smax.romanov@nginx.com 
3700423Smax.romanov@nginx.com     ra->msg_info.buf = wmsg.write;
3701423Smax.romanov@nginx.com     ra->msg_info.completion_handler = wmsg.write->completion_handler;
3702423Smax.romanov@nginx.com 
3703423Smax.romanov@nginx.com     for (b = wmsg.write; b != NULL; b = b->next) {
3704423Smax.romanov@nginx.com         b->completion_handler = nxt_router_dummy_buf_completion;
3705423Smax.romanov@nginx.com     }
3706423Smax.romanov@nginx.com 
3707423Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking,
3708423Smax.romanov@nginx.com                                      ra->stream);
3709423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3710423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
3711423Smax.romanov@nginx.com                             "Failed to get tracking area");
3712423Smax.romanov@nginx.com         goto release_port;
3713423Smax.romanov@nginx.com     }
3714423Smax.romanov@nginx.com 
3715423Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, wmsg.port, NXT_PORT_MSG_DATA,
3716423Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, wmsg.write,
3717423Smax.romanov@nginx.com                                  &ra->msg_info.tracking);
3718122Smax.romanov@nginx.com 
3719122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
3720423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
3721345Smax.romanov@nginx.com                             "Failed to send message to application");
3722343Smax.romanov@nginx.com         goto release_port;
3723122Smax.romanov@nginx.com     }
3724343Smax.romanov@nginx.com 
3725343Smax.romanov@nginx.com release_port:
3726343Smax.romanov@nginx.com 
3727345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
3728345Smax.romanov@nginx.com 
3729425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
373053Sigor@sysoev.ru }
373153Sigor@sysoev.ru 
373253Sigor@sysoev.ru 
3733216Sigor@sysoev.ru static nxt_int_t
3734216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3735216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3736216Sigor@sysoev.ru {
3737216Sigor@sysoev.ru     nxt_int_t                 rc;
3738216Sigor@sysoev.ru     nxt_buf_t                 *b;
3739216Sigor@sysoev.ru     nxt_http_field_t          *field;
3740216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3741216Sigor@sysoev.ru 
3742216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3743216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3744216Sigor@sysoev.ru 
3745216Sigor@sysoev.ru     h = &r->header;
3746216Sigor@sysoev.ru 
3747216Sigor@sysoev.ru #define RC(S)                                                                 \
3748216Sigor@sysoev.ru     do {                                                                      \
3749216Sigor@sysoev.ru         rc = (S);                                                             \
3750216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3751216Sigor@sysoev.ru             goto fail;                                                        \
3752216Sigor@sysoev.ru         }                                                                     \
3753216Sigor@sysoev.ru     } while(0)
3754216Sigor@sysoev.ru 
3755216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3756216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3757216Sigor@sysoev.ru 
3758216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3759216Sigor@sysoev.ru 
3760216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3761216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3762277Sigor@sysoev.ru 
3763216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3764216Sigor@sysoev.ru         NXT_WRITE(&eof);
3765277Sigor@sysoev.ru 
3766216Sigor@sysoev.ru     } else {
3767216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3768216Sigor@sysoev.ru     }
3769216Sigor@sysoev.ru 
3770216Sigor@sysoev.ru     if (h->query.start != NULL) {
3771216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3772216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3773216Sigor@sysoev.ru     } else {
3774216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3775216Sigor@sysoev.ru     }
3776216Sigor@sysoev.ru 
3777216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3778216Sigor@sysoev.ru 
3779216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3780268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3781216Sigor@sysoev.ru 
3782216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3783216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3784216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3785216Sigor@sysoev.ru 
3786216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3787417Svbart@nginx.com         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name,
3788417Svbart@nginx.com                                              field->name_length));
3789417Svbart@nginx.com         RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
3790216Sigor@sysoev.ru 
3791216Sigor@sysoev.ru     } nxt_list_loop;
3792216Sigor@sysoev.ru 
3793216Sigor@sysoev.ru     /* end-of-headers mark */
3794216Sigor@sysoev.ru     NXT_WRITE(&eof);
3795216Sigor@sysoev.ru 
3796216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3797216Sigor@sysoev.ru 
3798*510Salexander.borisov@nginx.com     for (b = r->body.buf; b != NULL; b = b->next) {
3799216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3800216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
3801216Sigor@sysoev.ru     }
3802216Sigor@sysoev.ru 
3803216Sigor@sysoev.ru #undef NXT_WRITE
3804216Sigor@sysoev.ru #undef RC
3805216Sigor@sysoev.ru 
3806216Sigor@sysoev.ru     return NXT_OK;
3807216Sigor@sysoev.ru 
3808216Sigor@sysoev.ru fail:
3809216Sigor@sysoev.ru 
3810216Sigor@sysoev.ru     return NXT_ERROR;
3811216Sigor@sysoev.ru }
3812216Sigor@sysoev.ru 
3813216Sigor@sysoev.ru 
3814216Sigor@sysoev.ru static nxt_int_t
3815216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3816216Sigor@sysoev.ru     nxt_app_wmsg_t *wmsg)
3817216Sigor@sysoev.ru {
3818216Sigor@sysoev.ru     nxt_int_t                 rc;
3819216Sigor@sysoev.ru     nxt_buf_t                 *b;
3820305Smax.romanov@nginx.com     nxt_bool_t                method_is_post;
3821216Sigor@sysoev.ru     nxt_http_field_t          *field;
3822216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3823216Sigor@sysoev.ru 
3824216Sigor@sysoev.ru     static const nxt_str_t prefix = nxt_string("HTTP_");
3825216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3826216Sigor@sysoev.ru 
3827216Sigor@sysoev.ru     h = &r->header;
3828216Sigor@sysoev.ru 
3829216Sigor@sysoev.ru #define RC(S)                                                                 \
3830216Sigor@sysoev.ru     do {                                                                      \
3831216Sigor@sysoev.ru         rc = (S);                                                             \
3832216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3833216Sigor@sysoev.ru             goto fail;                                                        \
3834216Sigor@sysoev.ru         }                                                                     \
3835216Sigor@sysoev.ru     } while(0)
3836216Sigor@sysoev.ru 
3837216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3838216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3839216Sigor@sysoev.ru 
3840216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3841216Sigor@sysoev.ru 
3842216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3843216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3844277Sigor@sysoev.ru 
3845216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3846216Sigor@sysoev.ru         NXT_WRITE(&eof);
3847277Sigor@sysoev.ru 
3848216Sigor@sysoev.ru     } else {
3849216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3850216Sigor@sysoev.ru     }
3851216Sigor@sysoev.ru 
3852216Sigor@sysoev.ru     if (h->query.start != NULL) {
3853216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3854216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3855216Sigor@sysoev.ru     } else {
3856216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3857216Sigor@sysoev.ru     }
3858216Sigor@sysoev.ru 
3859216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3860216Sigor@sysoev.ru 
3861216Sigor@sysoev.ru     // PHP_SELF
3862216Sigor@sysoev.ru     // SCRIPT_NAME
3863216Sigor@sysoev.ru     // SCRIPT_FILENAME
3864216Sigor@sysoev.ru     // DOCUMENT_ROOT
3865216Sigor@sysoev.ru 
3866216Sigor@sysoev.ru     NXT_WRITE(&r->remote);
3867268Sigor@sysoev.ru     NXT_WRITE(&r->local);
3868216Sigor@sysoev.ru 
3869216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3870216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3871216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3872216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3873216Sigor@sysoev.ru 
3874216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3875305Smax.romanov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3876305Smax.romanov@nginx.com 
3877426Smax.romanov@nginx.com     method_is_post = h->method.length == 4
3878426Smax.romanov@nginx.com                      && h->method.start[0] == 'P'
3879426Smax.romanov@nginx.com                      && h->method.start[1] == 'O'
3880426Smax.romanov@nginx.com                      && h->method.start[2] == 'S'
3881426Smax.romanov@nginx.com                      && h->method.start[3] == 'T';
3882305Smax.romanov@nginx.com 
3883305Smax.romanov@nginx.com     if (method_is_post) {
3884*510Salexander.borisov@nginx.com         for (b = r->body.buf; b != NULL; b = b->next) {
3885305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3886305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3887305Smax.romanov@nginx.com         }
3888305Smax.romanov@nginx.com     }
3889216Sigor@sysoev.ru 
3890216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3891417Svbart@nginx.com         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name,
3892417Svbart@nginx.com                                              field->name_length));
3893417Svbart@nginx.com         RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
3894216Sigor@sysoev.ru 
3895216Sigor@sysoev.ru     } nxt_list_loop;
3896216Sigor@sysoev.ru 
3897216Sigor@sysoev.ru     /* end-of-headers mark */
3898216Sigor@sysoev.ru     NXT_WRITE(&eof);
3899216Sigor@sysoev.ru 
3900305Smax.romanov@nginx.com     if (!method_is_post) {
3901*510Salexander.borisov@nginx.com         for (b = r->body.buf; b != NULL; b = b->next) {
3902305Smax.romanov@nginx.com             RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3903305Smax.romanov@nginx.com                                      nxt_buf_mem_used_size(&b->mem)));
3904305Smax.romanov@nginx.com         }
3905216Sigor@sysoev.ru     }
3906216Sigor@sysoev.ru 
3907216Sigor@sysoev.ru #undef NXT_WRITE
3908216Sigor@sysoev.ru #undef RC
3909216Sigor@sysoev.ru 
3910216Sigor@sysoev.ru     return NXT_OK;
3911216Sigor@sysoev.ru 
3912216Sigor@sysoev.ru fail:
3913216Sigor@sysoev.ru 
3914216Sigor@sysoev.ru     return NXT_ERROR;
3915216Sigor@sysoev.ru }
3916216Sigor@sysoev.ru 
3917216Sigor@sysoev.ru 
3918216Sigor@sysoev.ru static nxt_int_t
3919216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
3920216Sigor@sysoev.ru {
3921216Sigor@sysoev.ru     nxt_int_t                 rc;
3922216Sigor@sysoev.ru     nxt_buf_t                 *b;
3923216Sigor@sysoev.ru     nxt_http_field_t          *field;
3924216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
3925216Sigor@sysoev.ru 
3926216Sigor@sysoev.ru     static const nxt_str_t eof = nxt_null_string;
3927216Sigor@sysoev.ru 
3928216Sigor@sysoev.ru     h = &r->header;
3929216Sigor@sysoev.ru 
3930216Sigor@sysoev.ru #define RC(S)                                                                 \
3931216Sigor@sysoev.ru     do {                                                                      \
3932216Sigor@sysoev.ru         rc = (S);                                                             \
3933216Sigor@sysoev.ru         if (nxt_slow_path(rc != NXT_OK)) {                                    \
3934216Sigor@sysoev.ru             goto fail;                                                        \
3935216Sigor@sysoev.ru         }                                                                     \
3936216Sigor@sysoev.ru     } while(0)
3937216Sigor@sysoev.ru 
3938216Sigor@sysoev.ru #define NXT_WRITE(N)                                                          \
3939216Sigor@sysoev.ru     RC(nxt_app_msg_write_str(task, wmsg, N))
3940216Sigor@sysoev.ru 
3941216Sigor@sysoev.ru     /* TODO error handle, async mmap buffer assignment */
3942216Sigor@sysoev.ru 
3943216Sigor@sysoev.ru     NXT_WRITE(&h->method);
3944216Sigor@sysoev.ru     NXT_WRITE(&h->target);
3945277Sigor@sysoev.ru 
3946216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
3947216Sigor@sysoev.ru         NXT_WRITE(&eof);
3948277Sigor@sysoev.ru 
3949216Sigor@sysoev.ru     } else {
3950216Sigor@sysoev.ru         NXT_WRITE(&h->path);
3951216Sigor@sysoev.ru     }
3952216Sigor@sysoev.ru 
3953216Sigor@sysoev.ru     if (h->query.start != NULL) {
3954216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg,
3955216Sigor@sysoev.ru                                   h->query.start - h->target.start + 1));
3956216Sigor@sysoev.ru     } else {
3957216Sigor@sysoev.ru         RC(nxt_app_msg_write_size(task, wmsg, 0));
3958216Sigor@sysoev.ru     }
3959216Sigor@sysoev.ru 
3960216Sigor@sysoev.ru     NXT_WRITE(&h->version);
3961253Smax.romanov@nginx.com     NXT_WRITE(&r->remote);
3962216Sigor@sysoev.ru 
3963216Sigor@sysoev.ru     NXT_WRITE(&h->host);
3964216Sigor@sysoev.ru     NXT_WRITE(&h->cookie);
3965216Sigor@sysoev.ru     NXT_WRITE(&h->content_type);
3966216Sigor@sysoev.ru     NXT_WRITE(&h->content_length);
3967216Sigor@sysoev.ru 
3968216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
3969216Sigor@sysoev.ru 
3970216Sigor@sysoev.ru     nxt_list_each(field, h->fields) {
3971417Svbart@nginx.com         RC(nxt_app_msg_write(task, wmsg, field->name, field->name_length));
3972417Svbart@nginx.com         RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
3973216Sigor@sysoev.ru 
3974216Sigor@sysoev.ru     } nxt_list_loop;
3975216Sigor@sysoev.ru 
3976216Sigor@sysoev.ru     /* end-of-headers mark */
3977216Sigor@sysoev.ru     NXT_WRITE(&eof);
3978216Sigor@sysoev.ru 
3979216Sigor@sysoev.ru     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
3980216Sigor@sysoev.ru 
3981*510Salexander.borisov@nginx.com     for (b = r->body.buf; b != NULL; b = b->next) {
3982*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
3983*510Salexander.borisov@nginx.com                                  nxt_buf_mem_used_size(&b->mem)));
3984*510Salexander.borisov@nginx.com     }
3985*510Salexander.borisov@nginx.com 
3986*510Salexander.borisov@nginx.com #undef NXT_WRITE
3987*510Salexander.borisov@nginx.com #undef RC
3988*510Salexander.borisov@nginx.com 
3989*510Salexander.borisov@nginx.com     return NXT_OK;
3990*510Salexander.borisov@nginx.com 
3991*510Salexander.borisov@nginx.com fail:
3992*510Salexander.borisov@nginx.com 
3993*510Salexander.borisov@nginx.com     return NXT_ERROR;
3994*510Salexander.borisov@nginx.com }
3995*510Salexander.borisov@nginx.com 
3996*510Salexander.borisov@nginx.com 
3997*510Salexander.borisov@nginx.com static nxt_int_t
3998*510Salexander.borisov@nginx.com nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
3999*510Salexander.borisov@nginx.com     nxt_app_wmsg_t *wmsg)
4000*510Salexander.borisov@nginx.com {
4001*510Salexander.borisov@nginx.com     nxt_int_t                 rc;
4002*510Salexander.borisov@nginx.com     nxt_str_t                 str;
4003*510Salexander.borisov@nginx.com     nxt_buf_t                 *b;
4004*510Salexander.borisov@nginx.com     nxt_http_field_t          *field;
4005*510Salexander.borisov@nginx.com     nxt_app_request_header_t  *h;
4006*510Salexander.borisov@nginx.com 
4007*510Salexander.borisov@nginx.com     static const nxt_str_t prefix = nxt_string("HTTP_");
4008*510Salexander.borisov@nginx.com     static const nxt_str_t eof = nxt_null_string;
4009*510Salexander.borisov@nginx.com 
4010*510Salexander.borisov@nginx.com     h = &r->header;
4011*510Salexander.borisov@nginx.com 
4012*510Salexander.borisov@nginx.com #define RC(S)                                                                 \
4013*510Salexander.borisov@nginx.com     do {                                                                      \
4014*510Salexander.borisov@nginx.com         rc = (S);                                                             \
4015*510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {                                    \
4016*510Salexander.borisov@nginx.com             goto fail;                                                        \
4017*510Salexander.borisov@nginx.com         }                                                                     \
4018*510Salexander.borisov@nginx.com     } while(0)
4019*510Salexander.borisov@nginx.com 
4020*510Salexander.borisov@nginx.com #define NXT_WRITE(N)                                                          \
4021*510Salexander.borisov@nginx.com     RC(nxt_app_msg_write_str(task, wmsg, N))
4022*510Salexander.borisov@nginx.com 
4023*510Salexander.borisov@nginx.com     /* TODO error handle, async mmap buffer assignment */
4024*510Salexander.borisov@nginx.com 
4025*510Salexander.borisov@nginx.com     NXT_WRITE(&h->method);
4026*510Salexander.borisov@nginx.com     NXT_WRITE(&h->target);
4027*510Salexander.borisov@nginx.com 
4028*510Salexander.borisov@nginx.com     if (h->query.length) {
4029*510Salexander.borisov@nginx.com         str.start = h->target.start;
4030*510Salexander.borisov@nginx.com         str.length = (h->target.length - h->query.length) - 1;
4031*510Salexander.borisov@nginx.com 
4032*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write_str(task, wmsg, &str));
4033*510Salexander.borisov@nginx.com 
4034*510Salexander.borisov@nginx.com     } else {
4035*510Salexander.borisov@nginx.com         NXT_WRITE(&eof);
4036*510Salexander.borisov@nginx.com     }
4037*510Salexander.borisov@nginx.com 
4038*510Salexander.borisov@nginx.com     if (h->query.start != NULL) {
4039*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write_size(task, wmsg,
4040*510Salexander.borisov@nginx.com                                   h->query.start - h->target.start + 1));
4041*510Salexander.borisov@nginx.com     } else {
4042*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write_size(task, wmsg, 0));
4043*510Salexander.borisov@nginx.com     }
4044*510Salexander.borisov@nginx.com 
4045*510Salexander.borisov@nginx.com     NXT_WRITE(&h->version);
4046*510Salexander.borisov@nginx.com 
4047*510Salexander.borisov@nginx.com     NXT_WRITE(&r->remote);
4048*510Salexander.borisov@nginx.com     NXT_WRITE(&r->local);
4049*510Salexander.borisov@nginx.com 
4050*510Salexander.borisov@nginx.com     NXT_WRITE(&h->host);
4051*510Salexander.borisov@nginx.com     NXT_WRITE(&h->content_type);
4052*510Salexander.borisov@nginx.com     NXT_WRITE(&h->content_length);
4053*510Salexander.borisov@nginx.com 
4054*510Salexander.borisov@nginx.com     nxt_list_each(field, h->fields) {
4055*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix,
4056*510Salexander.borisov@nginx.com                                              field->name, field->name_length));
4057*510Salexander.borisov@nginx.com         RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
4058*510Salexander.borisov@nginx.com     } nxt_list_loop;
4059*510Salexander.borisov@nginx.com 
4060*510Salexander.borisov@nginx.com     /* end-of-headers mark */
4061*510Salexander.borisov@nginx.com     NXT_WRITE(&eof);
4062*510Salexander.borisov@nginx.com 
4063*510Salexander.borisov@nginx.com     RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
4064*510Salexander.borisov@nginx.com 
4065*510Salexander.borisov@nginx.com     for (b = r->body.buf; b != NULL; b = b->next) {
4066*510Salexander.borisov@nginx.com 
4067216Sigor@sysoev.ru         RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
4068216Sigor@sysoev.ru                                  nxt_buf_mem_used_size(&b->mem)));
4069216Sigor@sysoev.ru     }
4070216Sigor@sysoev.ru 
4071216Sigor@sysoev.ru #undef NXT_WRITE
4072216Sigor@sysoev.ru #undef RC
4073216Sigor@sysoev.ru 
4074216Sigor@sysoev.ru     return NXT_OK;
4075216Sigor@sysoev.ru 
4076216Sigor@sysoev.ru fail:
4077216Sigor@sysoev.ru 
4078216Sigor@sysoev.ru     return NXT_ERROR;
4079216Sigor@sysoev.ru }
4080216Sigor@sysoev.ru 
4081216Sigor@sysoev.ru 
4082431Sigor@sysoev.ru const nxt_conn_state_t  nxt_router_conn_close_state
408353Sigor@sysoev.ru     nxt_aligned(64) =
408453Sigor@sysoev.ru {
408553Sigor@sysoev.ru     .ready_handler = nxt_router_conn_free,
408653Sigor@sysoev.ru };
408753Sigor@sysoev.ru 
408853Sigor@sysoev.ru 
408953Sigor@sysoev.ru static void
4090164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data)
4091164Smax.romanov@nginx.com {
4092164Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
4093164Smax.romanov@nginx.com 
4094164Smax.romanov@nginx.com     joint = obj;
4095164Smax.romanov@nginx.com 
4096164Smax.romanov@nginx.com     nxt_router_conf_release(task, joint);
4097164Smax.romanov@nginx.com }
4098164Smax.romanov@nginx.com 
4099164Smax.romanov@nginx.com 
4100164Smax.romanov@nginx.com static void
410153Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data)
410253Sigor@sysoev.ru {
410362Sigor@sysoev.ru     nxt_conn_t               *c;
4104337Sigor@sysoev.ru     nxt_event_engine_t       *engine;
410553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
410653Sigor@sysoev.ru 
410753Sigor@sysoev.ru     c = obj;
410853Sigor@sysoev.ru 
410953Sigor@sysoev.ru     nxt_debug(task, "router conn close done");
411053Sigor@sysoev.ru 
4111122Smax.romanov@nginx.com     nxt_queue_remove(&c->link);
4112122Smax.romanov@nginx.com 
4113337Sigor@sysoev.ru     engine = task->thread->engine;
4114337Sigor@sysoev.ru 
4115337Sigor@sysoev.ru     nxt_sockaddr_cache_free(engine, c);
4116337Sigor@sysoev.ru 
4117359Sigor@sysoev.ru     joint = c->joint;
4118131Smax.romanov@nginx.com 
4119337Sigor@sysoev.ru     nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup,
4120337Sigor@sysoev.ru                    &engine->task, joint, NULL);
4121164Smax.romanov@nginx.com 
4122386Sigor@sysoev.ru     nxt_conn_free(task, c);
412353Sigor@sysoev.ru }
412453Sigor@sysoev.ru 
412553Sigor@sysoev.ru 
412653Sigor@sysoev.ru static void
4127318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
4128318Smax.romanov@nginx.com {
4129431Sigor@sysoev.ru     nxt_timer_t          *timer;
4130431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
4131318Smax.romanov@nginx.com 
4132318Smax.romanov@nginx.com     timer = obj;
4133318Smax.romanov@nginx.com 
4134318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
4135318Smax.romanov@nginx.com 
4136431Sigor@sysoev.ru     ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
4137431Sigor@sysoev.ru 
4138431Sigor@sysoev.ru     if (!ar->request->header_sent) {
4139431Sigor@sysoev.ru         nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE);
4140431Sigor@sysoev.ru     }
4141318Smax.romanov@nginx.com }
4142