xref: /unit/src/nxt_router.c (revision 977)
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>
10774Svbart@nginx.com #if (NXT_TLS)
11774Svbart@nginx.com #include <nxt_cert.h>
12774Svbart@nginx.com #endif
13431Sigor@sysoev.ru #include <nxt_http.h>
14743Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
15743Smax.romanov@nginx.com #include <nxt_unit_request.h>
16743Smax.romanov@nginx.com #include <nxt_unit_response.h>
1720Sigor@sysoev.ru 
1820Sigor@sysoev.ru 
19115Sigor@sysoev.ru typedef struct {
20318Smax.romanov@nginx.com     nxt_str_t         type;
21507Smax.romanov@nginx.com     uint32_t          processes;
22507Smax.romanov@nginx.com     uint32_t          max_processes;
23507Smax.romanov@nginx.com     uint32_t          spare_processes;
24318Smax.romanov@nginx.com     nxt_msec_t        timeout;
25427Smax.romanov@nginx.com     nxt_msec_t        res_timeout;
26507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
27318Smax.romanov@nginx.com     uint32_t          requests;
28318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
29507Smax.romanov@nginx.com     nxt_conf_value_t  *processes_value;
30133Sigor@sysoev.ru } nxt_router_app_conf_t;
31133Sigor@sysoev.ru 
32133Sigor@sysoev.ru 
33133Sigor@sysoev.ru typedef struct {
34964Sigor@sysoev.ru     nxt_str_t         pass;
35964Sigor@sysoev.ru     nxt_str_t         application;
36115Sigor@sysoev.ru } nxt_router_listener_conf_t;
37115Sigor@sysoev.ru 
38115Sigor@sysoev.ru 
39774Svbart@nginx.com #if (NXT_TLS)
40774Svbart@nginx.com 
41774Svbart@nginx.com typedef struct {
42774Svbart@nginx.com     nxt_str_t          name;
43774Svbart@nginx.com     nxt_socket_conf_t  *conf;
44774Svbart@nginx.com 
45774Svbart@nginx.com     nxt_queue_link_t   link;  /* for nxt_socket_conf_t.tls */
46774Svbart@nginx.com } nxt_router_tlssock_t;
47774Svbart@nginx.com 
48774Svbart@nginx.com #endif
49774Svbart@nginx.com 
50774Svbart@nginx.com 
51423Smax.romanov@nginx.com typedef struct nxt_msg_info_s {
52423Smax.romanov@nginx.com     nxt_buf_t                 *buf;
53423Smax.romanov@nginx.com     nxt_port_mmap_tracking_t  tracking;
54423Smax.romanov@nginx.com     nxt_work_handler_t        completion_handler;
55423Smax.romanov@nginx.com } nxt_msg_info_t;
56423Smax.romanov@nginx.com 
57423Smax.romanov@nginx.com 
58167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
59141Smax.romanov@nginx.com 
60141Smax.romanov@nginx.com 
61318Smax.romanov@nginx.com typedef struct {
62431Sigor@sysoev.ru     uint32_t                 stream;
63431Sigor@sysoev.ru     nxt_app_t                *app;
64431Sigor@sysoev.ru     nxt_port_t               *app_port;
65431Sigor@sysoev.ru     nxt_app_parse_ctx_t      *ap;
66431Sigor@sysoev.ru     nxt_msg_info_t           msg_info;
67431Sigor@sysoev.ru     nxt_req_app_link_t       *ra;
68431Sigor@sysoev.ru 
69431Sigor@sysoev.ru     nxt_queue_link_t         link;     /* for nxt_conn_t.requests */
70318Smax.romanov@nginx.com } nxt_req_conn_link_t;
71318Smax.romanov@nginx.com 
72318Smax.romanov@nginx.com 
73167Smax.romanov@nginx.com struct nxt_req_app_link_s {
74318Smax.romanov@nginx.com     uint32_t             stream;
75425Smax.romanov@nginx.com     nxt_atomic_t         use_count;
76167Smax.romanov@nginx.com     nxt_port_t           *app_port;
77167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
78167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
79423Smax.romanov@nginx.com     nxt_msg_info_t       msg_info;
80167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
81167Smax.romanov@nginx.com 
82427Smax.romanov@nginx.com     nxt_nsec_t           res_time;
83427Smax.romanov@nginx.com 
84425Smax.romanov@nginx.com     nxt_queue_link_t     link_app_requests; /* for nxt_app_t.requests */
85425Smax.romanov@nginx.com     nxt_queue_link_t     link_port_pending; /* for nxt_port_t.pending_requests */
86427Smax.romanov@nginx.com     nxt_queue_link_t     link_app_pending;  /* for nxt_app_t.pending */
87167Smax.romanov@nginx.com 
88167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
89167Smax.romanov@nginx.com     nxt_work_t           work;
90345Smax.romanov@nginx.com 
91345Smax.romanov@nginx.com     int                  err_code;
92345Smax.romanov@nginx.com     const char           *err_str;
93167Smax.romanov@nginx.com };
94167Smax.romanov@nginx.com 
95167Smax.romanov@nginx.com 
96198Sigor@sysoev.ru typedef struct {
97198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
98198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
99198Sigor@sysoev.ru } nxt_socket_rpc_t;
100198Sigor@sysoev.ru 
101198Sigor@sysoev.ru 
102507Smax.romanov@nginx.com typedef struct {
103507Smax.romanov@nginx.com     nxt_app_t               *app;
104507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
105507Smax.romanov@nginx.com } nxt_app_rpc_t;
106507Smax.romanov@nginx.com 
107507Smax.romanov@nginx.com 
108427Smax.romanov@nginx.com struct nxt_port_select_state_s {
109427Smax.romanov@nginx.com     nxt_app_t           *app;
110427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
111427Smax.romanov@nginx.com 
112427Smax.romanov@nginx.com     nxt_port_t          *failed_port;
113427Smax.romanov@nginx.com     int                 failed_port_use_delta;
114427Smax.romanov@nginx.com 
115507Smax.romanov@nginx.com     uint8_t             start_process;    /* 1 bit */
116427Smax.romanov@nginx.com     nxt_req_app_link_t  *shared_ra;
117427Smax.romanov@nginx.com     nxt_port_t          *port;
118427Smax.romanov@nginx.com };
119427Smax.romanov@nginx.com 
120427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t;
121427Smax.romanov@nginx.com 
122662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task,
123662Smax.romanov@nginx.com     nxt_port_t *controller_port);
124662Smax.romanov@nginx.com 
125427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task,
126427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
127427Smax.romanov@nginx.com 
128427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task,
129427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
130427Smax.romanov@nginx.com 
131507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
132343Smax.romanov@nginx.com 
133425Smax.romanov@nginx.com nxt_inline void
134425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra)
135425Smax.romanov@nginx.com {
136425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, 1);
137425Smax.romanov@nginx.com }
138425Smax.romanov@nginx.com 
139425Smax.romanov@nginx.com nxt_inline void
140425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra)
141425Smax.romanov@nginx.com {
142538Svbart@nginx.com #if (NXT_DEBUG)
143425Smax.romanov@nginx.com     int  c;
144425Smax.romanov@nginx.com 
145425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, -1);
146425Smax.romanov@nginx.com 
147425Smax.romanov@nginx.com     nxt_assert(c > 1);
148538Svbart@nginx.com #else
149538Svbart@nginx.com     (void) nxt_atomic_fetch_add(&ra->use_count, -1);
150538Svbart@nginx.com #endif
151425Smax.romanov@nginx.com }
152425Smax.romanov@nginx.com 
153425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i);
154425Smax.romanov@nginx.com 
155139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
156198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
157198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
158139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
159139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
160139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
161139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
162193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
16353Sigor@sysoev.ru 
164115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
165115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
166133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
167198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
168198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
169198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
170198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
171198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
172198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
173774Svbart@nginx.com #if (NXT_TLS)
174774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task,
175774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls);
176774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task,
177774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
178774Svbart@nginx.com #endif
179507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
180507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
181507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
182507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
183507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
184507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
185359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
186359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
187359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
188359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
18953Sigor@sysoev.ru 
19053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
19153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
19253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
193115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
194115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
195115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
196115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
197115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
198115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
199154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
200154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
201154Sigor@sysoev.ru     nxt_work_handler_t handler);
202313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
203313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
204139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
205139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
20653Sigor@sysoev.ru 
20753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
20853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
20953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
21053Sigor@sysoev.ru     nxt_event_engine_t *engine);
211343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
212133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
21353Sigor@sysoev.ru 
214315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
215315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
216315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
217315Sigor@sysoev.ru     nxt_work_t *jobs);
21853Sigor@sysoev.ru 
21953Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
22053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
22153Sigor@sysoev.ru     void *data);
22253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
22353Sigor@sysoev.ru     void *data);
22453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
22553Sigor@sysoev.ru     void *data);
226313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
227313Sigor@sysoev.ru     void *data);
22853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
22953Sigor@sysoev.ru     void *data);
23053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
23153Sigor@sysoev.ru     void *data);
232359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
233359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
23453Sigor@sysoev.ru 
235630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task,
236630Svbart@nginx.com     nxt_http_request_t *r, nxt_router_access_log_t *access_log);
237630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
238630Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
239630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task,
240630Svbart@nginx.com     nxt_router_temp_conf_t *tmcf);
241630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task,
242630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
243630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task,
244630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
245630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task,
246630Svbart@nginx.com     nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
247651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
248651Svbart@nginx.com     void *data);
249631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
250631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
251631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task,
252631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
253630Svbart@nginx.com 
254343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
255343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
256343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
257343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
258343Smax.romanov@nginx.com 
259753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
260343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
261343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
262427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
263427Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
264141Smax.romanov@nginx.com 
265425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
266343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
267743Smax.romanov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
268743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix);
269510Salexander.borisov@nginx.com 
270318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
271507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
272507Smax.romanov@nginx.com     void *data);
273507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
274507Smax.romanov@nginx.com     void *data);
275753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
276507Smax.romanov@nginx.com     void *data);
277753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
278431Sigor@sysoev.ru 
279431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
280431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
281141Smax.romanov@nginx.com 
282753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task,
283753Smax.romanov@nginx.com     nxt_app_joint_t *app_joint, int i);
284753Smax.romanov@nginx.com 
285119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
28620Sigor@sysoev.ru 
287743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
288743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
289743Smax.romanov@nginx.com 
290743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
291804Svbart@nginx.com     &empty_prefix,
292743Smax.romanov@nginx.com     &http_prefix,
293743Smax.romanov@nginx.com     &http_prefix,
294743Smax.romanov@nginx.com     &http_prefix,
295743Smax.romanov@nginx.com     &http_prefix,
296*977Smax.romanov@gmail.com     &empty_prefix,
297216Sigor@sysoev.ru };
298216Sigor@sysoev.ru 
299216Sigor@sysoev.ru 
300662Smax.romanov@nginx.com nxt_port_handlers_t  nxt_router_process_port_handlers = {
301662Smax.romanov@nginx.com     .quit         = nxt_worker_process_quit_handler,
302662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
303662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
304662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
305662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
306662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
307662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
308662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
309662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
310662Smax.romanov@nginx.com };
311662Smax.romanov@nginx.com 
312662Smax.romanov@nginx.com 
31320Sigor@sysoev.ru nxt_int_t
314141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
31520Sigor@sysoev.ru {
316141Smax.romanov@nginx.com     nxt_int_t      ret;
317662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
318141Smax.romanov@nginx.com     nxt_router_t   *router;
319141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
320141Smax.romanov@nginx.com 
321141Smax.romanov@nginx.com     rt = task->thread->runtime;
32253Sigor@sysoev.ru 
323771Sigor@sysoev.ru #if (NXT_TLS)
324771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
325771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
326771Sigor@sysoev.ru         return NXT_ERROR;
327771Sigor@sysoev.ru     }
328771Sigor@sysoev.ru 
329771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
330771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
331771Sigor@sysoev.ru         return ret;
332771Sigor@sysoev.ru     }
333771Sigor@sysoev.ru #endif
334771Sigor@sysoev.ru 
335431Sigor@sysoev.ru     ret = nxt_http_init(task, rt);
33688Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
33788Smax.romanov@nginx.com         return ret;
33888Smax.romanov@nginx.com     }
33988Smax.romanov@nginx.com 
34053Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
34153Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
34253Sigor@sysoev.ru         return NXT_ERROR;
34353Sigor@sysoev.ru     }
34453Sigor@sysoev.ru 
34553Sigor@sysoev.ru     nxt_queue_init(&router->engines);
34653Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
347133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
34853Sigor@sysoev.ru 
349119Smax.romanov@nginx.com     nxt_router = router;
350119Smax.romanov@nginx.com 
351662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
352662Smax.romanov@nginx.com     if (controller_port != NULL) {
353662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
354662Smax.romanov@nginx.com     }
355662Smax.romanov@nginx.com 
356115Sigor@sysoev.ru     return NXT_OK;
357115Sigor@sysoev.ru }
358115Sigor@sysoev.ru 
359115Sigor@sysoev.ru 
360343Smax.romanov@nginx.com static void
361662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
362662Smax.romanov@nginx.com {
363662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
364662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
365662Smax.romanov@nginx.com }
366662Smax.romanov@nginx.com 
367662Smax.romanov@nginx.com 
368662Smax.romanov@nginx.com static void
369507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
370507Smax.romanov@nginx.com     void *data)
371167Smax.romanov@nginx.com {
372343Smax.romanov@nginx.com     size_t         size;
373343Smax.romanov@nginx.com     uint32_t       stream;
374430Sigor@sysoev.ru     nxt_mp_t       *mp;
375648Svbart@nginx.com     nxt_int_t      ret;
376343Smax.romanov@nginx.com     nxt_app_t      *app;
377343Smax.romanov@nginx.com     nxt_buf_t      *b;
378343Smax.romanov@nginx.com     nxt_port_t     *main_port;
379343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
380343Smax.romanov@nginx.com 
381343Smax.romanov@nginx.com     app = data;
382167Smax.romanov@nginx.com 
383167Smax.romanov@nginx.com     rt = task->thread->runtime;
384240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
385167Smax.romanov@nginx.com 
386507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
387343Smax.romanov@nginx.com 
388343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
389343Smax.romanov@nginx.com 
390343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
391343Smax.romanov@nginx.com 
392343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
393343Smax.romanov@nginx.com         goto failed;
394167Smax.romanov@nginx.com     }
395167Smax.romanov@nginx.com 
396343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
397343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
398343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
399343Smax.romanov@nginx.com 
400753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
401753Smax.romanov@nginx.com 
402343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
403343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
404343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
405753Smax.romanov@nginx.com                                            -1, app->joint);
406343Smax.romanov@nginx.com 
407343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
408753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
409753Smax.romanov@nginx.com 
410343Smax.romanov@nginx.com         goto failed;
411343Smax.romanov@nginx.com     }
412343Smax.romanov@nginx.com 
413648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
414648Svbart@nginx.com                                 stream, port->id, b);
415648Svbart@nginx.com 
416648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
417648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
418753Smax.romanov@nginx.com 
419753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
420753Smax.romanov@nginx.com 
421648Svbart@nginx.com         goto failed;
422648Svbart@nginx.com     }
423343Smax.romanov@nginx.com 
424753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
425753Smax.romanov@nginx.com 
426343Smax.romanov@nginx.com     return;
427343Smax.romanov@nginx.com 
428343Smax.romanov@nginx.com failed:
429343Smax.romanov@nginx.com 
430648Svbart@nginx.com     if (b != NULL) {
431648Svbart@nginx.com         mp = b->data;
432648Svbart@nginx.com         nxt_mp_free(mp, b);
433648Svbart@nginx.com         nxt_mp_release(mp);
434648Svbart@nginx.com     }
435648Svbart@nginx.com 
436343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
437343Smax.romanov@nginx.com 
438507Smax.romanov@nginx.com     app->pending_processes--;
439343Smax.romanov@nginx.com 
440343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
441343Smax.romanov@nginx.com 
442343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
443167Smax.romanov@nginx.com }
444167Smax.romanov@nginx.com 
445167Smax.romanov@nginx.com 
446753Smax.romanov@nginx.com static void
447753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
448753Smax.romanov@nginx.com {
449753Smax.romanov@nginx.com     app_joint->use_count += i;
450753Smax.romanov@nginx.com 
451753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
452753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
453753Smax.romanov@nginx.com 
454753Smax.romanov@nginx.com         nxt_free(app_joint);
455753Smax.romanov@nginx.com     }
456753Smax.romanov@nginx.com }
457753Smax.romanov@nginx.com 
458753Smax.romanov@nginx.com 
459343Smax.romanov@nginx.com static nxt_int_t
460507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
461141Smax.romanov@nginx.com {
462343Smax.romanov@nginx.com     nxt_int_t      res;
463343Smax.romanov@nginx.com     nxt_port_t     *router_port;
464343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
465343Smax.romanov@nginx.com 
466343Smax.romanov@nginx.com     rt = task->thread->runtime;
467343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
468343Smax.romanov@nginx.com 
469343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
470343Smax.romanov@nginx.com 
471507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
472343Smax.romanov@nginx.com                         app);
473343Smax.romanov@nginx.com 
474343Smax.romanov@nginx.com     if (res == NXT_OK) {
475343Smax.romanov@nginx.com         return res;
476318Smax.romanov@nginx.com     }
477318Smax.romanov@nginx.com 
478343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
479343Smax.romanov@nginx.com 
480507Smax.romanov@nginx.com     app->pending_processes--;
481343Smax.romanov@nginx.com 
482343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
483343Smax.romanov@nginx.com 
484343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
485343Smax.romanov@nginx.com 
486343Smax.romanov@nginx.com     return NXT_ERROR;
487318Smax.romanov@nginx.com }
488318Smax.romanov@nginx.com 
489318Smax.romanov@nginx.com 
490351Smax.romanov@nginx.com nxt_inline void
491351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
492351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
493167Smax.romanov@nginx.com {
494318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
495351Smax.romanov@nginx.com 
496318Smax.romanov@nginx.com     engine = task->thread->engine;
497167Smax.romanov@nginx.com 
498167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
499167Smax.romanov@nginx.com 
500318Smax.romanov@nginx.com     ra->stream = rc->stream;
501425Smax.romanov@nginx.com     ra->use_count = 1;
502167Smax.romanov@nginx.com     ra->rc = rc;
503318Smax.romanov@nginx.com     rc->ra = ra;
504318Smax.romanov@nginx.com     ra->reply_port = engine->port;
505351Smax.romanov@nginx.com     ra->ap = rc->ap;
506167Smax.romanov@nginx.com 
507167Smax.romanov@nginx.com     ra->work.handler = NULL;
508318Smax.romanov@nginx.com     ra->work.task = &engine->task;
509167Smax.romanov@nginx.com     ra->work.obj = ra;
510318Smax.romanov@nginx.com     ra->work.data = engine;
511351Smax.romanov@nginx.com }
512351Smax.romanov@nginx.com 
513351Smax.romanov@nginx.com 
514351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
515351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
516351Smax.romanov@nginx.com {
517351Smax.romanov@nginx.com     nxt_mp_t            *mp;
518351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
519351Smax.romanov@nginx.com 
520425Smax.romanov@nginx.com     if (ra_src->mem_pool != NULL) {
521425Smax.romanov@nginx.com         return ra_src;
522425Smax.romanov@nginx.com     }
523425Smax.romanov@nginx.com 
524351Smax.romanov@nginx.com     mp = ra_src->ap->mem_pool;
525351Smax.romanov@nginx.com 
526430Sigor@sysoev.ru     ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t));
527351Smax.romanov@nginx.com 
528351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
529351Smax.romanov@nginx.com 
530351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
531351Smax.romanov@nginx.com         ra_src->rc = NULL;
532351Smax.romanov@nginx.com 
533351Smax.romanov@nginx.com         return NULL;
534351Smax.romanov@nginx.com     }
535351Smax.romanov@nginx.com 
536430Sigor@sysoev.ru     nxt_mp_retain(mp);
537430Sigor@sysoev.ru 
538351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
539351Smax.romanov@nginx.com 
540351Smax.romanov@nginx.com     ra->mem_pool = mp;
541167Smax.romanov@nginx.com 
542167Smax.romanov@nginx.com     return ra;
543167Smax.romanov@nginx.com }
544167Smax.romanov@nginx.com 
545167Smax.romanov@nginx.com 
546423Smax.romanov@nginx.com nxt_inline nxt_bool_t
547423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
548423Smax.romanov@nginx.com     uint32_t stream)
549423Smax.romanov@nginx.com {
550423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
551423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
552423Smax.romanov@nginx.com 
553423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
554423Smax.romanov@nginx.com         return 0;
555423Smax.romanov@nginx.com     }
556423Smax.romanov@nginx.com 
557423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
558423Smax.romanov@nginx.com                                               stream);
559423Smax.romanov@nginx.com 
560423Smax.romanov@nginx.com     if (cancelled) {
561423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
562423Smax.romanov@nginx.com     }
563423Smax.romanov@nginx.com 
564423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
565423Smax.romanov@nginx.com         next = b->next;
566423Smax.romanov@nginx.com 
567423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
568423Smax.romanov@nginx.com 
569423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
570423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
571423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
572423Smax.romanov@nginx.com         }
573423Smax.romanov@nginx.com     }
574423Smax.romanov@nginx.com 
575423Smax.romanov@nginx.com     msg_info->buf = NULL;
576423Smax.romanov@nginx.com 
577423Smax.romanov@nginx.com     return cancelled;
578423Smax.romanov@nginx.com }
579423Smax.romanov@nginx.com 
580423Smax.romanov@nginx.com 
581167Smax.romanov@nginx.com static void
582425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra);
583425Smax.romanov@nginx.com 
584425Smax.romanov@nginx.com 
585425Smax.romanov@nginx.com static void
586425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data)
587167Smax.romanov@nginx.com {
588425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
589425Smax.romanov@nginx.com 
590425Smax.romanov@nginx.com     ra = obj;
591425Smax.romanov@nginx.com 
592425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
593425Smax.romanov@nginx.com 
594425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
595425Smax.romanov@nginx.com }
596425Smax.romanov@nginx.com 
597425Smax.romanov@nginx.com 
598425Smax.romanov@nginx.com static void
599425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra)
600425Smax.romanov@nginx.com {
601343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
602343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
603318Smax.romanov@nginx.com 
604425Smax.romanov@nginx.com     engine = ra->work.data;
605318Smax.romanov@nginx.com 
606343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
607425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
608425Smax.romanov@nginx.com 
609425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_update_peer_handler;
610318Smax.romanov@nginx.com         ra->work.task = &engine->task;
611318Smax.romanov@nginx.com         ra->work.next = NULL;
612318Smax.romanov@nginx.com 
613425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post update peer to %p",
614318Smax.romanov@nginx.com                   ra->stream, engine);
615318Smax.romanov@nginx.com 
616318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
617318Smax.romanov@nginx.com 
618318Smax.romanov@nginx.com         return;
619318Smax.romanov@nginx.com     }
620318Smax.romanov@nginx.com 
621425Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD update peer", ra->stream);
622425Smax.romanov@nginx.com 
623425Smax.romanov@nginx.com     rc = ra->rc;
624425Smax.romanov@nginx.com 
625425Smax.romanov@nginx.com     if (rc != NULL && ra->app_port != NULL) {
626425Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid);
627425Smax.romanov@nginx.com     }
628425Smax.romanov@nginx.com 
629425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
630425Smax.romanov@nginx.com }
631425Smax.romanov@nginx.com 
632425Smax.romanov@nginx.com 
633425Smax.romanov@nginx.com static void
634425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra)
635425Smax.romanov@nginx.com {
636431Sigor@sysoev.ru     nxt_mp_t                *mp;
637431Sigor@sysoev.ru     nxt_req_conn_link_t     *rc;
638425Smax.romanov@nginx.com 
639425Smax.romanov@nginx.com     nxt_assert(task->thread->engine == ra->work.data);
640425Smax.romanov@nginx.com     nxt_assert(ra->use_count == 0);
641425Smax.romanov@nginx.com 
642343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
643343Smax.romanov@nginx.com 
644343Smax.romanov@nginx.com     rc = ra->rc;
645343Smax.romanov@nginx.com 
646343Smax.romanov@nginx.com     if (rc != NULL) {
647423Smax.romanov@nginx.com         if (nxt_slow_path(ra->err_code != 0)) {
648431Sigor@sysoev.ru             nxt_http_request_error(task, rc->ap->request, ra->err_code);
649423Smax.romanov@nginx.com 
650423Smax.romanov@nginx.com         } else {
651423Smax.romanov@nginx.com             rc->app_port = ra->app_port;
652423Smax.romanov@nginx.com             rc->msg_info = ra->msg_info;
653423Smax.romanov@nginx.com 
654425Smax.romanov@nginx.com             if (rc->app->timeout != 0) {
655431Sigor@sysoev.ru                 rc->ap->timer.handler = nxt_router_app_timeout;
656615Smax.romanov@nginx.com                 rc->ap->timer_data = rc;
657431Sigor@sysoev.ru                 nxt_timer_add(task->thread->engine, &rc->ap->timer,
658425Smax.romanov@nginx.com                               rc->app->timeout);
659425Smax.romanov@nginx.com             }
660425Smax.romanov@nginx.com 
661423Smax.romanov@nginx.com             ra->app_port = NULL;
662423Smax.romanov@nginx.com             ra->msg_info.buf = NULL;
663423Smax.romanov@nginx.com         }
664343Smax.romanov@nginx.com 
665343Smax.romanov@nginx.com         rc->ra = NULL;
666343Smax.romanov@nginx.com         ra->rc = NULL;
667343Smax.romanov@nginx.com     }
668343Smax.romanov@nginx.com 
669343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
670343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
671343Smax.romanov@nginx.com 
672343Smax.romanov@nginx.com         ra->app_port = NULL;
673167Smax.romanov@nginx.com     }
674167Smax.romanov@nginx.com 
675423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
676423Smax.romanov@nginx.com 
677430Sigor@sysoev.ru     mp = ra->mem_pool;
678430Sigor@sysoev.ru 
679430Sigor@sysoev.ru     if (mp != NULL) {
680430Sigor@sysoev.ru         nxt_mp_free(mp, ra);
681430Sigor@sysoev.ru         nxt_mp_release(mp);
682351Smax.romanov@nginx.com     }
683167Smax.romanov@nginx.com }
684167Smax.romanov@nginx.com 
685167Smax.romanov@nginx.com 
686425Smax.romanov@nginx.com static void
687425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data)
688425Smax.romanov@nginx.com {
689425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
690425Smax.romanov@nginx.com 
691425Smax.romanov@nginx.com     ra = obj;
692425Smax.romanov@nginx.com 
693425Smax.romanov@nginx.com     nxt_assert(ra->work.data == data);
694425Smax.romanov@nginx.com 
695425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, -1);
696425Smax.romanov@nginx.com 
697425Smax.romanov@nginx.com     nxt_router_ra_release(task, ra);
698425Smax.romanov@nginx.com }
699425Smax.romanov@nginx.com 
700425Smax.romanov@nginx.com 
701425Smax.romanov@nginx.com static void
702425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i)
703425Smax.romanov@nginx.com {
704425Smax.romanov@nginx.com     int                 c;
705425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
706425Smax.romanov@nginx.com 
707425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, i);
708425Smax.romanov@nginx.com 
709425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
710425Smax.romanov@nginx.com         engine = ra->work.data;
711425Smax.romanov@nginx.com 
712425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
713425Smax.romanov@nginx.com             nxt_router_ra_release(task, ra);
714425Smax.romanov@nginx.com 
715425Smax.romanov@nginx.com             return;
716425Smax.romanov@nginx.com         }
717425Smax.romanov@nginx.com 
718425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
719425Smax.romanov@nginx.com 
720425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release_handler;
721425Smax.romanov@nginx.com         ra->work.task = &engine->task;
722425Smax.romanov@nginx.com         ra->work.next = NULL;
723425Smax.romanov@nginx.com 
724425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
725425Smax.romanov@nginx.com                   ra->stream, engine);
726425Smax.romanov@nginx.com 
727425Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
728425Smax.romanov@nginx.com     }
729425Smax.romanov@nginx.com }
730425Smax.romanov@nginx.com 
731425Smax.romanov@nginx.com 
732423Smax.romanov@nginx.com nxt_inline void
733521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str)
734345Smax.romanov@nginx.com {
735423Smax.romanov@nginx.com     ra->app_port = NULL;
736423Smax.romanov@nginx.com     ra->err_code = code;
737423Smax.romanov@nginx.com     ra->err_str = str;
738345Smax.romanov@nginx.com }
739345Smax.romanov@nginx.com 
740345Smax.romanov@nginx.com 
741427Smax.romanov@nginx.com nxt_inline void
742427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
743427Smax.romanov@nginx.com {
744427Smax.romanov@nginx.com     nxt_queue_insert_tail(&ra->app_port->pending_requests,
745427Smax.romanov@nginx.com                           &ra->link_port_pending);
746427Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &ra->link_app_pending);
747427Smax.romanov@nginx.com 
748427Smax.romanov@nginx.com     nxt_router_ra_inc_use(ra);
749427Smax.romanov@nginx.com 
750427Smax.romanov@nginx.com     ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout;
751427Smax.romanov@nginx.com 
752427Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream);
753427Smax.romanov@nginx.com }
754427Smax.romanov@nginx.com 
755427Smax.romanov@nginx.com 
756425Smax.romanov@nginx.com nxt_inline nxt_bool_t
757425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
758425Smax.romanov@nginx.com {
759425Smax.romanov@nginx.com     if (lnk->next != NULL) {
760425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
761425Smax.romanov@nginx.com 
762425Smax.romanov@nginx.com         lnk->next = NULL;
763425Smax.romanov@nginx.com 
764425Smax.romanov@nginx.com         return 1;
765425Smax.romanov@nginx.com     }
766425Smax.romanov@nginx.com 
767425Smax.romanov@nginx.com     return 0;
768425Smax.romanov@nginx.com }
769425Smax.romanov@nginx.com 
770425Smax.romanov@nginx.com 
771343Smax.romanov@nginx.com nxt_inline void
772343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
773343Smax.romanov@nginx.com {
774425Smax.romanov@nginx.com     int                 ra_use_delta;
775343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
776343Smax.romanov@nginx.com 
777343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
778343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
779343Smax.romanov@nginx.com 
780343Smax.romanov@nginx.com         rc->app_port = NULL;
781343Smax.romanov@nginx.com     }
782343Smax.romanov@nginx.com 
783423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &rc->msg_info, rc->stream);
784423Smax.romanov@nginx.com 
785343Smax.romanov@nginx.com     ra = rc->ra;
786343Smax.romanov@nginx.com 
787343Smax.romanov@nginx.com     if (ra != NULL) {
788343Smax.romanov@nginx.com         rc->ra = NULL;
789343Smax.romanov@nginx.com         ra->rc = NULL;
790343Smax.romanov@nginx.com 
791425Smax.romanov@nginx.com         ra_use_delta = 0;
792425Smax.romanov@nginx.com 
793343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
794343Smax.romanov@nginx.com 
795425Smax.romanov@nginx.com         if (ra->link_app_requests.next == NULL
796427Smax.romanov@nginx.com             && ra->link_port_pending.next == NULL
797427Smax.romanov@nginx.com             && ra->link_app_pending.next == NULL)
798425Smax.romanov@nginx.com         {
799425Smax.romanov@nginx.com             ra = NULL;
800343Smax.romanov@nginx.com 
801343Smax.romanov@nginx.com         } else {
802425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests);
803425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending);
804427Smax.romanov@nginx.com             nxt_queue_chk_remove(&ra->link_app_pending);
805343Smax.romanov@nginx.com         }
806343Smax.romanov@nginx.com 
807343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
808425Smax.romanov@nginx.com 
809425Smax.romanov@nginx.com         if (ra != NULL) {
810425Smax.romanov@nginx.com             nxt_router_ra_use(task, ra, ra_use_delta);
811425Smax.romanov@nginx.com         }
812343Smax.romanov@nginx.com     }
813343Smax.romanov@nginx.com 
814343Smax.romanov@nginx.com     if (rc->app != NULL) {
815343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
816343Smax.romanov@nginx.com 
817343Smax.romanov@nginx.com         rc->app = NULL;
818343Smax.romanov@nginx.com     }
819343Smax.romanov@nginx.com 
820346Smax.romanov@nginx.com     if (rc->ap != NULL) {
821615Smax.romanov@nginx.com         rc->ap->timer_data = NULL;
822615Smax.romanov@nginx.com 
823346Smax.romanov@nginx.com         nxt_app_http_req_done(task, rc->ap);
824346Smax.romanov@nginx.com 
825346Smax.romanov@nginx.com         rc->ap = NULL;
826346Smax.romanov@nginx.com     }
827343Smax.romanov@nginx.com }
828343Smax.romanov@nginx.com 
829343Smax.romanov@nginx.com 
830141Smax.romanov@nginx.com void
831141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
832141Smax.romanov@nginx.com {
833141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
834141Smax.romanov@nginx.com 
835670Smax.romanov@nginx.com     if (msg->u.new_port != NULL
836670Smax.romanov@nginx.com         && msg->u.new_port->type == NXT_PROCESS_CONTROLLER)
837670Smax.romanov@nginx.com     {
838662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
839662Smax.romanov@nginx.com     }
840662Smax.romanov@nginx.com 
841192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
842141Smax.romanov@nginx.com         return;
843141Smax.romanov@nginx.com     }
844141Smax.romanov@nginx.com 
845426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
846426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
847347Smax.romanov@nginx.com     {
848192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
849141Smax.romanov@nginx.com     }
850192Smax.romanov@nginx.com 
851192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
852141Smax.romanov@nginx.com }
853141Smax.romanov@nginx.com 
854141Smax.romanov@nginx.com 
855139Sigor@sysoev.ru void
856139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
857115Sigor@sysoev.ru {
858198Sigor@sysoev.ru     nxt_int_t               ret;
859139Sigor@sysoev.ru     nxt_buf_t               *b;
860139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
861139Sigor@sysoev.ru 
862139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
863139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
864139Sigor@sysoev.ru         return;
86553Sigor@sysoev.ru     }
86653Sigor@sysoev.ru 
867494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
868423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
869493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
870423Smax.romanov@nginx.com 
871591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
872139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
873139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
874198Sigor@sysoev.ru                                        msg->port_msg.pid,
875198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
876198Sigor@sysoev.ru 
877779Smax.romanov@nginx.com     if (nxt_slow_path(tmcf->port == NULL)) {
878779Smax.romanov@nginx.com         nxt_alert(task, "reply port not found");
879779Smax.romanov@nginx.com 
880779Smax.romanov@nginx.com         return;
881779Smax.romanov@nginx.com     }
882779Smax.romanov@nginx.com 
883779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
884779Smax.romanov@nginx.com 
885591Sigor@sysoev.ru     b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool,
886591Sigor@sysoev.ru                                msg->buf, msg->size);
887551Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
888551Smax.romanov@nginx.com         nxt_router_conf_error(task, tmcf);
889551Smax.romanov@nginx.com 
890551Smax.romanov@nginx.com         return;
891551Smax.romanov@nginx.com     }
892551Smax.romanov@nginx.com 
893198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
894198Sigor@sysoev.ru 
895198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
896198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
897198Sigor@sysoev.ru 
898198Sigor@sysoev.ru     } else {
899198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
900139Sigor@sysoev.ru     }
90153Sigor@sysoev.ru }
90253Sigor@sysoev.ru 
90353Sigor@sysoev.ru 
904347Smax.romanov@nginx.com static void
905507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
906507Smax.romanov@nginx.com     void *data)
907347Smax.romanov@nginx.com {
908347Smax.romanov@nginx.com     union {
909347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
910347Smax.romanov@nginx.com         void       *data;
911347Smax.romanov@nginx.com     } u;
912347Smax.romanov@nginx.com 
913347Smax.romanov@nginx.com     u.data = data;
914347Smax.romanov@nginx.com 
915347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
916347Smax.romanov@nginx.com }
917347Smax.romanov@nginx.com 
918347Smax.romanov@nginx.com 
919192Smax.romanov@nginx.com void
920192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
921192Smax.romanov@nginx.com {
922347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
923318Smax.romanov@nginx.com 
924192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
925192Smax.romanov@nginx.com 
926192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
927192Smax.romanov@nginx.com         return;
928192Smax.romanov@nginx.com     }
929192Smax.romanov@nginx.com 
930318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
931318Smax.romanov@nginx.com     {
932507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
933347Smax.romanov@nginx.com                       msg->u.data);
934318Smax.romanov@nginx.com     }
935318Smax.romanov@nginx.com     nxt_queue_loop;
936318Smax.romanov@nginx.com 
937192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
938192Smax.romanov@nginx.com 
939192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
940192Smax.romanov@nginx.com }
941192Smax.romanov@nginx.com 
942192Smax.romanov@nginx.com 
94353Sigor@sysoev.ru static nxt_router_temp_conf_t *
944139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
94553Sigor@sysoev.ru {
94665Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
94753Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
94853Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
94953Sigor@sysoev.ru 
95065Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
95153Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
95253Sigor@sysoev.ru         return NULL;
95353Sigor@sysoev.ru     }
95453Sigor@sysoev.ru 
95565Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
95653Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
95753Sigor@sysoev.ru         goto fail;
95853Sigor@sysoev.ru     }
95953Sigor@sysoev.ru 
96053Sigor@sysoev.ru     rtcf->mem_pool = mp;
96153Sigor@sysoev.ru 
96265Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
96353Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
96453Sigor@sysoev.ru         goto fail;
96553Sigor@sysoev.ru     }
96653Sigor@sysoev.ru 
96765Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
96853Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
96953Sigor@sysoev.ru         goto temp_fail;
97053Sigor@sysoev.ru     }
97153Sigor@sysoev.ru 
97253Sigor@sysoev.ru     tmcf->mem_pool = tmp;
973591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
974139Sigor@sysoev.ru     tmcf->count = 1;
975139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
97653Sigor@sysoev.ru 
97753Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
97853Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
97953Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
98053Sigor@sysoev.ru         goto temp_fail;
98153Sigor@sysoev.ru     }
98253Sigor@sysoev.ru 
98353Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
98453Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
98553Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
98653Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
98753Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
988416Smax.romanov@nginx.com 
989774Svbart@nginx.com #if (NXT_TLS)
990774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
991774Svbart@nginx.com #endif
992774Svbart@nginx.com 
993133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
994133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
99553Sigor@sysoev.ru 
99653Sigor@sysoev.ru     return tmcf;
99753Sigor@sysoev.ru 
99853Sigor@sysoev.ru temp_fail:
99953Sigor@sysoev.ru 
100065Sigor@sysoev.ru     nxt_mp_destroy(tmp);
100153Sigor@sysoev.ru 
100253Sigor@sysoev.ru fail:
100353Sigor@sysoev.ru 
100465Sigor@sysoev.ru     nxt_mp_destroy(mp);
100553Sigor@sysoev.ru 
100653Sigor@sysoev.ru     return NULL;
100753Sigor@sysoev.ru }
100853Sigor@sysoev.ru 
100953Sigor@sysoev.ru 
1010507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1011507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
1012507Smax.romanov@nginx.com {
1013507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
1014507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
1015507Smax.romanov@nginx.com }
1016507Smax.romanov@nginx.com 
1017507Smax.romanov@nginx.com 
1018507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1019507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
1020507Smax.romanov@nginx.com {
1021507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
1022507Smax.romanov@nginx.com             < app->spare_processes;
1023507Smax.romanov@nginx.com }
1024507Smax.romanov@nginx.com 
1025507Smax.romanov@nginx.com 
1026198Sigor@sysoev.ru static void
1027198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1028139Sigor@sysoev.ru {
1029139Sigor@sysoev.ru     nxt_int_t                    ret;
1030507Smax.romanov@nginx.com     nxt_app_t                    *app;
1031139Sigor@sysoev.ru     nxt_router_t                 *router;
1032139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1033198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1034198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1035630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1036198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1037139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1038774Svbart@nginx.com #if (NXT_TLS)
1039774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
1040774Svbart@nginx.com #endif
1041139Sigor@sysoev.ru 
1042198Sigor@sysoev.ru     tmcf = obj;
1043198Sigor@sysoev.ru 
1044198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
1045198Sigor@sysoev.ru 
1046198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
1047198Sigor@sysoev.ru         nxt_queue_remove(qlk);
1048198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
1049198Sigor@sysoev.ru 
1050198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1051198Sigor@sysoev.ru 
1052198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1053198Sigor@sysoev.ru 
1054198Sigor@sysoev.ru         return;
1055139Sigor@sysoev.ru     }
1056139Sigor@sysoev.ru 
1057774Svbart@nginx.com #if (NXT_TLS)
1058774Svbart@nginx.com     qlk = nxt_queue_first(&tmcf->tls);
1059774Svbart@nginx.com 
1060774Svbart@nginx.com     if (qlk != nxt_queue_tail(&tmcf->tls)) {
1061774Svbart@nginx.com         nxt_queue_remove(qlk);
1062774Svbart@nginx.com 
1063774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1064774Svbart@nginx.com 
1065774Svbart@nginx.com         nxt_router_tls_rpc_create(task, tmcf, tls);
1066774Svbart@nginx.com         return;
1067774Svbart@nginx.com     }
1068774Svbart@nginx.com #endif
1069774Svbart@nginx.com 
1070507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1071507Smax.romanov@nginx.com 
1072507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1073507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1074507Smax.romanov@nginx.com             return;
1075507Smax.romanov@nginx.com         }
1076507Smax.romanov@nginx.com 
1077507Smax.romanov@nginx.com     } nxt_queue_loop;
1078507Smax.romanov@nginx.com 
1079630Svbart@nginx.com     rtcf = tmcf->router_conf;
1080630Svbart@nginx.com 
1081630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1082630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1083630Svbart@nginx.com         return;
1084630Svbart@nginx.com     }
1085630Svbart@nginx.com 
1086139Sigor@sysoev.ru     rt = task->thread->runtime;
1087139Sigor@sysoev.ru 
1088139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1089139Sigor@sysoev.ru 
1090630Svbart@nginx.com     router = rtcf->router;
1091198Sigor@sysoev.ru 
1092139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1093139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1094198Sigor@sysoev.ru         goto fail;
1095139Sigor@sysoev.ru     }
1096139Sigor@sysoev.ru 
1097139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1098139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1099198Sigor@sysoev.ru         goto fail;
1100139Sigor@sysoev.ru     }
1101139Sigor@sysoev.ru 
1102343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1103139Sigor@sysoev.ru 
1104315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1105139Sigor@sysoev.ru 
1106139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
1107139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
1108139Sigor@sysoev.ru 
1109630Svbart@nginx.com     router->access_log = rtcf->access_log;
1110630Svbart@nginx.com 
1111198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1112198Sigor@sysoev.ru 
1113198Sigor@sysoev.ru     return;
1114198Sigor@sysoev.ru 
1115198Sigor@sysoev.ru fail:
1116198Sigor@sysoev.ru 
1117198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1118198Sigor@sysoev.ru 
1119198Sigor@sysoev.ru     return;
1120139Sigor@sysoev.ru }
1121139Sigor@sysoev.ru 
1122139Sigor@sysoev.ru 
1123139Sigor@sysoev.ru static void
1124139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1125139Sigor@sysoev.ru {
1126153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1127153Sigor@sysoev.ru 
1128153Sigor@sysoev.ru     job = obj;
1129153Sigor@sysoev.ru 
1130198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1131139Sigor@sysoev.ru }
1132139Sigor@sysoev.ru 
1133139Sigor@sysoev.ru 
1134139Sigor@sysoev.ru static void
1135198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1136139Sigor@sysoev.ru {
1137139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
1138139Sigor@sysoev.ru 
1139139Sigor@sysoev.ru     if (--tmcf->count == 0) {
1140193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1141139Sigor@sysoev.ru     }
1142139Sigor@sysoev.ru }
1143139Sigor@sysoev.ru 
1144139Sigor@sysoev.ru 
1145139Sigor@sysoev.ru static void
1146139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1147139Sigor@sysoev.ru {
1148507Smax.romanov@nginx.com     nxt_app_t          *app;
1149568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1150148Sigor@sysoev.ru     nxt_socket_t       s;
1151149Sigor@sysoev.ru     nxt_router_t       *router;
1152148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1153148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1154630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1155148Sigor@sysoev.ru 
1156564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1157198Sigor@sysoev.ru 
1158148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
1159148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
1160148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1161148Sigor@sysoev.ru     {
1162148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1163359Sigor@sysoev.ru         s = skcf->listen->socket;
1164148Sigor@sysoev.ru 
1165148Sigor@sysoev.ru         if (s != -1) {
1166148Sigor@sysoev.ru             nxt_socket_close(task, s);
1167148Sigor@sysoev.ru         }
1168148Sigor@sysoev.ru 
1169359Sigor@sysoev.ru         nxt_free(skcf->listen);
1170148Sigor@sysoev.ru     }
1171148Sigor@sysoev.ru 
1172568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
1173568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->updating);
1174568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->pending);
1175568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->creating);
1176568Smax.romanov@nginx.com 
1177964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1178964Sigor@sysoev.ru 
1179964Sigor@sysoev.ru     nxt_http_routes_cleanup(task, rtcf->routes);
1180964Sigor@sysoev.ru 
1181568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1182568Smax.romanov@nginx.com 
1183964Sigor@sysoev.ru         if (skcf->pass != NULL) {
1184964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
1185568Smax.romanov@nginx.com         }
1186568Smax.romanov@nginx.com 
1187568Smax.romanov@nginx.com     } nxt_queue_loop;
1188568Smax.romanov@nginx.com 
1189507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1190507Smax.romanov@nginx.com 
1191753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1192507Smax.romanov@nginx.com 
1193507Smax.romanov@nginx.com     } nxt_queue_loop;
1194507Smax.romanov@nginx.com 
1195630Svbart@nginx.com     router = rtcf->router;
1196149Sigor@sysoev.ru 
1197149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1198149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1199149Sigor@sysoev.ru 
1200416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1201416Smax.romanov@nginx.com 
1202148Sigor@sysoev.ru     // TODO: new engines and threads
1203148Sigor@sysoev.ru 
1204630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1205630Svbart@nginx.com 
1206630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1207139Sigor@sysoev.ru 
1208193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1209139Sigor@sysoev.ru }
1210139Sigor@sysoev.ru 
1211139Sigor@sysoev.ru 
1212139Sigor@sysoev.ru static void
1213139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1214193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1215139Sigor@sysoev.ru {
1216193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1217779Smax.romanov@nginx.com 
1218779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1219779Smax.romanov@nginx.com 
1220779Smax.romanov@nginx.com     tmcf->port = NULL;
1221139Sigor@sysoev.ru }
1222139Sigor@sysoev.ru 
1223139Sigor@sysoev.ru 
1224115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1225115Sigor@sysoev.ru     {
1226133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1227115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1228115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1229115Sigor@sysoev.ru     },
1230115Sigor@sysoev.ru };
1231115Sigor@sysoev.ru 
1232115Sigor@sysoev.ru 
1233133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1234115Sigor@sysoev.ru     {
1235133Sigor@sysoev.ru         nxt_string("type"),
1236115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1237133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1238115Sigor@sysoev.ru     },
1239115Sigor@sysoev.ru 
1240115Sigor@sysoev.ru     {
1241507Smax.romanov@nginx.com         nxt_string("limits"),
1242507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1243507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1244133Sigor@sysoev.ru     },
1245318Smax.romanov@nginx.com 
1246318Smax.romanov@nginx.com     {
1247507Smax.romanov@nginx.com         nxt_string("processes"),
1248507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1249507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1250507Smax.romanov@nginx.com     },
1251507Smax.romanov@nginx.com 
1252507Smax.romanov@nginx.com     {
1253507Smax.romanov@nginx.com         nxt_string("processes"),
1254318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1255507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1256318Smax.romanov@nginx.com     },
1257318Smax.romanov@nginx.com };
1258318Smax.romanov@nginx.com 
1259318Smax.romanov@nginx.com 
1260318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1261318Smax.romanov@nginx.com     {
1262318Smax.romanov@nginx.com         nxt_string("timeout"),
1263318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1264318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1265318Smax.romanov@nginx.com     },
1266318Smax.romanov@nginx.com 
1267318Smax.romanov@nginx.com     {
1268427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1269427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1270427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1271427Smax.romanov@nginx.com     },
1272427Smax.romanov@nginx.com 
1273427Smax.romanov@nginx.com     {
1274318Smax.romanov@nginx.com         nxt_string("requests"),
1275318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1276318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1277318Smax.romanov@nginx.com     },
1278133Sigor@sysoev.ru };
1279133Sigor@sysoev.ru 
1280133Sigor@sysoev.ru 
1281507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1282507Smax.romanov@nginx.com     {
1283507Smax.romanov@nginx.com         nxt_string("spare"),
1284507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1285507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1286507Smax.romanov@nginx.com     },
1287507Smax.romanov@nginx.com 
1288507Smax.romanov@nginx.com     {
1289507Smax.romanov@nginx.com         nxt_string("max"),
1290507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1291507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1292507Smax.romanov@nginx.com     },
1293507Smax.romanov@nginx.com 
1294507Smax.romanov@nginx.com     {
1295507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1296507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1297507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1298507Smax.romanov@nginx.com     },
1299507Smax.romanov@nginx.com };
1300507Smax.romanov@nginx.com 
1301507Smax.romanov@nginx.com 
1302133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1303133Sigor@sysoev.ru     {
1304964Sigor@sysoev.ru         nxt_string("pass"),
1305964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1306964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1307964Sigor@sysoev.ru     },
1308964Sigor@sysoev.ru 
1309964Sigor@sysoev.ru     {
1310133Sigor@sysoev.ru         nxt_string("application"),
1311964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1312133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1313115Sigor@sysoev.ru     },
1314115Sigor@sysoev.ru };
1315115Sigor@sysoev.ru 
1316115Sigor@sysoev.ru 
1317115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1318115Sigor@sysoev.ru     {
1319115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1320115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1321115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1322115Sigor@sysoev.ru     },
1323115Sigor@sysoev.ru 
1324115Sigor@sysoev.ru     {
1325115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1326115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1327115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1328115Sigor@sysoev.ru     },
1329115Sigor@sysoev.ru 
1330115Sigor@sysoev.ru     {
1331206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1332206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1333206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1334206Smax.romanov@nginx.com     },
1335206Smax.romanov@nginx.com 
1336206Smax.romanov@nginx.com     {
1337206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1338206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1339206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1340206Smax.romanov@nginx.com     },
1341206Smax.romanov@nginx.com 
1342206Smax.romanov@nginx.com     {
1343206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1344206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1345206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1346206Smax.romanov@nginx.com     },
1347206Smax.romanov@nginx.com 
1348206Smax.romanov@nginx.com     {
1349431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1350431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1351431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1352431Sigor@sysoev.ru     },
1353431Sigor@sysoev.ru 
1354431Sigor@sysoev.ru     {
1355115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1356115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1357115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1358115Sigor@sysoev.ru     },
1359206Smax.romanov@nginx.com 
1360206Smax.romanov@nginx.com     {
1361206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1362206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1363206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1364206Smax.romanov@nginx.com     },
1365431Sigor@sysoev.ru 
1366431Sigor@sysoev.ru     {
1367431Sigor@sysoev.ru         nxt_string("send_timeout"),
1368431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1369431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1370431Sigor@sysoev.ru     },
1371115Sigor@sysoev.ru };
1372115Sigor@sysoev.ru 
1373115Sigor@sysoev.ru 
137453Sigor@sysoev.ru static nxt_int_t
1375115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1376115Sigor@sysoev.ru     u_char *start, u_char *end)
137753Sigor@sysoev.ru {
1378133Sigor@sysoev.ru     u_char                      *p;
1379133Sigor@sysoev.ru     size_t                      size;
1380115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1381115Sigor@sysoev.ru     uint32_t                    next;
1382115Sigor@sysoev.ru     nxt_int_t                   ret;
1383630Svbart@nginx.com     nxt_str_t                   name, path;
1384133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1385359Sigor@sysoev.ru     nxt_router_t                *router;
1386753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
1387630Svbart@nginx.com     nxt_conf_value_t            *conf, *http, *value;
1388133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1389133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1390964Sigor@sysoev.ru     nxt_conf_value_t            *routes_conf;
1391115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1392964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1393507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1394216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1395133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1396630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1397115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1398774Svbart@nginx.com #if (NXT_TLS)
1399774Svbart@nginx.com     nxt_router_tlssock_t        *tls;
1400774Svbart@nginx.com #endif
1401115Sigor@sysoev.ru 
1402716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1403133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1404115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1405964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1406630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1407774Svbart@nginx.com #if (NXT_TLS)
1408774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1409774Svbart@nginx.com #endif
1410115Sigor@sysoev.ru 
1411208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1412115Sigor@sysoev.ru     if (conf == NULL) {
1413564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1414115Sigor@sysoev.ru         return NXT_ERROR;
1415115Sigor@sysoev.ru     }
1416115Sigor@sysoev.ru 
1417591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1418213Svbart@nginx.com 
1419213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1420591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1421115Sigor@sysoev.ru     if (ret != NXT_OK) {
1422564Svbart@nginx.com         nxt_alert(task, "root map error");
1423115Sigor@sysoev.ru         return NXT_ERROR;
1424115Sigor@sysoev.ru     }
1425115Sigor@sysoev.ru 
1426591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1427591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1428117Sigor@sysoev.ru     }
1429117Sigor@sysoev.ru 
1430133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1431133Sigor@sysoev.ru     if (applications == NULL) {
1432564Svbart@nginx.com         nxt_alert(task, "no \"applications\" block");
1433115Sigor@sysoev.ru         return NXT_ERROR;
1434115Sigor@sysoev.ru     }
1435115Sigor@sysoev.ru 
1436591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1437359Sigor@sysoev.ru 
1438133Sigor@sysoev.ru     next = 0;
1439133Sigor@sysoev.ru 
1440133Sigor@sysoev.ru     for ( ;; ) {
1441133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1442133Sigor@sysoev.ru         if (application == NULL) {
1443133Sigor@sysoev.ru             break;
1444133Sigor@sysoev.ru         }
1445133Sigor@sysoev.ru 
1446133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1447133Sigor@sysoev.ru 
1448144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1449144Smax.romanov@nginx.com 
1450144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1451133Sigor@sysoev.ru         if (app == NULL) {
1452133Sigor@sysoev.ru             goto fail;
1453133Sigor@sysoev.ru         }
1454133Sigor@sysoev.ru 
1455144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1456144Smax.romanov@nginx.com 
1457144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1458144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1459133Sigor@sysoev.ru 
1460133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1461133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1462133Sigor@sysoev.ru 
1463144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1464144Smax.romanov@nginx.com 
1465133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1466133Sigor@sysoev.ru 
1467359Sigor@sysoev.ru         prev = nxt_router_app_find(&router->apps, &name);
1468133Sigor@sysoev.ru 
1469133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1470133Sigor@sysoev.ru             nxt_free(app);
1471133Sigor@sysoev.ru 
1472133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1473133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1474133Sigor@sysoev.ru             continue;
1475133Sigor@sysoev.ru         }
1476133Sigor@sysoev.ru 
1477507Smax.romanov@nginx.com         apcf.processes = 1;
1478507Smax.romanov@nginx.com         apcf.max_processes = 1;
1479537Svbart@nginx.com         apcf.spare_processes = 0;
1480318Smax.romanov@nginx.com         apcf.timeout = 0;
1481427Smax.romanov@nginx.com         apcf.res_timeout = 1000;
1482507Smax.romanov@nginx.com         apcf.idle_timeout = 15000;
1483318Smax.romanov@nginx.com         apcf.requests = 0;
1484318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1485507Smax.romanov@nginx.com         apcf.processes_value = NULL;
1486263Smax.romanov@nginx.com 
1487753Smax.romanov@nginx.com         app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
1488753Smax.romanov@nginx.com         if (nxt_slow_path(app_joint == NULL)) {
1489753Smax.romanov@nginx.com             goto app_fail;
1490753Smax.romanov@nginx.com         }
1491753Smax.romanov@nginx.com 
1492753Smax.romanov@nginx.com         nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
1493753Smax.romanov@nginx.com 
1494213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1495136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1496133Sigor@sysoev.ru         if (ret != NXT_OK) {
1497564Svbart@nginx.com             nxt_alert(task, "application map error");
1498133Sigor@sysoev.ru             goto app_fail;
1499133Sigor@sysoev.ru         }
1500115Sigor@sysoev.ru 
1501318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1502318Smax.romanov@nginx.com 
1503318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1504564Svbart@nginx.com                 nxt_alert(task, "application limits is not object");
1505318Smax.romanov@nginx.com                 goto app_fail;
1506318Smax.romanov@nginx.com             }
1507318Smax.romanov@nginx.com 
1508318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1509318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1510318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1511318Smax.romanov@nginx.com                                       &apcf);
1512318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1513564Svbart@nginx.com                 nxt_alert(task, "application limits map error");
1514318Smax.romanov@nginx.com                 goto app_fail;
1515318Smax.romanov@nginx.com             }
1516318Smax.romanov@nginx.com         }
1517318Smax.romanov@nginx.com 
1518507Smax.romanov@nginx.com         if (apcf.processes_value != NULL
1519507Smax.romanov@nginx.com             && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1520507Smax.romanov@nginx.com         {
1521507Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.processes_value,
1522507Smax.romanov@nginx.com                                       nxt_router_app_processes_conf,
1523507Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_processes_conf),
1524507Smax.romanov@nginx.com                                       &apcf);
1525507Smax.romanov@nginx.com             if (ret != NXT_OK) {
1526564Svbart@nginx.com                 nxt_alert(task, "application processes map error");
1527507Smax.romanov@nginx.com                 goto app_fail;
1528507Smax.romanov@nginx.com             }
1529507Smax.romanov@nginx.com 
1530507Smax.romanov@nginx.com         } else {
1531507Smax.romanov@nginx.com             apcf.max_processes = apcf.processes;
1532507Smax.romanov@nginx.com             apcf.spare_processes = apcf.processes;
1533507Smax.romanov@nginx.com         }
1534507Smax.romanov@nginx.com 
1535133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1536507Smax.romanov@nginx.com         nxt_debug(task, "application processes: %D", apcf.processes);
1537507Smax.romanov@nginx.com         nxt_debug(task, "application request timeout: %M", apcf.timeout);
1538507Smax.romanov@nginx.com         nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout);
1539318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1540133Sigor@sysoev.ru 
1541216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1542216Sigor@sysoev.ru 
1543216Sigor@sysoev.ru         if (lang == NULL) {
1544564Svbart@nginx.com             nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1545141Smax.romanov@nginx.com             goto app_fail;
1546141Smax.romanov@nginx.com         }
1547141Smax.romanov@nginx.com 
1548216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1549216Sigor@sysoev.ru 
1550133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1551133Sigor@sysoev.ru         if (ret != NXT_OK) {
1552133Sigor@sysoev.ru             goto app_fail;
1553133Sigor@sysoev.ru         }
1554133Sigor@sysoev.ru 
1555141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1556507Smax.romanov@nginx.com         nxt_queue_init(&app->spare_ports);
1557507Smax.romanov@nginx.com         nxt_queue_init(&app->idle_ports);
1558141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1559427Smax.romanov@nginx.com         nxt_queue_init(&app->pending);
1560141Smax.romanov@nginx.com 
1561144Smax.romanov@nginx.com         app->name.length = name.length;
1562144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1563144Smax.romanov@nginx.com 
1564356Svbart@nginx.com         app->type = lang->type;
1565507Smax.romanov@nginx.com         app->max_processes = apcf.max_processes;
1566507Smax.romanov@nginx.com         app->spare_processes = apcf.spare_processes;
1567507Smax.romanov@nginx.com         app->max_pending_processes = apcf.spare_processes
1568507Smax.romanov@nginx.com                                       ? apcf.spare_processes : 1;
1569318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1570427Smax.romanov@nginx.com         app->res_timeout = apcf.res_timeout * 1000000;
1571507Smax.romanov@nginx.com         app->idle_timeout = apcf.idle_timeout;
1572343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1573428Smax.romanov@nginx.com         app->max_requests = apcf.requests;
1574133Sigor@sysoev.ru 
1575507Smax.romanov@nginx.com         engine = task->thread->engine;
1576507Smax.romanov@nginx.com 
1577507Smax.romanov@nginx.com         app->engine = engine;
1578507Smax.romanov@nginx.com 
1579507Smax.romanov@nginx.com         app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1580507Smax.romanov@nginx.com         app->adjust_idle_work.task = &engine->task;
1581507Smax.romanov@nginx.com         app->adjust_idle_work.obj = app;
1582507Smax.romanov@nginx.com 
1583133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1584343Smax.romanov@nginx.com 
1585343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1586753Smax.romanov@nginx.com 
1587753Smax.romanov@nginx.com         app->joint = app_joint;
1588753Smax.romanov@nginx.com 
1589753Smax.romanov@nginx.com         app_joint->use_count = 1;
1590753Smax.romanov@nginx.com         app_joint->app = app;
1591753Smax.romanov@nginx.com 
1592811Svbart@nginx.com         app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
1593753Smax.romanov@nginx.com         app_joint->idle_timer.work_queue = &engine->fast_work_queue;
1594753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
1595753Smax.romanov@nginx.com         app_joint->idle_timer.task = &engine->task;
1596753Smax.romanov@nginx.com         app_joint->idle_timer.log = app_joint->idle_timer.task->log;
1597753Smax.romanov@nginx.com 
1598753Smax.romanov@nginx.com         app_joint->free_app_work.handler = nxt_router_free_app;
1599753Smax.romanov@nginx.com         app_joint->free_app_work.task = &engine->task;
1600753Smax.romanov@nginx.com         app_joint->free_app_work.obj = app_joint;
1601133Sigor@sysoev.ru     }
1602133Sigor@sysoev.ru 
1603964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1604964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1605964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1606964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1607964Sigor@sysoev.ru             return NXT_ERROR;
1608964Sigor@sysoev.ru         }
1609964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1610964Sigor@sysoev.ru     }
1611964Sigor@sysoev.ru 
1612133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1613133Sigor@sysoev.ru #if 0
1614133Sigor@sysoev.ru     if (http == NULL) {
1615564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1616133Sigor@sysoev.ru         return NXT_ERROR;
1617133Sigor@sysoev.ru     }
1618133Sigor@sysoev.ru #endif
1619133Sigor@sysoev.ru 
1620133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1621115Sigor@sysoev.ru     if (listeners == NULL) {
1622564Svbart@nginx.com         nxt_alert(task, "no \"listeners\" block");
1623115Sigor@sysoev.ru         return NXT_ERROR;
1624115Sigor@sysoev.ru     }
162553Sigor@sysoev.ru 
1626133Sigor@sysoev.ru     next = 0;
162753Sigor@sysoev.ru 
1628115Sigor@sysoev.ru     for ( ;; ) {
1629115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1630115Sigor@sysoev.ru         if (listener == NULL) {
1631115Sigor@sysoev.ru             break;
1632115Sigor@sysoev.ru         }
163353Sigor@sysoev.ru 
1634359Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, tmcf, &name);
1635115Sigor@sysoev.ru         if (skcf == NULL) {
1636133Sigor@sysoev.ru             goto fail;
1637115Sigor@sysoev.ru         }
163853Sigor@sysoev.ru 
1639770Smax.romanov@nginx.com         nxt_memzero(&lscf, sizeof(lscf));
1640770Smax.romanov@nginx.com 
1641213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1642136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1643115Sigor@sysoev.ru         if (ret != NXT_OK) {
1644564Svbart@nginx.com             nxt_alert(task, "listener map error");
1645133Sigor@sysoev.ru             goto fail;
1646115Sigor@sysoev.ru         }
164753Sigor@sysoev.ru 
1648133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1649133Sigor@sysoev.ru 
1650133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1651133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1652133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1653206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1654206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1655715Svbart@nginx.com         skcf->max_body_size = 8 * 1024 * 1024;
1656715Svbart@nginx.com         skcf->idle_timeout = 180 * 1000;
1657715Svbart@nginx.com         skcf->header_read_timeout = 30 * 1000;
1658715Svbart@nginx.com         skcf->body_read_timeout = 30 * 1000;
1659715Svbart@nginx.com         skcf->send_timeout = 30 * 1000;
166053Sigor@sysoev.ru 
1661133Sigor@sysoev.ru         if (http != NULL) {
1662213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1663136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1664133Sigor@sysoev.ru             if (ret != NXT_OK) {
1665564Svbart@nginx.com                 nxt_alert(task, "http map error");
1666133Sigor@sysoev.ru                 goto fail;
1667133Sigor@sysoev.ru             }
1668115Sigor@sysoev.ru         }
1669115Sigor@sysoev.ru 
1670774Svbart@nginx.com #if (NXT_TLS)
1671774Svbart@nginx.com 
1672774Svbart@nginx.com         value = nxt_conf_get_path(listener, &certificate_path);
1673774Svbart@nginx.com 
1674774Svbart@nginx.com         if (value != NULL) {
1675774Svbart@nginx.com             nxt_conf_get_string(value, &name);
1676774Svbart@nginx.com 
1677774Svbart@nginx.com             tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
1678774Svbart@nginx.com             if (nxt_slow_path(tls == NULL)) {
1679774Svbart@nginx.com                 goto fail;
1680774Svbart@nginx.com             }
1681774Svbart@nginx.com 
1682774Svbart@nginx.com             tls->name = name;
1683774Svbart@nginx.com             tls->conf = skcf;
1684774Svbart@nginx.com 
1685774Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1686774Svbart@nginx.com         }
1687774Svbart@nginx.com 
1688774Svbart@nginx.com #endif
1689774Svbart@nginx.com 
1690431Sigor@sysoev.ru         skcf->listen->handler = nxt_http_conn_init;
1691591Sigor@sysoev.ru         skcf->router_conf = tmcf->router_conf;
1692160Sigor@sysoev.ru         skcf->router_conf->count++;
1693770Smax.romanov@nginx.com 
1694964Sigor@sysoev.ru         if (lscf.pass.length != 0) {
1695964Sigor@sysoev.ru             skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass);
1696964Sigor@sysoev.ru 
1697964Sigor@sysoev.ru         /* COMPATIBILITY: listener application. */
1698964Sigor@sysoev.ru         } else if (lscf.application.length > 0) {
1699964Sigor@sysoev.ru             skcf->pass = nxt_http_pass_application(task, tmcf,
1700964Sigor@sysoev.ru                                                    &lscf.application);
1701770Smax.romanov@nginx.com         }
1702115Sigor@sysoev.ru     }
170353Sigor@sysoev.ru 
1704630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1705630Svbart@nginx.com 
1706630Svbart@nginx.com     if (value != NULL) {
1707630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1708630Svbart@nginx.com 
1709630Svbart@nginx.com         access_log = router->access_log;
1710630Svbart@nginx.com 
1711630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1712630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1713630Svbart@nginx.com             access_log->count++;
1714630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1715630Svbart@nginx.com 
1716630Svbart@nginx.com         } else {
1717630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1718630Svbart@nginx.com                                     + path.length);
1719630Svbart@nginx.com             if (access_log == NULL) {
1720630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1721630Svbart@nginx.com                 goto fail;
1722630Svbart@nginx.com             }
1723630Svbart@nginx.com 
1724630Svbart@nginx.com             access_log->fd = -1;
1725630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1726630Svbart@nginx.com             access_log->count = 1;
1727630Svbart@nginx.com 
1728630Svbart@nginx.com             access_log->path.length = path.length;
1729630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1730630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1731630Svbart@nginx.com 
1732630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1733630Svbart@nginx.com         }
1734630Svbart@nginx.com 
1735630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1736630Svbart@nginx.com     }
1737630Svbart@nginx.com 
1738964Sigor@sysoev.ru     nxt_http_routes_resolve(task, tmcf);
1739964Sigor@sysoev.ru 
1740359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1741359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1742198Sigor@sysoev.ru 
174353Sigor@sysoev.ru     return NXT_OK;
1744133Sigor@sysoev.ru 
1745133Sigor@sysoev.ru app_fail:
1746133Sigor@sysoev.ru 
1747133Sigor@sysoev.ru     nxt_free(app);
1748133Sigor@sysoev.ru 
1749133Sigor@sysoev.ru fail:
1750133Sigor@sysoev.ru 
1751141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1752141Smax.romanov@nginx.com 
1753141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1754133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1755133Sigor@sysoev.ru         nxt_free(app);
1756141Smax.romanov@nginx.com 
1757141Smax.romanov@nginx.com     } nxt_queue_loop;
1758133Sigor@sysoev.ru 
1759133Sigor@sysoev.ru     return NXT_ERROR;
1760133Sigor@sysoev.ru }
1761133Sigor@sysoev.ru 
1762133Sigor@sysoev.ru 
1763133Sigor@sysoev.ru static nxt_app_t *
1764133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1765133Sigor@sysoev.ru {
1766141Smax.romanov@nginx.com     nxt_app_t  *app;
1767141Smax.romanov@nginx.com 
1768141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1769133Sigor@sysoev.ru 
1770133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1771133Sigor@sysoev.ru             return app;
1772133Sigor@sysoev.ru         }
1773141Smax.romanov@nginx.com 
1774141Smax.romanov@nginx.com     } nxt_queue_loop;
1775133Sigor@sysoev.ru 
1776133Sigor@sysoev.ru     return NULL;
1777133Sigor@sysoev.ru }
1778133Sigor@sysoev.ru 
1779133Sigor@sysoev.ru 
1780964Sigor@sysoev.ru nxt_app_t *
1781133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1782133Sigor@sysoev.ru {
1783133Sigor@sysoev.ru     nxt_app_t  *app;
1784133Sigor@sysoev.ru 
1785133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1786133Sigor@sysoev.ru 
1787133Sigor@sysoev.ru     if (app == NULL) {
1788134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1789133Sigor@sysoev.ru     }
1790133Sigor@sysoev.ru 
1791133Sigor@sysoev.ru     return app;
179253Sigor@sysoev.ru }
179353Sigor@sysoev.ru 
179453Sigor@sysoev.ru 
179553Sigor@sysoev.ru static nxt_socket_conf_t *
1796359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1797359Sigor@sysoev.ru     nxt_str_t *name)
179853Sigor@sysoev.ru {
1799359Sigor@sysoev.ru     size_t               size;
1800359Sigor@sysoev.ru     nxt_int_t            ret;
1801359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1802359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1803359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1804359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1805359Sigor@sysoev.ru 
1806359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1807359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1808564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1809359Sigor@sysoev.ru         return NULL;
1810359Sigor@sysoev.ru     }
1811359Sigor@sysoev.ru 
1812359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1813359Sigor@sysoev.ru 
1814359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1815493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1816359Sigor@sysoev.ru 
1817591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1818163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
181953Sigor@sysoev.ru         return NULL;
182053Sigor@sysoev.ru     }
182153Sigor@sysoev.ru 
1822359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1823359Sigor@sysoev.ru 
1824359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1825359Sigor@sysoev.ru 
1826359Sigor@sysoev.ru     if (ret != NXT_OK) {
1827359Sigor@sysoev.ru 
1828359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1829359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1830359Sigor@sysoev.ru             return NULL;
1831359Sigor@sysoev.ru         }
1832359Sigor@sysoev.ru 
1833359Sigor@sysoev.ru         skcf->listen = ls;
1834359Sigor@sysoev.ru 
1835359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1836359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1837359Sigor@sysoev.ru 
1838359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1839359Sigor@sysoev.ru 
1840359Sigor@sysoev.ru         ls->socket = -1;
1841359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1842359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1843359Sigor@sysoev.ru         ls->read_after_accept = 1;
1844359Sigor@sysoev.ru     }
1845359Sigor@sysoev.ru 
1846359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1847359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1848359Sigor@sysoev.ru     case AF_UNIX:
1849359Sigor@sysoev.ru         wildcard = 0;
1850359Sigor@sysoev.ru         break;
1851359Sigor@sysoev.ru #endif
1852359Sigor@sysoev.ru #if (NXT_INET6)
1853359Sigor@sysoev.ru     case AF_INET6:
1854359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1855359Sigor@sysoev.ru         break;
1856359Sigor@sysoev.ru #endif
1857359Sigor@sysoev.ru     case AF_INET:
1858359Sigor@sysoev.ru     default:
1859359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1860359Sigor@sysoev.ru         break;
1861359Sigor@sysoev.ru     }
1862359Sigor@sysoev.ru 
1863359Sigor@sysoev.ru     if (!wildcard) {
1864591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
1865359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1866359Sigor@sysoev.ru             return NULL;
1867359Sigor@sysoev.ru         }
1868359Sigor@sysoev.ru 
1869359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1870359Sigor@sysoev.ru     }
1871163Smax.romanov@nginx.com 
1872163Smax.romanov@nginx.com     return skcf;
187353Sigor@sysoev.ru }
187453Sigor@sysoev.ru 
187553Sigor@sysoev.ru 
1876359Sigor@sysoev.ru static nxt_int_t
1877359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1878359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
187953Sigor@sysoev.ru {
1880359Sigor@sysoev.ru     nxt_router_t       *router;
1881359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1882359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1883359Sigor@sysoev.ru 
1884591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1885359Sigor@sysoev.ru 
1886359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
1887359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
1888359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
188953Sigor@sysoev.ru     {
1890359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1891359Sigor@sysoev.ru 
1892359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
1893359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
1894359Sigor@sysoev.ru 
1895359Sigor@sysoev.ru             nxt_queue_remove(qlk);
1896359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
1897359Sigor@sysoev.ru 
1898359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
1899359Sigor@sysoev.ru 
1900359Sigor@sysoev.ru             return NXT_OK;
190153Sigor@sysoev.ru         }
190253Sigor@sysoev.ru     }
190353Sigor@sysoev.ru 
1904359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
1905359Sigor@sysoev.ru 
1906359Sigor@sysoev.ru     return NXT_DECLINED;
190753Sigor@sysoev.ru }
190853Sigor@sysoev.ru 
190953Sigor@sysoev.ru 
1910198Sigor@sysoev.ru static void
1911198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1912198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1913198Sigor@sysoev.ru {
1914358Sigor@sysoev.ru     size_t            size;
1915198Sigor@sysoev.ru     uint32_t          stream;
1916648Svbart@nginx.com     nxt_int_t         ret;
1917198Sigor@sysoev.ru     nxt_buf_t         *b;
1918198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1919198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1920198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1921198Sigor@sysoev.ru 
1922198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1923198Sigor@sysoev.ru     if (rpc == NULL) {
1924198Sigor@sysoev.ru         goto fail;
1925198Sigor@sysoev.ru     }
1926198Sigor@sysoev.ru 
1927198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1928198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1929198Sigor@sysoev.ru 
1930359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
1931358Sigor@sysoev.ru 
1932358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1933198Sigor@sysoev.ru     if (b == NULL) {
1934198Sigor@sysoev.ru         goto fail;
1935198Sigor@sysoev.ru     }
1936198Sigor@sysoev.ru 
1937359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
1938198Sigor@sysoev.ru 
1939198Sigor@sysoev.ru     rt = task->thread->runtime;
1940240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1941198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1942198Sigor@sysoev.ru 
1943198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1944198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1945198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1946198Sigor@sysoev.ru                                            main_port->pid, rpc);
1947645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
1948198Sigor@sysoev.ru         goto fail;
1949198Sigor@sysoev.ru     }
1950198Sigor@sysoev.ru 
1951648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1952648Svbart@nginx.com                                 stream, router_port->id, b);
1953648Svbart@nginx.com 
1954648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1955648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
1956648Svbart@nginx.com         goto fail;
1957648Svbart@nginx.com     }
1958198Sigor@sysoev.ru 
1959198Sigor@sysoev.ru     return;
1960198Sigor@sysoev.ru 
1961198Sigor@sysoev.ru fail:
1962198Sigor@sysoev.ru 
1963198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1964198Sigor@sysoev.ru }
1965198Sigor@sysoev.ru 
1966198Sigor@sysoev.ru 
1967198Sigor@sysoev.ru static void
1968198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1969198Sigor@sysoev.ru     void *data)
197053Sigor@sysoev.ru {
1971359Sigor@sysoev.ru     nxt_int_t         ret;
1972359Sigor@sysoev.ru     nxt_socket_t      s;
1973359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
197453Sigor@sysoev.ru 
1975198Sigor@sysoev.ru     rpc = data;
1976198Sigor@sysoev.ru 
1977198Sigor@sysoev.ru     s = msg->fd;
1978198Sigor@sysoev.ru 
1979198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1980198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1981198Sigor@sysoev.ru         goto fail;
198253Sigor@sysoev.ru     }
198353Sigor@sysoev.ru 
1984359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
1985198Sigor@sysoev.ru 
1986198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1987198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1988198Sigor@sysoev.ru         goto fail;
1989198Sigor@sysoev.ru     }
1990198Sigor@sysoev.ru 
1991359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
1992198Sigor@sysoev.ru 
1993198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1994198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1995198Sigor@sysoev.ru 
1996198Sigor@sysoev.ru     return;
1997148Sigor@sysoev.ru 
1998148Sigor@sysoev.ru fail:
1999148Sigor@sysoev.ru 
2000148Sigor@sysoev.ru     nxt_socket_close(task, s);
2001148Sigor@sysoev.ru 
2002198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2003198Sigor@sysoev.ru }
2004198Sigor@sysoev.ru 
2005198Sigor@sysoev.ru 
2006198Sigor@sysoev.ru static void
2007198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2008198Sigor@sysoev.ru     void *data)
2009198Sigor@sysoev.ru {
2010955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2011955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2012955Svbart@nginx.com 
2013955Svbart@nginx.com     rpc = data;
2014955Svbart@nginx.com     tmcf = rpc->temp_conf;
2015955Svbart@nginx.com 
2016955Svbart@nginx.com #if 0
2017198Sigor@sysoev.ru     u_char                  *p;
2018198Sigor@sysoev.ru     size_t                  size;
2019198Sigor@sysoev.ru     uint8_t                 error;
2020198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2021198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2022198Sigor@sysoev.ru 
2023198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2024198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2025198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2026198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2027198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2028198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2029198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2030198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2031198Sigor@sysoev.ru     };
2032198Sigor@sysoev.ru 
2033359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2034352Smax.romanov@nginx.com 
2035352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2036352Smax.romanov@nginx.com 
2037551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2038551Smax.romanov@nginx.com         return;
2039551Smax.romanov@nginx.com     }
2040352Smax.romanov@nginx.com 
2041198Sigor@sysoev.ru     p = in->mem.pos;
2042198Sigor@sysoev.ru 
2043198Sigor@sysoev.ru     error = *p++;
2044198Sigor@sysoev.ru 
2045703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2046703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2047198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2048198Sigor@sysoev.ru 
2049198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2050198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2051198Sigor@sysoev.ru         return;
2052198Sigor@sysoev.ru     }
2053198Sigor@sysoev.ru 
2054198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2055198Sigor@sysoev.ru                         "listen socket error: "
2056198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2057493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2058198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2059198Sigor@sysoev.ru 
2060198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2061955Svbart@nginx.com #endif
2062198Sigor@sysoev.ru 
2063198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
206453Sigor@sysoev.ru }
206553Sigor@sysoev.ru 
206653Sigor@sysoev.ru 
2067774Svbart@nginx.com #if (NXT_TLS)
2068774Svbart@nginx.com 
2069774Svbart@nginx.com static void
2070774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2071774Svbart@nginx.com     nxt_router_tlssock_t *tls)
2072774Svbart@nginx.com {
2073774Svbart@nginx.com     nxt_socket_rpc_t  *rpc;
2074774Svbart@nginx.com 
2075774Svbart@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2076774Svbart@nginx.com     if (rpc == NULL) {
2077774Svbart@nginx.com         nxt_router_conf_error(task, tmcf);
2078774Svbart@nginx.com         return;
2079774Svbart@nginx.com     }
2080774Svbart@nginx.com 
2081774Svbart@nginx.com     rpc->socket_conf = tls->conf;
2082774Svbart@nginx.com     rpc->temp_conf = tmcf;
2083774Svbart@nginx.com 
2084774Svbart@nginx.com     nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
2085774Svbart@nginx.com                        nxt_router_tls_rpc_handler, rpc);
2086774Svbart@nginx.com }
2087774Svbart@nginx.com 
2088774Svbart@nginx.com 
2089774Svbart@nginx.com static void
2090774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2091774Svbart@nginx.com     void *data)
2092774Svbart@nginx.com {
2093774Svbart@nginx.com     nxt_mp_t               *mp;
2094774Svbart@nginx.com     nxt_int_t              ret;
2095774Svbart@nginx.com     nxt_tls_conf_t         *tlscf;
2096774Svbart@nginx.com     nxt_socket_rpc_t       *rpc;
2097774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf;
2098774Svbart@nginx.com 
2099774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2100774Svbart@nginx.com 
2101774Svbart@nginx.com     rpc = data;
2102774Svbart@nginx.com     tmcf = rpc->temp_conf;
2103774Svbart@nginx.com 
2104774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2105774Svbart@nginx.com         goto fail;
2106774Svbart@nginx.com     }
2107774Svbart@nginx.com 
2108774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2109774Svbart@nginx.com 
2110774Svbart@nginx.com     tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2111774Svbart@nginx.com     if (nxt_slow_path(tlscf == NULL)) {
2112774Svbart@nginx.com         goto fail;
2113774Svbart@nginx.com     }
2114774Svbart@nginx.com 
2115774Svbart@nginx.com     tlscf->chain_file = msg->fd;
2116774Svbart@nginx.com 
2117774Svbart@nginx.com     ret = task->thread->runtime->tls->server_init(task, tlscf);
2118774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2119774Svbart@nginx.com         goto fail;
2120774Svbart@nginx.com     }
2121774Svbart@nginx.com 
2122774Svbart@nginx.com     rpc->socket_conf->tls = tlscf;
2123774Svbart@nginx.com 
2124774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2125774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2126774Svbart@nginx.com     return;
2127774Svbart@nginx.com 
2128774Svbart@nginx.com fail:
2129774Svbart@nginx.com 
2130774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2131774Svbart@nginx.com }
2132774Svbart@nginx.com 
2133774Svbart@nginx.com #endif
2134774Svbart@nginx.com 
2135774Svbart@nginx.com 
2136507Smax.romanov@nginx.com static void
2137507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2138507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2139507Smax.romanov@nginx.com {
2140507Smax.romanov@nginx.com     size_t         size;
2141507Smax.romanov@nginx.com     uint32_t       stream;
2142648Svbart@nginx.com     nxt_int_t      ret;
2143507Smax.romanov@nginx.com     nxt_buf_t      *b;
2144507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
2145507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2146507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2147507Smax.romanov@nginx.com 
2148507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2149507Smax.romanov@nginx.com     if (rpc == NULL) {
2150507Smax.romanov@nginx.com         goto fail;
2151507Smax.romanov@nginx.com     }
2152507Smax.romanov@nginx.com 
2153507Smax.romanov@nginx.com     rpc->app = app;
2154507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2155507Smax.romanov@nginx.com 
2156507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
2157507Smax.romanov@nginx.com 
2158507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
2159507Smax.romanov@nginx.com 
2160507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2161507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2162507Smax.romanov@nginx.com         goto fail;
2163507Smax.romanov@nginx.com     }
2164507Smax.romanov@nginx.com 
2165507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
2166507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
2167507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2168507Smax.romanov@nginx.com 
2169507Smax.romanov@nginx.com     rt = task->thread->runtime;
2170507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2171507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2172507Smax.romanov@nginx.com 
2173507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2174507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
2175507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
2176507Smax.romanov@nginx.com                                            -1, rpc);
2177507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2178507Smax.romanov@nginx.com         goto fail;
2179507Smax.romanov@nginx.com     }
2180507Smax.romanov@nginx.com 
2181648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2182648Svbart@nginx.com                                 stream, router_port->id, b);
2183648Svbart@nginx.com 
2184648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2185648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2186648Svbart@nginx.com         goto fail;
2187648Svbart@nginx.com     }
2188648Svbart@nginx.com 
2189507Smax.romanov@nginx.com     app->pending_processes++;
2190507Smax.romanov@nginx.com 
2191507Smax.romanov@nginx.com     return;
2192507Smax.romanov@nginx.com 
2193507Smax.romanov@nginx.com fail:
2194507Smax.romanov@nginx.com 
2195507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2196507Smax.romanov@nginx.com }
2197507Smax.romanov@nginx.com 
2198507Smax.romanov@nginx.com 
2199507Smax.romanov@nginx.com static void
2200507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2201507Smax.romanov@nginx.com     void *data)
2202507Smax.romanov@nginx.com {
2203507Smax.romanov@nginx.com     nxt_app_t           *app;
2204507Smax.romanov@nginx.com     nxt_port_t          *port;
2205507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2206507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2207507Smax.romanov@nginx.com 
2208507Smax.romanov@nginx.com     rpc = data;
2209507Smax.romanov@nginx.com     app = rpc->app;
2210507Smax.romanov@nginx.com 
2211507Smax.romanov@nginx.com     port = msg->u.new_port;
2212507Smax.romanov@nginx.com     port->app = app;
2213507Smax.romanov@nginx.com 
2214507Smax.romanov@nginx.com     app->pending_processes--;
2215507Smax.romanov@nginx.com     app->processes++;
2216507Smax.romanov@nginx.com     app->idle_processes++;
2217507Smax.romanov@nginx.com 
2218507Smax.romanov@nginx.com     engine = task->thread->engine;
2219507Smax.romanov@nginx.com 
2220507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2221507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2222507Smax.romanov@nginx.com 
2223507Smax.romanov@nginx.com     port->idle_start = 0;
2224507Smax.romanov@nginx.com 
2225507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2226507Smax.romanov@nginx.com 
2227507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2228507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2229507Smax.romanov@nginx.com }
2230507Smax.romanov@nginx.com 
2231507Smax.romanov@nginx.com 
2232507Smax.romanov@nginx.com static void
2233507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2234507Smax.romanov@nginx.com     void *data)
2235507Smax.romanov@nginx.com {
2236507Smax.romanov@nginx.com     nxt_app_t               *app;
2237507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2238507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2239507Smax.romanov@nginx.com 
2240507Smax.romanov@nginx.com     rpc = data;
2241507Smax.romanov@nginx.com     app = rpc->app;
2242507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2243507Smax.romanov@nginx.com 
2244507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2245507Smax.romanov@nginx.com             &app->name);
2246507Smax.romanov@nginx.com 
2247507Smax.romanov@nginx.com     app->pending_processes--;
2248507Smax.romanov@nginx.com 
2249507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2250507Smax.romanov@nginx.com }
2251507Smax.romanov@nginx.com 
2252507Smax.romanov@nginx.com 
225353Sigor@sysoev.ru static nxt_int_t
225453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
225553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
225653Sigor@sysoev.ru {
225753Sigor@sysoev.ru     nxt_int_t                 ret;
225853Sigor@sysoev.ru     nxt_uint_t                n, threads;
225953Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
226053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
226153Sigor@sysoev.ru 
2262591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
226353Sigor@sysoev.ru 
226453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
226553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
226653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
226753Sigor@sysoev.ru         return NXT_ERROR;
226853Sigor@sysoev.ru     }
226953Sigor@sysoev.ru 
227053Sigor@sysoev.ru     n = 0;
227153Sigor@sysoev.ru 
227253Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
227353Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
227453Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
227553Sigor@sysoev.ru     {
227653Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
227753Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
227853Sigor@sysoev.ru             return NXT_ERROR;
227953Sigor@sysoev.ru         }
228053Sigor@sysoev.ru 
2281115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
228253Sigor@sysoev.ru 
228353Sigor@sysoev.ru         if (n < threads) {
2284315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2285115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
228653Sigor@sysoev.ru 
228753Sigor@sysoev.ru         } else {
2288315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2289115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
229053Sigor@sysoev.ru         }
229153Sigor@sysoev.ru 
229253Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
229353Sigor@sysoev.ru             return ret;
229453Sigor@sysoev.ru         }
229553Sigor@sysoev.ru 
229653Sigor@sysoev.ru         n++;
229753Sigor@sysoev.ru     }
229853Sigor@sysoev.ru 
229953Sigor@sysoev.ru     tmcf->new_threads = n;
230053Sigor@sysoev.ru 
230153Sigor@sysoev.ru     while (n < threads) {
230253Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
230353Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
230453Sigor@sysoev.ru             return NXT_ERROR;
230553Sigor@sysoev.ru         }
230653Sigor@sysoev.ru 
2307315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2308315Sigor@sysoev.ru 
230953Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
231053Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
231153Sigor@sysoev.ru             return NXT_ERROR;
231253Sigor@sysoev.ru         }
231353Sigor@sysoev.ru 
2314115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
231553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
231653Sigor@sysoev.ru             return ret;
231753Sigor@sysoev.ru         }
231853Sigor@sysoev.ru 
231953Sigor@sysoev.ru         n++;
232053Sigor@sysoev.ru     }
232153Sigor@sysoev.ru 
232253Sigor@sysoev.ru     return NXT_OK;
232353Sigor@sysoev.ru }
232453Sigor@sysoev.ru 
232553Sigor@sysoev.ru 
232653Sigor@sysoev.ru static nxt_int_t
2327115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2328115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
232953Sigor@sysoev.ru {
2330359Sigor@sysoev.ru     nxt_int_t  ret;
233153Sigor@sysoev.ru 
2332154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2333154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2334115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2335115Sigor@sysoev.ru         return ret;
2336115Sigor@sysoev.ru     }
2337115Sigor@sysoev.ru 
2338154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2339154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
234053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
234153Sigor@sysoev.ru         return ret;
234253Sigor@sysoev.ru     }
234353Sigor@sysoev.ru 
2344115Sigor@sysoev.ru     return ret;
234553Sigor@sysoev.ru }
234653Sigor@sysoev.ru 
234753Sigor@sysoev.ru 
234853Sigor@sysoev.ru static nxt_int_t
2349115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2350115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
235153Sigor@sysoev.ru {
2352359Sigor@sysoev.ru     nxt_int_t  ret;
235353Sigor@sysoev.ru 
2354154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2355154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
235653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
235753Sigor@sysoev.ru         return ret;
235853Sigor@sysoev.ru     }
235953Sigor@sysoev.ru 
2360154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2361154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
236253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
236353Sigor@sysoev.ru         return ret;
236453Sigor@sysoev.ru     }
236553Sigor@sysoev.ru 
2366139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
2367115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2368115Sigor@sysoev.ru         return ret;
2369115Sigor@sysoev.ru     }
2370115Sigor@sysoev.ru 
2371115Sigor@sysoev.ru     return ret;
237253Sigor@sysoev.ru }
237353Sigor@sysoev.ru 
237453Sigor@sysoev.ru 
237553Sigor@sysoev.ru static nxt_int_t
2376115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2377115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
237853Sigor@sysoev.ru {
237953Sigor@sysoev.ru     nxt_int_t  ret;
238053Sigor@sysoev.ru 
2381313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2382313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2383313Sigor@sysoev.ru         return ret;
2384313Sigor@sysoev.ru     }
2385313Sigor@sysoev.ru 
2386139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
238753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
238853Sigor@sysoev.ru         return ret;
238953Sigor@sysoev.ru     }
239053Sigor@sysoev.ru 
2391139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
239253Sigor@sysoev.ru }
239353Sigor@sysoev.ru 
239453Sigor@sysoev.ru 
239553Sigor@sysoev.ru static nxt_int_t
2396154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2397154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
239853Sigor@sysoev.ru     nxt_work_handler_t handler)
239953Sigor@sysoev.ru {
2400153Sigor@sysoev.ru     nxt_joint_job_t          *job;
240153Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2402155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
240353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
240453Sigor@sysoev.ru 
240553Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
240653Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
240753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
240853Sigor@sysoev.ru     {
2409154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2410153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2411139Sigor@sysoev.ru             return NXT_ERROR;
2412139Sigor@sysoev.ru         }
2413139Sigor@sysoev.ru 
2414154Sigor@sysoev.ru         job->work.next = recf->jobs;
2415154Sigor@sysoev.ru         recf->jobs = &job->work;
2416154Sigor@sysoev.ru 
2417153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2418153Sigor@sysoev.ru         job->work.handler = handler;
2419153Sigor@sysoev.ru         job->work.task = &job->task;
2420153Sigor@sysoev.ru         job->work.obj = job;
2421153Sigor@sysoev.ru         job->tmcf = tmcf;
242253Sigor@sysoev.ru 
2423154Sigor@sysoev.ru         tmcf->count++;
2424154Sigor@sysoev.ru 
2425591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2426154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
242753Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
242853Sigor@sysoev.ru             return NXT_ERROR;
242953Sigor@sysoev.ru         }
243053Sigor@sysoev.ru 
2431153Sigor@sysoev.ru         job->work.data = joint;
243253Sigor@sysoev.ru 
243353Sigor@sysoev.ru         joint->count = 1;
2434155Sigor@sysoev.ru 
2435155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2436155Sigor@sysoev.ru         skcf->count++;
2437155Sigor@sysoev.ru         joint->socket_conf = skcf;
2438155Sigor@sysoev.ru 
243988Smax.romanov@nginx.com         joint->engine = recf->engine;
244053Sigor@sysoev.ru     }
244153Sigor@sysoev.ru 
244220Sigor@sysoev.ru     return NXT_OK;
244320Sigor@sysoev.ru }
244420Sigor@sysoev.ru 
244520Sigor@sysoev.ru 
244620Sigor@sysoev.ru static nxt_int_t
2447313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2448313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2449313Sigor@sysoev.ru {
2450313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2451313Sigor@sysoev.ru 
2452313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2453313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2454313Sigor@sysoev.ru         return NXT_ERROR;
2455313Sigor@sysoev.ru     }
2456313Sigor@sysoev.ru 
2457313Sigor@sysoev.ru     job->work.next = recf->jobs;
2458313Sigor@sysoev.ru     recf->jobs = &job->work;
2459313Sigor@sysoev.ru 
2460313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2461313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2462313Sigor@sysoev.ru     job->work.task = &job->task;
2463313Sigor@sysoev.ru     job->work.obj = NULL;
2464313Sigor@sysoev.ru     job->work.data = NULL;
2465313Sigor@sysoev.ru     job->tmcf = NULL;
2466313Sigor@sysoev.ru 
2467313Sigor@sysoev.ru     return NXT_OK;
2468313Sigor@sysoev.ru }
2469313Sigor@sysoev.ru 
2470313Sigor@sysoev.ru 
2471313Sigor@sysoev.ru static nxt_int_t
2472139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2473139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
247420Sigor@sysoev.ru {
2475153Sigor@sysoev.ru     nxt_joint_job_t   *job;
247653Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
247720Sigor@sysoev.ru 
247853Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
247953Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
248053Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
248153Sigor@sysoev.ru     {
2482154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2483153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2484139Sigor@sysoev.ru             return NXT_ERROR;
2485139Sigor@sysoev.ru         }
2486139Sigor@sysoev.ru 
2487154Sigor@sysoev.ru         job->work.next = recf->jobs;
2488154Sigor@sysoev.ru         recf->jobs = &job->work;
2489154Sigor@sysoev.ru 
2490153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2491153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2492153Sigor@sysoev.ru         job->work.task = &job->task;
2493153Sigor@sysoev.ru         job->work.obj = job;
2494153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2495153Sigor@sysoev.ru         job->tmcf = tmcf;
2496154Sigor@sysoev.ru 
2497154Sigor@sysoev.ru         tmcf->count++;
249820Sigor@sysoev.ru     }
249920Sigor@sysoev.ru 
250053Sigor@sysoev.ru     return NXT_OK;
250153Sigor@sysoev.ru }
250220Sigor@sysoev.ru 
250320Sigor@sysoev.ru 
250453Sigor@sysoev.ru static nxt_int_t
250553Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
250653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
250753Sigor@sysoev.ru {
250853Sigor@sysoev.ru     nxt_int_t                 ret;
250953Sigor@sysoev.ru     nxt_uint_t                i, threads;
251053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
251120Sigor@sysoev.ru 
251253Sigor@sysoev.ru     recf = tmcf->engines->elts;
2513591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
251420Sigor@sysoev.ru 
251553Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
251653Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
251753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
251853Sigor@sysoev.ru             return ret;
251953Sigor@sysoev.ru         }
252020Sigor@sysoev.ru     }
252120Sigor@sysoev.ru 
252220Sigor@sysoev.ru     return NXT_OK;
252320Sigor@sysoev.ru }
252453Sigor@sysoev.ru 
252553Sigor@sysoev.ru 
252653Sigor@sysoev.ru static nxt_int_t
252753Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
252853Sigor@sysoev.ru     nxt_event_engine_t *engine)
252953Sigor@sysoev.ru {
253053Sigor@sysoev.ru     nxt_int_t            ret;
253153Sigor@sysoev.ru     nxt_thread_link_t    *link;
253253Sigor@sysoev.ru     nxt_thread_handle_t  handle;
253353Sigor@sysoev.ru 
253453Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
253553Sigor@sysoev.ru 
253653Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
253753Sigor@sysoev.ru         return NXT_ERROR;
253853Sigor@sysoev.ru     }
253953Sigor@sysoev.ru 
254053Sigor@sysoev.ru     link->start = nxt_router_thread_start;
254153Sigor@sysoev.ru     link->engine = engine;
254253Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
254353Sigor@sysoev.ru     link->work.task = task;
254453Sigor@sysoev.ru     link->work.data = link;
254553Sigor@sysoev.ru 
254653Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
254753Sigor@sysoev.ru 
254853Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
254953Sigor@sysoev.ru 
255053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
255153Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
255253Sigor@sysoev.ru     }
255353Sigor@sysoev.ru 
255453Sigor@sysoev.ru     return ret;
255553Sigor@sysoev.ru }
255653Sigor@sysoev.ru 
255753Sigor@sysoev.ru 
255853Sigor@sysoev.ru static void
2559343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2560343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2561133Sigor@sysoev.ru {
2562507Smax.romanov@nginx.com     nxt_app_t  *app;
2563141Smax.romanov@nginx.com 
2564141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2565133Sigor@sysoev.ru 
2566753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2567343Smax.romanov@nginx.com 
2568141Smax.romanov@nginx.com     } nxt_queue_loop;
2569133Sigor@sysoev.ru 
2570133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2571133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2572133Sigor@sysoev.ru }
2573133Sigor@sysoev.ru 
2574133Sigor@sysoev.ru 
2575133Sigor@sysoev.ru static void
2576315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
257753Sigor@sysoev.ru {
257853Sigor@sysoev.ru     nxt_uint_t                n;
2579315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
258053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
258153Sigor@sysoev.ru 
258253Sigor@sysoev.ru     recf = tmcf->engines->elts;
258353Sigor@sysoev.ru 
258453Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2585315Sigor@sysoev.ru         engine = recf->engine;
2586315Sigor@sysoev.ru 
2587315Sigor@sysoev.ru         switch (recf->action) {
2588315Sigor@sysoev.ru 
2589315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2590315Sigor@sysoev.ru             break;
2591315Sigor@sysoev.ru 
2592315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2593315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2594315Sigor@sysoev.ru             break;
2595315Sigor@sysoev.ru 
2596315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2597315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2598315Sigor@sysoev.ru             break;
2599315Sigor@sysoev.ru         }
2600315Sigor@sysoev.ru 
2601316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2602316Sigor@sysoev.ru 
260353Sigor@sysoev.ru         recf++;
260453Sigor@sysoev.ru     }
260553Sigor@sysoev.ru }
260653Sigor@sysoev.ru 
260753Sigor@sysoev.ru 
260853Sigor@sysoev.ru static void
2609315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
261053Sigor@sysoev.ru {
2611154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2612154Sigor@sysoev.ru 
2613315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2614154Sigor@sysoev.ru         next = work->next;
2615154Sigor@sysoev.ru         work->next = NULL;
2616154Sigor@sysoev.ru 
2617315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
261853Sigor@sysoev.ru     }
261953Sigor@sysoev.ru }
262053Sigor@sysoev.ru 
262153Sigor@sysoev.ru 
2622320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2623616Smax.romanov@nginx.com     .rpc_error = nxt_port_rpc_handler,
2624616Smax.romanov@nginx.com     .mmap      = nxt_port_mmap_handler,
2625616Smax.romanov@nginx.com     .data      = nxt_port_rpc_handler,
262688Smax.romanov@nginx.com };
262788Smax.romanov@nginx.com 
262888Smax.romanov@nginx.com 
262988Smax.romanov@nginx.com static void
263053Sigor@sysoev.ru nxt_router_thread_start(void *data)
263153Sigor@sysoev.ru {
2632141Smax.romanov@nginx.com     nxt_int_t           ret;
2633141Smax.romanov@nginx.com     nxt_port_t          *port;
263488Smax.romanov@nginx.com     nxt_task_t          *task;
263553Sigor@sysoev.ru     nxt_thread_t        *thread;
263653Sigor@sysoev.ru     nxt_thread_link_t   *link;
263753Sigor@sysoev.ru     nxt_event_engine_t  *engine;
263853Sigor@sysoev.ru 
263953Sigor@sysoev.ru     link = data;
264053Sigor@sysoev.ru     engine = link->engine;
264188Smax.romanov@nginx.com     task = &engine->task;
264253Sigor@sysoev.ru 
264353Sigor@sysoev.ru     thread = nxt_thread();
264453Sigor@sysoev.ru 
2645165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2646165Smax.romanov@nginx.com 
264753Sigor@sysoev.ru     /* STUB */
264853Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
264953Sigor@sysoev.ru 
265053Sigor@sysoev.ru     engine->task.thread = thread;
265153Sigor@sysoev.ru     engine->task.log = thread->log;
265253Sigor@sysoev.ru     thread->engine = engine;
265363Sigor@sysoev.ru     thread->task = &engine->task;
2654326Svbart@nginx.com #if 0
265553Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2656326Svbart@nginx.com #endif
265753Sigor@sysoev.ru 
265863Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2659337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2660337Sigor@sysoev.ru         return;
2661337Sigor@sysoev.ru     }
266253Sigor@sysoev.ru 
2663197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2664197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2665141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2666141Smax.romanov@nginx.com         return;
2667141Smax.romanov@nginx.com     }
2668141Smax.romanov@nginx.com 
2669141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2670141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2671343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2672141Smax.romanov@nginx.com         return;
2673141Smax.romanov@nginx.com     }
2674141Smax.romanov@nginx.com 
2675141Smax.romanov@nginx.com     engine->port = port;
2676141Smax.romanov@nginx.com 
2677320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2678141Smax.romanov@nginx.com 
267953Sigor@sysoev.ru     nxt_event_engine_start(engine);
268053Sigor@sysoev.ru }
268153Sigor@sysoev.ru 
268253Sigor@sysoev.ru 
268353Sigor@sysoev.ru static void
268453Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
268553Sigor@sysoev.ru {
2686153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2687359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2688359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
268953Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2690359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
269153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
269253Sigor@sysoev.ru 
2693153Sigor@sysoev.ru     job = obj;
269453Sigor@sysoev.ru     joint = data;
269553Sigor@sysoev.ru 
2696159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2697159Sigor@sysoev.ru 
2698359Sigor@sysoev.ru     skcf = joint->socket_conf;
2699359Sigor@sysoev.ru     ls = skcf->listen;
2700359Sigor@sysoev.ru 
2701359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2702359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2703359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
270453Sigor@sysoev.ru         return;
270553Sigor@sysoev.ru     }
270653Sigor@sysoev.ru 
2707359Sigor@sysoev.ru     lev->socket.data = joint;
2708359Sigor@sysoev.ru 
2709359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2710359Sigor@sysoev.ru 
2711359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2712359Sigor@sysoev.ru     ls->count++;
2713359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2714139Sigor@sysoev.ru 
2715153Sigor@sysoev.ru     job->work.next = NULL;
2716153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2717153Sigor@sysoev.ru 
2718153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
271953Sigor@sysoev.ru }
272053Sigor@sysoev.ru 
272153Sigor@sysoev.ru 
272253Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
272353Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
272453Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
272553Sigor@sysoev.ru {
2726115Sigor@sysoev.ru     nxt_socket_t        fd;
2727115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2728359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2729359Sigor@sysoev.ru 
2730359Sigor@sysoev.ru     fd = skcf->listen->socket;
273153Sigor@sysoev.ru 
2732115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2733115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2734115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
273553Sigor@sysoev.ru     {
2736359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2737359Sigor@sysoev.ru 
2738359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2739359Sigor@sysoev.ru             return lev;
274053Sigor@sysoev.ru         }
274153Sigor@sysoev.ru     }
274253Sigor@sysoev.ru 
274353Sigor@sysoev.ru     return NULL;
274453Sigor@sysoev.ru }
274553Sigor@sysoev.ru 
274653Sigor@sysoev.ru 
274753Sigor@sysoev.ru static void
274853Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
274953Sigor@sysoev.ru {
2750153Sigor@sysoev.ru     nxt_joint_job_t          *job;
275153Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2752359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
275353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
275453Sigor@sysoev.ru 
2755153Sigor@sysoev.ru     job = obj;
275653Sigor@sysoev.ru     joint = data;
275753Sigor@sysoev.ru 
2758139Sigor@sysoev.ru     engine = task->thread->engine;
2759139Sigor@sysoev.ru 
2760159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2761159Sigor@sysoev.ru 
2762359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2763359Sigor@sysoev.ru                                   joint->socket_conf);
2764359Sigor@sysoev.ru 
2765359Sigor@sysoev.ru     old = lev->socket.data;
2766359Sigor@sysoev.ru     lev->socket.data = joint;
2767359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
276853Sigor@sysoev.ru 
2769153Sigor@sysoev.ru     job->work.next = NULL;
2770153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2771153Sigor@sysoev.ru 
2772153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2773139Sigor@sysoev.ru 
2774181Smax.romanov@nginx.com     /*
2775181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2776181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2777181Smax.romanov@nginx.com      */
2778181Smax.romanov@nginx.com 
2779181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
278053Sigor@sysoev.ru }
278153Sigor@sysoev.ru 
278253Sigor@sysoev.ru 
278353Sigor@sysoev.ru static void
278453Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
278553Sigor@sysoev.ru {
2786153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2787153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2788359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2789153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2790153Sigor@sysoev.ru 
2791153Sigor@sysoev.ru     job = obj;
279253Sigor@sysoev.ru     skcf = data;
279353Sigor@sysoev.ru 
2794139Sigor@sysoev.ru     engine = task->thread->engine;
2795139Sigor@sysoev.ru 
2796359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2797359Sigor@sysoev.ru 
2798359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
279953Sigor@sysoev.ru 
2800163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2801359Sigor@sysoev.ru               lev->socket.fd);
2802359Sigor@sysoev.ru 
2803359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2804359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2805359Sigor@sysoev.ru 
2806359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2807139Sigor@sysoev.ru 
2808153Sigor@sysoev.ru     job->work.next = NULL;
2809153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2810153Sigor@sysoev.ru 
2811153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
281253Sigor@sysoev.ru }
281353Sigor@sysoev.ru 
281453Sigor@sysoev.ru 
281553Sigor@sysoev.ru static void
2816313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2817313Sigor@sysoev.ru {
2818313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2819313Sigor@sysoev.ru 
2820313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2821313Sigor@sysoev.ru 
2822313Sigor@sysoev.ru     engine = task->thread->engine;
2823313Sigor@sysoev.ru 
2824313Sigor@sysoev.ru     engine->shutdown = 1;
2825313Sigor@sysoev.ru 
2826313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2827313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2828313Sigor@sysoev.ru     }
2829313Sigor@sysoev.ru }
2830313Sigor@sysoev.ru 
2831313Sigor@sysoev.ru 
2832313Sigor@sysoev.ru static void
283353Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
283453Sigor@sysoev.ru {
283553Sigor@sysoev.ru     nxt_timer_t              *timer;
2836359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
283753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
283853Sigor@sysoev.ru 
283953Sigor@sysoev.ru     timer = obj;
2840359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
284153Sigor@sysoev.ru 
2842163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2843359Sigor@sysoev.ru               lev->socket.fd);
2844359Sigor@sysoev.ru 
2845359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2846359Sigor@sysoev.ru 
2847683Sigor@sysoev.ru     joint = lev->socket.data;
2848683Sigor@sysoev.ru     lev->socket.data = NULL;
2849683Sigor@sysoev.ru 
2850359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2851123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2852123Smax.romanov@nginx.com 
2853359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2854359Sigor@sysoev.ru 
2855683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
285653Sigor@sysoev.ru }
285753Sigor@sysoev.ru 
285853Sigor@sysoev.ru 
285953Sigor@sysoev.ru static void
2860359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
286153Sigor@sysoev.ru {
2862359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
286353Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
286453Sigor@sysoev.ru 
2865359Sigor@sysoev.ru     ls = skcf->listen;
2866118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
286753Sigor@sysoev.ru 
286853Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
286953Sigor@sysoev.ru 
2870359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2871359Sigor@sysoev.ru               task->thread->engine, ls->count);
2872359Sigor@sysoev.ru 
2873359Sigor@sysoev.ru     if (--ls->count != 0) {
2874359Sigor@sysoev.ru         ls = NULL;
287553Sigor@sysoev.ru     }
287653Sigor@sysoev.ru 
287753Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
287853Sigor@sysoev.ru 
2879359Sigor@sysoev.ru     if (ls != NULL) {
2880359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
2881359Sigor@sysoev.ru         nxt_free(ls);
288253Sigor@sysoev.ru     }
288353Sigor@sysoev.ru }
288453Sigor@sysoev.ru 
288553Sigor@sysoev.ru 
2886683Sigor@sysoev.ru void
2887683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
2888683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
2889683Sigor@sysoev.ru {
2890683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2891683Sigor@sysoev.ru 
2892683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
2893683Sigor@sysoev.ru 
2894683Sigor@sysoev.ru     if (--lev->count == 0) {
2895683Sigor@sysoev.ru         nxt_free(lev);
2896683Sigor@sysoev.ru     }
2897683Sigor@sysoev.ru 
2898683Sigor@sysoev.ru     if (joint != NULL) {
2899683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
2900683Sigor@sysoev.ru     }
2901683Sigor@sysoev.ru 
2902683Sigor@sysoev.ru     engine = task->thread->engine;
2903683Sigor@sysoev.ru 
2904683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
2905683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2906683Sigor@sysoev.ru     }
2907683Sigor@sysoev.ru }
2908683Sigor@sysoev.ru 
2909683Sigor@sysoev.ru 
2910683Sigor@sysoev.ru void
291153Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
291253Sigor@sysoev.ru {
291353Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
291453Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
291553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
291653Sigor@sysoev.ru 
2917163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
291853Sigor@sysoev.ru 
291953Sigor@sysoev.ru     if (--joint->count != 0) {
292053Sigor@sysoev.ru         return;
292153Sigor@sysoev.ru     }
292253Sigor@sysoev.ru 
292353Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
292453Sigor@sysoev.ru 
2925530Sigor@sysoev.ru     /*
2926530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
2927530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
2928530Sigor@sysoev.ru      * be already destroyed by another thread.
2929530Sigor@sysoev.ru      */
293053Sigor@sysoev.ru     skcf = joint->socket_conf;
293153Sigor@sysoev.ru     rtcf = skcf->router_conf;
293253Sigor@sysoev.ru     lock = &rtcf->router->lock;
293353Sigor@sysoev.ru 
293453Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
293553Sigor@sysoev.ru 
2936163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2937163Smax.romanov@nginx.com               rtcf, rtcf->count);
2938163Smax.romanov@nginx.com 
293953Sigor@sysoev.ru     if (--skcf->count != 0) {
2940952Sigor@sysoev.ru         skcf = NULL;
294153Sigor@sysoev.ru         rtcf = NULL;
294253Sigor@sysoev.ru 
294353Sigor@sysoev.ru     } else {
294453Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
294553Sigor@sysoev.ru 
294653Sigor@sysoev.ru         if (--rtcf->count != 0) {
294753Sigor@sysoev.ru             rtcf = NULL;
294853Sigor@sysoev.ru         }
294953Sigor@sysoev.ru     }
295053Sigor@sysoev.ru 
295153Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
295253Sigor@sysoev.ru 
2953952Sigor@sysoev.ru     if (skcf != NULL) {
2954964Sigor@sysoev.ru         if (skcf->pass != NULL) {
2955964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
2956964Sigor@sysoev.ru         }
2957964Sigor@sysoev.ru 
2958952Sigor@sysoev.ru #if (NXT_TLS)
2959952Sigor@sysoev.ru         if (skcf->tls != NULL) {
2960952Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
2961952Sigor@sysoev.ru         }
2962952Sigor@sysoev.ru #endif
2963952Sigor@sysoev.ru     }
2964952Sigor@sysoev.ru 
2965141Smax.romanov@nginx.com     /* TODO remove engine->port */
2966141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2967141Smax.romanov@nginx.com 
296853Sigor@sysoev.ru     if (rtcf != NULL) {
2969115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2970131Smax.romanov@nginx.com 
2971964Sigor@sysoev.ru         nxt_http_routes_cleanup(task, rtcf->routes);
2972964Sigor@sysoev.ru 
2973630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
2974630Svbart@nginx.com 
2975131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2976131Smax.romanov@nginx.com 
297765Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
297853Sigor@sysoev.ru     }
297953Sigor@sysoev.ru }
298053Sigor@sysoev.ru 
298153Sigor@sysoev.ru 
298253Sigor@sysoev.ru static void
2983630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
2984630Svbart@nginx.com     nxt_router_access_log_t *access_log)
2985630Svbart@nginx.com {
2986630Svbart@nginx.com     size_t     size;
2987630Svbart@nginx.com     u_char     *buf, *p;
2988630Svbart@nginx.com     nxt_off_t  bytes;
2989630Svbart@nginx.com 
2990630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
2991630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
2992630Svbart@nginx.com         nxt_router_access_log_date,
2993630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
2994703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
2995630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
2996630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
2997630Svbart@nginx.com     };
2998630Svbart@nginx.com 
2999630Svbart@nginx.com     size = r->remote->address_length
3000630Svbart@nginx.com            + 6                  /* ' - - [' */
3001630Svbart@nginx.com            + date_cache.size
3002630Svbart@nginx.com            + 3                  /* '] "' */
3003630Svbart@nginx.com            + r->method->length
3004630Svbart@nginx.com            + 1                  /* space */
3005630Svbart@nginx.com            + r->target.length
3006630Svbart@nginx.com            + 1                  /* space */
3007630Svbart@nginx.com            + r->version.length
3008630Svbart@nginx.com            + 2                  /* '" ' */
3009630Svbart@nginx.com            + 3                  /* status */
3010630Svbart@nginx.com            + 1                  /* space */
3011630Svbart@nginx.com            + NXT_OFF_T_LEN
3012630Svbart@nginx.com            + 2                  /* ' "' */
3013630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3014630Svbart@nginx.com            + 3                  /* '" "' */
3015630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3016630Svbart@nginx.com            + 2                  /* '"\n' */
3017630Svbart@nginx.com     ;
3018630Svbart@nginx.com 
3019630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3020630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3021630Svbart@nginx.com         return;
3022630Svbart@nginx.com     }
3023630Svbart@nginx.com 
3024630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3025630Svbart@nginx.com                    r->remote->address_length);
3026630Svbart@nginx.com 
3027630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3028630Svbart@nginx.com 
3029630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3030630Svbart@nginx.com 
3031630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3032630Svbart@nginx.com 
3033630Svbart@nginx.com     if (r->method->length != 0) {
3034630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3035630Svbart@nginx.com 
3036630Svbart@nginx.com         if (r->target.length != 0) {
3037630Svbart@nginx.com             *p++ = ' ';
3038630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3039630Svbart@nginx.com 
3040630Svbart@nginx.com             if (r->version.length != 0) {
3041630Svbart@nginx.com                 *p++ = ' ';
3042630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3043630Svbart@nginx.com             }
3044630Svbart@nginx.com         }
3045630Svbart@nginx.com 
3046630Svbart@nginx.com     } else {
3047630Svbart@nginx.com         *p++ = '-';
3048630Svbart@nginx.com     }
3049630Svbart@nginx.com 
3050630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3051630Svbart@nginx.com 
3052630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3053630Svbart@nginx.com 
3054630Svbart@nginx.com     *p++ = ' ';
3055630Svbart@nginx.com 
3056630Svbart@nginx.com     bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto);
3057630Svbart@nginx.com 
3058630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3059630Svbart@nginx.com 
3060630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3061630Svbart@nginx.com 
3062630Svbart@nginx.com     if (r->referer != NULL) {
3063630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3064630Svbart@nginx.com 
3065630Svbart@nginx.com     } else {
3066630Svbart@nginx.com         *p++ = '-';
3067630Svbart@nginx.com     }
3068630Svbart@nginx.com 
3069630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3070630Svbart@nginx.com 
3071630Svbart@nginx.com     if (r->user_agent != NULL) {
3072630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3073630Svbart@nginx.com 
3074630Svbart@nginx.com     } else {
3075630Svbart@nginx.com         *p++ = '-';
3076630Svbart@nginx.com     }
3077630Svbart@nginx.com 
3078630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3079630Svbart@nginx.com 
3080630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3081630Svbart@nginx.com }
3082630Svbart@nginx.com 
3083630Svbart@nginx.com 
3084630Svbart@nginx.com static u_char *
3085630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3086630Svbart@nginx.com     size_t size, const char *format)
3087630Svbart@nginx.com {
3088630Svbart@nginx.com     u_char  sign;
3089630Svbart@nginx.com     time_t  gmtoff;
3090630Svbart@nginx.com 
3091630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3092630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3093630Svbart@nginx.com 
3094630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3095630Svbart@nginx.com 
3096630Svbart@nginx.com     if (gmtoff < 0) {
3097630Svbart@nginx.com         gmtoff = -gmtoff;
3098630Svbart@nginx.com         sign = '-';
3099630Svbart@nginx.com 
3100630Svbart@nginx.com     } else {
3101630Svbart@nginx.com         sign = '+';
3102630Svbart@nginx.com     }
3103630Svbart@nginx.com 
3104630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3105630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3106630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3107630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3108630Svbart@nginx.com }
3109630Svbart@nginx.com 
3110630Svbart@nginx.com 
3111630Svbart@nginx.com static void
3112630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3113630Svbart@nginx.com {
3114630Svbart@nginx.com     uint32_t                 stream;
3115648Svbart@nginx.com     nxt_int_t                ret;
3116630Svbart@nginx.com     nxt_buf_t                *b;
3117630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3118630Svbart@nginx.com     nxt_runtime_t            *rt;
3119630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3120630Svbart@nginx.com 
3121630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3122630Svbart@nginx.com 
3123630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3124630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3125630Svbart@nginx.com         goto fail;
3126630Svbart@nginx.com     }
3127630Svbart@nginx.com 
3128630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3129630Svbart@nginx.com     *b->mem.free++ = '\0';
3130630Svbart@nginx.com 
3131630Svbart@nginx.com     rt = task->thread->runtime;
3132630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3133630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3134630Svbart@nginx.com 
3135630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3136630Svbart@nginx.com                                            nxt_router_access_log_ready,
3137630Svbart@nginx.com                                            nxt_router_access_log_error,
3138630Svbart@nginx.com                                            -1, tmcf);
3139630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3140630Svbart@nginx.com         goto fail;
3141630Svbart@nginx.com     }
3142630Svbart@nginx.com 
3143648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3144648Svbart@nginx.com                                 stream, router_port->id, b);
3145648Svbart@nginx.com 
3146648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3147648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3148648Svbart@nginx.com         goto fail;
3149648Svbart@nginx.com     }
3150630Svbart@nginx.com 
3151630Svbart@nginx.com     return;
3152630Svbart@nginx.com 
3153630Svbart@nginx.com fail:
3154630Svbart@nginx.com 
3155630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3156630Svbart@nginx.com }
3157630Svbart@nginx.com 
3158630Svbart@nginx.com 
3159630Svbart@nginx.com static void
3160630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3161630Svbart@nginx.com     void *data)
3162630Svbart@nginx.com {
3163630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3164630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3165630Svbart@nginx.com 
3166630Svbart@nginx.com     tmcf = data;
3167630Svbart@nginx.com 
3168630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3169630Svbart@nginx.com 
3170630Svbart@nginx.com     access_log->fd = msg->fd;
3171630Svbart@nginx.com 
3172630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3173630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3174630Svbart@nginx.com }
3175630Svbart@nginx.com 
3176630Svbart@nginx.com 
3177630Svbart@nginx.com static void
3178630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3179630Svbart@nginx.com     void *data)
3180630Svbart@nginx.com {
3181630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3182630Svbart@nginx.com 
3183630Svbart@nginx.com     tmcf = data;
3184630Svbart@nginx.com 
3185630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3186630Svbart@nginx.com }
3187630Svbart@nginx.com 
3188630Svbart@nginx.com 
3189630Svbart@nginx.com static void
3190630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3191630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3192630Svbart@nginx.com {
3193630Svbart@nginx.com     if (access_log == NULL) {
3194630Svbart@nginx.com         return;
3195630Svbart@nginx.com     }
3196630Svbart@nginx.com 
3197630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3198630Svbart@nginx.com 
3199630Svbart@nginx.com     if (--access_log->count != 0) {
3200630Svbart@nginx.com         access_log = NULL;
3201630Svbart@nginx.com     }
3202630Svbart@nginx.com 
3203630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3204630Svbart@nginx.com 
3205630Svbart@nginx.com     if (access_log != NULL) {
3206630Svbart@nginx.com 
3207630Svbart@nginx.com         if (access_log->fd != -1) {
3208630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3209630Svbart@nginx.com         }
3210630Svbart@nginx.com 
3211630Svbart@nginx.com         nxt_free(access_log);
3212630Svbart@nginx.com     }
3213630Svbart@nginx.com }
3214630Svbart@nginx.com 
3215630Svbart@nginx.com 
3216631Svbart@nginx.com typedef struct {
3217631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3218631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3219631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3220631Svbart@nginx.com 
3221631Svbart@nginx.com 
3222631Svbart@nginx.com void
3223631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3224631Svbart@nginx.com {
3225631Svbart@nginx.com     nxt_mp_t                        *mp;
3226631Svbart@nginx.com     uint32_t                        stream;
3227631Svbart@nginx.com     nxt_int_t                       ret;
3228631Svbart@nginx.com     nxt_buf_t                       *b;
3229631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3230631Svbart@nginx.com     nxt_runtime_t                   *rt;
3231631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3232631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3233631Svbart@nginx.com 
3234631Svbart@nginx.com     access_log = nxt_router->access_log;
3235631Svbart@nginx.com 
3236631Svbart@nginx.com     if (access_log == NULL) {
3237631Svbart@nginx.com         return;
3238631Svbart@nginx.com     }
3239631Svbart@nginx.com 
3240631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3241631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3242631Svbart@nginx.com         return;
3243631Svbart@nginx.com     }
3244631Svbart@nginx.com 
3245631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3246631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3247631Svbart@nginx.com         goto fail;
3248631Svbart@nginx.com     }
3249631Svbart@nginx.com 
3250631Svbart@nginx.com     reopen->mem_pool = mp;
3251631Svbart@nginx.com     reopen->access_log = access_log;
3252631Svbart@nginx.com 
3253631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3254631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3255631Svbart@nginx.com         goto fail;
3256631Svbart@nginx.com     }
3257631Svbart@nginx.com 
3258651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3259651Svbart@nginx.com 
3260631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3261631Svbart@nginx.com     *b->mem.free++ = '\0';
3262631Svbart@nginx.com 
3263631Svbart@nginx.com     rt = task->thread->runtime;
3264631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3265631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3266631Svbart@nginx.com 
3267631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3268631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3269631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3270631Svbart@nginx.com                                            -1, reopen);
3271631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3272631Svbart@nginx.com         goto fail;
3273631Svbart@nginx.com     }
3274631Svbart@nginx.com 
3275631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3276631Svbart@nginx.com                                 stream, router_port->id, b);
3277631Svbart@nginx.com 
3278631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3279631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3280631Svbart@nginx.com         goto fail;
3281631Svbart@nginx.com     }
3282631Svbart@nginx.com 
3283651Svbart@nginx.com     nxt_mp_retain(mp);
3284651Svbart@nginx.com 
3285631Svbart@nginx.com     return;
3286631Svbart@nginx.com 
3287631Svbart@nginx.com fail:
3288631Svbart@nginx.com 
3289631Svbart@nginx.com     nxt_mp_destroy(mp);
3290631Svbart@nginx.com }
3291631Svbart@nginx.com 
3292631Svbart@nginx.com 
3293631Svbart@nginx.com static void
3294651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3295651Svbart@nginx.com {
3296651Svbart@nginx.com     nxt_mp_t   *mp;
3297651Svbart@nginx.com     nxt_buf_t  *b;
3298651Svbart@nginx.com 
3299651Svbart@nginx.com     b = obj;
3300651Svbart@nginx.com     mp = b->data;
3301651Svbart@nginx.com 
3302651Svbart@nginx.com     nxt_mp_release(mp);
3303651Svbart@nginx.com }
3304651Svbart@nginx.com 
3305651Svbart@nginx.com 
3306651Svbart@nginx.com static void
3307631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3308631Svbart@nginx.com     void *data)
3309631Svbart@nginx.com {
3310631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3311631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3312631Svbart@nginx.com 
3313631Svbart@nginx.com     reopen = data;
3314631Svbart@nginx.com 
3315631Svbart@nginx.com     access_log = reopen->access_log;
3316631Svbart@nginx.com 
3317631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3318631Svbart@nginx.com 
3319631Svbart@nginx.com         if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) {
3320631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3321631Svbart@nginx.com                       msg->fd, access_log->fd, nxt_errno);
3322631Svbart@nginx.com         }
3323631Svbart@nginx.com     }
3324631Svbart@nginx.com 
3325631Svbart@nginx.com     nxt_fd_close(msg->fd);
3326651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3327631Svbart@nginx.com }
3328631Svbart@nginx.com 
3329631Svbart@nginx.com 
3330631Svbart@nginx.com static void
3331631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3332631Svbart@nginx.com     void *data)
3333631Svbart@nginx.com {
3334631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3335631Svbart@nginx.com 
3336631Svbart@nginx.com     reopen = data;
3337631Svbart@nginx.com 
3338651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3339631Svbart@nginx.com }
3340631Svbart@nginx.com 
3341631Svbart@nginx.com 
3342630Svbart@nginx.com static void
334353Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
334453Sigor@sysoev.ru {
3345141Smax.romanov@nginx.com     nxt_port_t           *port;
334653Sigor@sysoev.ru     nxt_thread_link_t    *link;
334753Sigor@sysoev.ru     nxt_event_engine_t   *engine;
334853Sigor@sysoev.ru     nxt_thread_handle_t  handle;
334953Sigor@sysoev.ru 
335058Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
335153Sigor@sysoev.ru     link = data;
335253Sigor@sysoev.ru 
335353Sigor@sysoev.ru     nxt_thread_wait(handle);
335453Sigor@sysoev.ru 
335553Sigor@sysoev.ru     engine = link->engine;
335653Sigor@sysoev.ru 
335753Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
335853Sigor@sysoev.ru 
3359141Smax.romanov@nginx.com     port = engine->port;
3360141Smax.romanov@nginx.com 
3361141Smax.romanov@nginx.com     // TODO notify all apps
3362141Smax.romanov@nginx.com 
3363343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3364163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3365343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3366163Smax.romanov@nginx.com 
3367163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
336863Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
336953Sigor@sysoev.ru 
337053Sigor@sysoev.ru     nxt_event_engine_free(engine);
337153Sigor@sysoev.ru 
337253Sigor@sysoev.ru     nxt_free(link);
337353Sigor@sysoev.ru }
337453Sigor@sysoev.ru 
337553Sigor@sysoev.ru 
337653Sigor@sysoev.ru static void
3377318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3378318Smax.romanov@nginx.com     void *data)
337988Smax.romanov@nginx.com {
338088Smax.romanov@nginx.com     size_t               dump_size;
3381431Sigor@sysoev.ru     nxt_int_t            ret;
3382608Sigor@sysoev.ru     nxt_buf_t            *b;
3383431Sigor@sysoev.ru     nxt_http_request_t   *r;
338488Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3385431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
3386743Smax.romanov@nginx.com     nxt_unit_response_t  *resp;
338788Smax.romanov@nginx.com 
338888Smax.romanov@nginx.com     b = msg->buf;
3389318Smax.romanov@nginx.com     rc = data;
339088Smax.romanov@nginx.com 
339188Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
339288Smax.romanov@nginx.com 
339388Smax.romanov@nginx.com     if (dump_size > 300) {
339488Smax.romanov@nginx.com         dump_size = 300;
339588Smax.romanov@nginx.com     }
339688Smax.romanov@nginx.com 
339788Smax.romanov@nginx.com     if (msg->size == 0) {
339888Smax.romanov@nginx.com         b = NULL;
339988Smax.romanov@nginx.com     }
340088Smax.romanov@nginx.com 
3401431Sigor@sysoev.ru     ar = rc->ap;
3402570Smax.romanov@nginx.com     if (nxt_slow_path(ar == NULL)) {
3403570Smax.romanov@nginx.com         return;
3404570Smax.romanov@nginx.com     }
3405425Smax.romanov@nginx.com 
3406608Sigor@sysoev.ru     if (ar->request->error) {
3407608Sigor@sysoev.ru         nxt_router_rc_unlink(task, rc);
3408608Sigor@sysoev.ru         return;
3409608Sigor@sysoev.ru     }
3410608Sigor@sysoev.ru 
341188Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
341288Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
341388Smax.romanov@nginx.com 
3414608Sigor@sysoev.ru         nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request));
3415167Smax.romanov@nginx.com 
3416343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3417425Smax.romanov@nginx.com 
3418425Smax.romanov@nginx.com     } else {
3419615Smax.romanov@nginx.com         if (rc->app != NULL && rc->app->timeout != 0) {
3420431Sigor@sysoev.ru             ar->timer.handler = nxt_router_app_timeout;
3421615Smax.romanov@nginx.com             ar->timer_data = rc;
3422431Sigor@sysoev.ru             nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout);
3423425Smax.romanov@nginx.com         }
342488Smax.romanov@nginx.com     }
342588Smax.romanov@nginx.com 
342688Smax.romanov@nginx.com     if (b == NULL) {
342788Smax.romanov@nginx.com         return;
342888Smax.romanov@nginx.com     }
342988Smax.romanov@nginx.com 
3430206Smax.romanov@nginx.com     if (msg->buf == b) {
3431206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3432206Smax.romanov@nginx.com         msg->buf = NULL;
3433206Smax.romanov@nginx.com     }
3434194Smax.romanov@nginx.com 
3435431Sigor@sysoev.ru     r = ar->request;
3436431Sigor@sysoev.ru 
3437431Sigor@sysoev.ru     if (r->header_sent) {
3438431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3439431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3440277Sigor@sysoev.ru 
344188Smax.romanov@nginx.com     } else {
3442743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3443743Smax.romanov@nginx.com 
3444743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3445743Smax.romanov@nginx.com             goto fail;
3446743Smax.romanov@nginx.com         }
3447743Smax.romanov@nginx.com 
3448743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3449743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3450743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3451743Smax.romanov@nginx.com             goto fail;
3452743Smax.romanov@nginx.com         }
3453743Smax.romanov@nginx.com 
3454743Smax.romanov@nginx.com         nxt_unit_field_t  *f;
3455743Smax.romanov@nginx.com         nxt_http_field_t  *field;
3456743Smax.romanov@nginx.com 
3457743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
3458743Smax.romanov@nginx.com             field = nxt_list_add(ar->resp_parser.fields);
3459743Smax.romanov@nginx.com 
3460743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3461743Smax.romanov@nginx.com                 goto fail;
3462743Smax.romanov@nginx.com             }
3463743Smax.romanov@nginx.com 
3464743Smax.romanov@nginx.com             field->hash = f->hash;
3465743Smax.romanov@nginx.com             field->skip = f->skip;
3466743Smax.romanov@nginx.com 
3467743Smax.romanov@nginx.com             field->name_length = f->name_length;
3468743Smax.romanov@nginx.com             field->value_length = f->value_length;
3469743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3470743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3471743Smax.romanov@nginx.com 
3472743Smax.romanov@nginx.com             nxt_debug(task, "header: %*s: %*s",
3473743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3474743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
3475743Smax.romanov@nginx.com         }
3476743Smax.romanov@nginx.com         r->status = resp->status;
3477743Smax.romanov@nginx.com 
3478743Smax.romanov@nginx.com /*
3479431Sigor@sysoev.ru         ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem);
3480431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_DONE)) {
3481431Sigor@sysoev.ru             goto fail;
3482431Sigor@sysoev.ru         }
3483743Smax.romanov@nginx.com */
3484431Sigor@sysoev.ru         r->resp.fields = ar->resp_parser.fields;
3485431Sigor@sysoev.ru 
3486431Sigor@sysoev.ru         ret = nxt_http_fields_process(r->resp.fields,
3487431Sigor@sysoev.ru                                       &nxt_response_fields_hash, r);
3488431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
3489431Sigor@sysoev.ru             goto fail;
3490431Sigor@sysoev.ru         }
3491431Sigor@sysoev.ru 
3492743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3493743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3494743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3495743Smax.romanov@nginx.com 
3496743Smax.romanov@nginx.com         } else {
3497743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3498743Smax.romanov@nginx.com         }
3499743Smax.romanov@nginx.com 
3500435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
3501435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3502435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3503507Smax.romanov@nginx.com 
3504520Smax.romanov@nginx.com             b = b->next;
3505520Smax.romanov@nginx.com         }
3506520Smax.romanov@nginx.com 
3507520Smax.romanov@nginx.com         if (b != NULL) {
3508431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3509431Sigor@sysoev.ru         }
3510431Sigor@sysoev.ru 
3511431Sigor@sysoev.ru         r->state = &nxt_http_request_send_state;
3512431Sigor@sysoev.ru 
3513431Sigor@sysoev.ru         nxt_http_request_header_send(task, r);
3514431Sigor@sysoev.ru     }
3515431Sigor@sysoev.ru 
3516431Sigor@sysoev.ru     return;
3517431Sigor@sysoev.ru 
3518431Sigor@sysoev.ru fail:
3519431Sigor@sysoev.ru 
3520615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3521615Smax.romanov@nginx.com 
3522431Sigor@sysoev.ru     nxt_router_rc_unlink(task, rc);
3523431Sigor@sysoev.ru }
3524431Sigor@sysoev.ru 
3525431Sigor@sysoev.ru 
3526431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3527431Sigor@sysoev.ru     nxt_aligned(64) =
3528431Sigor@sysoev.ru {
3529431Sigor@sysoev.ru     .ready_handler = nxt_http_request_send_body,
3530943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
3531431Sigor@sysoev.ru };
3532431Sigor@sysoev.ru 
3533431Sigor@sysoev.ru 
3534431Sigor@sysoev.ru static void
3535431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3536431Sigor@sysoev.ru {
3537431Sigor@sysoev.ru     nxt_buf_t           *out;
3538431Sigor@sysoev.ru     nxt_http_request_t  *r;
3539431Sigor@sysoev.ru 
3540431Sigor@sysoev.ru     r = obj;
3541431Sigor@sysoev.ru 
3542431Sigor@sysoev.ru     out = r->out;
3543431Sigor@sysoev.ru 
3544431Sigor@sysoev.ru     if (out != NULL) {
3545431Sigor@sysoev.ru         r->out = NULL;
3546431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
354788Smax.romanov@nginx.com     }
354888Smax.romanov@nginx.com }
354988Smax.romanov@nginx.com 
3550277Sigor@sysoev.ru 
3551318Smax.romanov@nginx.com static void
3552318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3553318Smax.romanov@nginx.com     void *data)
3554318Smax.romanov@nginx.com {
3555425Smax.romanov@nginx.com     nxt_int_t            res;
3556425Smax.romanov@nginx.com     nxt_port_t           *port;
3557425Smax.romanov@nginx.com     nxt_bool_t           cancelled;
3558425Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
3559318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3560318Smax.romanov@nginx.com 
3561318Smax.romanov@nginx.com     rc = data;
3562318Smax.romanov@nginx.com 
3563425Smax.romanov@nginx.com     ra = rc->ra;
3564425Smax.romanov@nginx.com 
3565425Smax.romanov@nginx.com     if (ra != NULL) {
3566425Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
3567425Smax.romanov@nginx.com 
3568425Smax.romanov@nginx.com         if (cancelled) {
3569425Smax.romanov@nginx.com             nxt_router_ra_inc_use(ra);
3570425Smax.romanov@nginx.com 
3571427Smax.romanov@nginx.com             res = nxt_router_app_port(task, rc->app, ra);
3572425Smax.romanov@nginx.com 
3573425Smax.romanov@nginx.com             if (res == NXT_OK) {
3574425Smax.romanov@nginx.com                 port = ra->app_port;
3575425Smax.romanov@nginx.com 
3576551Smax.romanov@nginx.com                 if (nxt_slow_path(port == NULL)) {
3577551Smax.romanov@nginx.com                     nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra");
3578551Smax.romanov@nginx.com                     return;
3579551Smax.romanov@nginx.com                 }
3580425Smax.romanov@nginx.com 
3581425Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc,
3582425Smax.romanov@nginx.com                                          port->pid);
3583425Smax.romanov@nginx.com 
3584425Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, ra);
3585425Smax.romanov@nginx.com             }
3586425Smax.romanov@nginx.com 
3587425Smax.romanov@nginx.com             msg->port_msg.last = 0;
3588425Smax.romanov@nginx.com 
3589425Smax.romanov@nginx.com             return;
3590425Smax.romanov@nginx.com         }
3591425Smax.romanov@nginx.com     }
3592425Smax.romanov@nginx.com 
3593616Smax.romanov@nginx.com     if (rc->ap != NULL) {
3594616Smax.romanov@nginx.com         nxt_http_request_error(task, rc->ap->request,
3595616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3596616Smax.romanov@nginx.com     }
3597318Smax.romanov@nginx.com 
3598343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
3599318Smax.romanov@nginx.com }
3600318Smax.romanov@nginx.com 
3601318Smax.romanov@nginx.com 
3602141Smax.romanov@nginx.com static void
3603343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3604343Smax.romanov@nginx.com     void *data)
3605192Smax.romanov@nginx.com {
3606753Smax.romanov@nginx.com     nxt_app_t        *app;
3607753Smax.romanov@nginx.com     nxt_port_t       *port;
3608753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3609753Smax.romanov@nginx.com 
3610753Smax.romanov@nginx.com     app_joint = data;
3611347Smax.romanov@nginx.com     port = msg->u.new_port;
3612343Smax.romanov@nginx.com 
3613753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3614343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3615343Smax.romanov@nginx.com 
3616753Smax.romanov@nginx.com     app = app_joint->app;
3617753Smax.romanov@nginx.com 
3618753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3619753Smax.romanov@nginx.com 
3620753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3621753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3622753Smax.romanov@nginx.com 
3623753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3624753Smax.romanov@nginx.com 
3625753Smax.romanov@nginx.com         return;
3626753Smax.romanov@nginx.com     }
3627753Smax.romanov@nginx.com 
3628343Smax.romanov@nginx.com     port->app = app;
3629343Smax.romanov@nginx.com 
3630343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3631343Smax.romanov@nginx.com 
3632507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3633507Smax.romanov@nginx.com 
3634507Smax.romanov@nginx.com     app->pending_processes--;
3635507Smax.romanov@nginx.com     app->processes++;
3636343Smax.romanov@nginx.com 
3637343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3638343Smax.romanov@nginx.com 
3639507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3640507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3641343Smax.romanov@nginx.com 
3642343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
3643192Smax.romanov@nginx.com }
3644192Smax.romanov@nginx.com 
3645192Smax.romanov@nginx.com 
3646192Smax.romanov@nginx.com static void
3647343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3648343Smax.romanov@nginx.com     void *data)
3649192Smax.romanov@nginx.com {
3650318Smax.romanov@nginx.com     nxt_app_t           *app;
3651753Smax.romanov@nginx.com     nxt_app_joint_t     *app_joint;
3652318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
3653318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3654343Smax.romanov@nginx.com 
3655753Smax.romanov@nginx.com     app_joint = data;
3656753Smax.romanov@nginx.com 
3657753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3658753Smax.romanov@nginx.com 
3659753Smax.romanov@nginx.com     app = app_joint->app;
3660753Smax.romanov@nginx.com 
3661753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3662753Smax.romanov@nginx.com 
3663753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3664753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
3665753Smax.romanov@nginx.com 
3666753Smax.romanov@nginx.com         return;
3667753Smax.romanov@nginx.com     }
3668343Smax.romanov@nginx.com 
3669343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
3670343Smax.romanov@nginx.com 
3671343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3672343Smax.romanov@nginx.com 
3673507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3674507Smax.romanov@nginx.com 
3675507Smax.romanov@nginx.com     app->pending_processes--;
3676318Smax.romanov@nginx.com 
3677318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
3678318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
3679318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3680343Smax.romanov@nginx.com         lnk->next = NULL;
3681318Smax.romanov@nginx.com 
3682425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3683318Smax.romanov@nginx.com 
3684343Smax.romanov@nginx.com     } else {
3685343Smax.romanov@nginx.com         ra = NULL;
3686343Smax.romanov@nginx.com     }
3687343Smax.romanov@nginx.com 
3688343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3689343Smax.romanov@nginx.com 
3690343Smax.romanov@nginx.com     if (ra != NULL) {
3691318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
3692318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
3693318Smax.romanov@nginx.com 
3694507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start application process");
3695425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3696318Smax.romanov@nginx.com     }
3697192Smax.romanov@nginx.com }
3698192Smax.romanov@nginx.com 
3699753Smax.romanov@nginx.com nxt_inline nxt_port_t *
3700753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app);
3701192Smax.romanov@nginx.com 
3702343Smax.romanov@nginx.com void
3703343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
3704141Smax.romanov@nginx.com {
3705343Smax.romanov@nginx.com     int  c;
3706343Smax.romanov@nginx.com 
3707343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
3708343Smax.romanov@nginx.com 
3709343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
3710343Smax.romanov@nginx.com 
3711753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
3712753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
3713753Smax.romanov@nginx.com 
3714753Smax.romanov@nginx.com         } else {
3715753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
3716753Smax.romanov@nginx.com         }
3717163Smax.romanov@nginx.com     }
3718343Smax.romanov@nginx.com }
3719343Smax.romanov@nginx.com 
3720343Smax.romanov@nginx.com 
3721424Smax.romanov@nginx.com nxt_inline nxt_bool_t
3722424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
3723424Smax.romanov@nginx.com {
3724424Smax.romanov@nginx.com     nxt_port_t        *port;
3725424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3726424Smax.romanov@nginx.com 
3727424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3728424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3729424Smax.romanov@nginx.com 
3730424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
3731424Smax.romanov@nginx.com }
3732424Smax.romanov@nginx.com 
3733424Smax.romanov@nginx.com 
3734343Smax.romanov@nginx.com nxt_inline nxt_port_t *
3735427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
3736343Smax.romanov@nginx.com {
3737343Smax.romanov@nginx.com     nxt_port_t        *port;
3738343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3739343Smax.romanov@nginx.com 
3740343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3741343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
3742343Smax.romanov@nginx.com 
3743343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3744343Smax.romanov@nginx.com 
3745424Smax.romanov@nginx.com     port->app_pending_responses++;
3746424Smax.romanov@nginx.com 
3747507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3748507Smax.romanov@nginx.com         app->idle_processes--;
3749507Smax.romanov@nginx.com 
3750507Smax.romanov@nginx.com         if (port->idle_start == 0) {
3751507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
3752507Smax.romanov@nginx.com 
3753507Smax.romanov@nginx.com         } else {
3754507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
3755507Smax.romanov@nginx.com 
3756507Smax.romanov@nginx.com             port->idle_start = 0;
3757507Smax.romanov@nginx.com         }
3758507Smax.romanov@nginx.com     }
3759507Smax.romanov@nginx.com 
3760428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
3761428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3762428Smax.romanov@nginx.com         && (app->max_requests == 0
3763428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3764428Smax.romanov@nginx.com                 < app->max_requests))
3765277Sigor@sysoev.ru     {
3766343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
3767343Smax.romanov@nginx.com 
3768425Smax.romanov@nginx.com         nxt_port_inc_use(port);
3769425Smax.romanov@nginx.com 
3770343Smax.romanov@nginx.com     } else {
3771343Smax.romanov@nginx.com         lnk->next = NULL;
3772167Smax.romanov@nginx.com     }
3773167Smax.romanov@nginx.com 
3774343Smax.romanov@nginx.com     return port;
3775163Smax.romanov@nginx.com }
3776163Smax.romanov@nginx.com 
3777163Smax.romanov@nginx.com 
3778507Smax.romanov@nginx.com nxt_inline nxt_port_t *
3779507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
3780141Smax.romanov@nginx.com {
3781343Smax.romanov@nginx.com     nxt_port_t  *port;
3782141Smax.romanov@nginx.com 
3783141Smax.romanov@nginx.com     port = NULL;
3784141Smax.romanov@nginx.com 
3785141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3786141Smax.romanov@nginx.com 
3787343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
3788343Smax.romanov@nginx.com 
3789424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
3790343Smax.romanov@nginx.com             port = NULL;
3791343Smax.romanov@nginx.com 
3792343Smax.romanov@nginx.com             continue;
3793343Smax.romanov@nginx.com         }
3794343Smax.romanov@nginx.com 
3795507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
3796507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
3797507Smax.romanov@nginx.com 
3798507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
3799507Smax.romanov@nginx.com             app->idle_processes--;
3800507Smax.romanov@nginx.com         }
3801507Smax.romanov@nginx.com 
3802507Smax.romanov@nginx.com         port->app = NULL;
3803507Smax.romanov@nginx.com         app->processes--;
3804343Smax.romanov@nginx.com 
3805343Smax.romanov@nginx.com         break;
3806343Smax.romanov@nginx.com 
3807343Smax.romanov@nginx.com     } nxt_queue_loop;
3808141Smax.romanov@nginx.com 
3809141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3810141Smax.romanov@nginx.com 
3811141Smax.romanov@nginx.com     return port;
3812141Smax.romanov@nginx.com }
3813141Smax.romanov@nginx.com 
3814141Smax.romanov@nginx.com 
3815141Smax.romanov@nginx.com static void
3816753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
3817507Smax.romanov@nginx.com {
3818753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
3819507Smax.romanov@nginx.com 
3820507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
3821507Smax.romanov@nginx.com 
3822753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
3823507Smax.romanov@nginx.com }
3824507Smax.romanov@nginx.com 
3825507Smax.romanov@nginx.com 
3826507Smax.romanov@nginx.com static void
3827343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
3828141Smax.romanov@nginx.com {
3829343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3830343Smax.romanov@nginx.com 
3831538Svbart@nginx.com     ra = data;
3832538Svbart@nginx.com 
3833538Svbart@nginx.com #if (NXT_DEBUG)
3834538Svbart@nginx.com     {
3835538Svbart@nginx.com     nxt_app_t  *app;
3836538Svbart@nginx.com 
3837343Smax.romanov@nginx.com     app = obj;
3838141Smax.romanov@nginx.com 
3839141Smax.romanov@nginx.com     nxt_assert(app != NULL);
3840343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
3841343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3842343Smax.romanov@nginx.com 
3843343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
3844343Smax.romanov@nginx.com               &app->name, app, ra->stream);
3845538Svbart@nginx.com     }
3846538Svbart@nginx.com #endif
3847343Smax.romanov@nginx.com 
3848425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
3849343Smax.romanov@nginx.com }
3850343Smax.romanov@nginx.com 
3851343Smax.romanov@nginx.com 
3852343Smax.romanov@nginx.com static void
3853343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
3854343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
3855343Smax.romanov@nginx.com {
3856427Smax.romanov@nginx.com     nxt_app_t                *app;
3857507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
3858507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
3859427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
3860427Smax.romanov@nginx.com     nxt_req_app_link_t       *ra, *pending_ra, *re_ra;
3861427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
3862343Smax.romanov@nginx.com 
3863343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3864343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
3865343Smax.romanov@nginx.com 
3866427Smax.romanov@nginx.com     ra = NULL;
3867427Smax.romanov@nginx.com 
3868343Smax.romanov@nginx.com     app = port->app;
3869343Smax.romanov@nginx.com 
3870343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3871343Smax.romanov@nginx.com 
3872424Smax.romanov@nginx.com     port->app_pending_responses -= request_failed + got_response;
3873343Smax.romanov@nginx.com     port->app_responses += got_response;
3874343Smax.romanov@nginx.com 
3875427Smax.romanov@nginx.com     if (port->pair[1] != -1
3876426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
3877428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3878428Smax.romanov@nginx.com         && (app->max_requests == 0
3879428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3880428Smax.romanov@nginx.com                 < app->max_requests))
3881343Smax.romanov@nginx.com     {
3882424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
3883424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
3884424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
3885424Smax.romanov@nginx.com 
3886424Smax.romanov@nginx.com             } else {
3887424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3888424Smax.romanov@nginx.com             }
3889424Smax.romanov@nginx.com 
3890425Smax.romanov@nginx.com             nxt_port_inc_use(port);
3891424Smax.romanov@nginx.com 
3892424Smax.romanov@nginx.com         } else {
3893424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
3894424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
3895424Smax.romanov@nginx.com             {
3896424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
3897424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3898424Smax.romanov@nginx.com             }
3899424Smax.romanov@nginx.com         }
3900141Smax.romanov@nginx.com     }
3901141Smax.romanov@nginx.com 
3902427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
3903426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
3904343Smax.romanov@nginx.com     {
3905141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
3906141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3907343Smax.romanov@nginx.com         lnk->next = NULL;
3908141Smax.romanov@nginx.com 
3909425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3910425Smax.romanov@nginx.com 
3911427Smax.romanov@nginx.com         ra->app_port = nxt_router_pop_first_port(app);
3912425Smax.romanov@nginx.com 
3913425Smax.romanov@nginx.com         if (ra->app_port->app_pending_responses > 1) {
3914427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
3915425Smax.romanov@nginx.com         }
3916425Smax.romanov@nginx.com     }
3917425Smax.romanov@nginx.com 
3918427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
3919425Smax.romanov@nginx.com     if ((request_failed > 0 || got_response > 0)
3920425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
3921425Smax.romanov@nginx.com     {
3922425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
3923425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3924425Smax.romanov@nginx.com         lnk->next = NULL;
3925425Smax.romanov@nginx.com 
3926427Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
3927427Smax.romanov@nginx.com                                          link_port_pending);
3928427Smax.romanov@nginx.com 
3929427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
3930427Smax.romanov@nginx.com 
3931427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
3932427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
3933425Smax.romanov@nginx.com 
3934425Smax.romanov@nginx.com     } else {
3935427Smax.romanov@nginx.com         pending_ra = NULL;
3936141Smax.romanov@nginx.com     }
3937141Smax.romanov@nginx.com 
3938427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
3939427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
3940427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
3941427Smax.romanov@nginx.com 
3942427Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending);
3943427Smax.romanov@nginx.com 
3944427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
3945427Smax.romanov@nginx.com 
3946427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
3947427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
3948427Smax.romanov@nginx.com 
3949427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
3950427Smax.romanov@nginx.com                                               re_ra->stream);
3951427Smax.romanov@nginx.com 
3952427Smax.romanov@nginx.com             if (cancelled) {
3953427Smax.romanov@nginx.com                 nxt_router_ra_inc_use(re_ra);
3954427Smax.romanov@nginx.com 
3955427Smax.romanov@nginx.com                 state.ra = re_ra;
3956427Smax.romanov@nginx.com                 state.app = app;
3957427Smax.romanov@nginx.com 
3958427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
3959427Smax.romanov@nginx.com 
3960427Smax.romanov@nginx.com                 goto re_ra_cancelled;
3961427Smax.romanov@nginx.com             }
3962427Smax.romanov@nginx.com         }
3963427Smax.romanov@nginx.com     }
3964427Smax.romanov@nginx.com 
3965427Smax.romanov@nginx.com     re_ra = NULL;
3966427Smax.romanov@nginx.com 
3967427Smax.romanov@nginx.com re_ra_cancelled:
3968427Smax.romanov@nginx.com 
3969753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
3970753Smax.romanov@nginx.com                  && port->app_pending_responses == 0
3971753Smax.romanov@nginx.com                  && port->app_responses >= app->max_requests);
3972367Smax.romanov@nginx.com 
3973507Smax.romanov@nginx.com     if (send_quit) {
3974507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
3975507Smax.romanov@nginx.com 
3976507Smax.romanov@nginx.com         port->app = NULL;
3977507Smax.romanov@nginx.com         app->processes--;
3978507Smax.romanov@nginx.com 
3979507Smax.romanov@nginx.com     } else {
3980507Smax.romanov@nginx.com         port_unchained = 0;
3981507Smax.romanov@nginx.com     }
3982507Smax.romanov@nginx.com 
3983507Smax.romanov@nginx.com     adjust_idle_timer = 0;
3984507Smax.romanov@nginx.com 
3985571Smax.romanov@nginx.com     if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) {
3986507Smax.romanov@nginx.com         nxt_assert(port->idle_link.next == NULL);
3987507Smax.romanov@nginx.com 
3988507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
3989507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
3990507Smax.romanov@nginx.com         {
3991507Smax.romanov@nginx.com             adjust_idle_timer = 1;
3992507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
3993507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
3994507Smax.romanov@nginx.com         }
3995507Smax.romanov@nginx.com 
3996507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
3997507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
3998507Smax.romanov@nginx.com 
3999507Smax.romanov@nginx.com         } else {
4000507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
4001507Smax.romanov@nginx.com 
4002507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
4003507Smax.romanov@nginx.com         }
4004507Smax.romanov@nginx.com 
4005507Smax.romanov@nginx.com         app->idle_processes++;
4006507Smax.romanov@nginx.com     }
4007507Smax.romanov@nginx.com 
4008343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4009343Smax.romanov@nginx.com 
4010507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4011507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4012507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4013507Smax.romanov@nginx.com     }
4014507Smax.romanov@nginx.com 
4015427Smax.romanov@nginx.com     if (pending_ra != NULL) {
4016427Smax.romanov@nginx.com         nxt_router_ra_use(task, pending_ra, -1);
4017427Smax.romanov@nginx.com     }
4018427Smax.romanov@nginx.com 
4019427Smax.romanov@nginx.com     if (re_ra != NULL) {
4020427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
4021427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4022427Smax.romanov@nginx.com                                nxt_router_app_process_request,
4023427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
4024427Smax.romanov@nginx.com         }
4025425Smax.romanov@nginx.com     }
4026425Smax.romanov@nginx.com 
4027343Smax.romanov@nginx.com     if (ra != NULL) {
4028425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
4029425Smax.romanov@nginx.com 
4030343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4031343Smax.romanov@nginx.com                            nxt_router_app_process_request,
4032343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
4033343Smax.romanov@nginx.com 
4034343Smax.romanov@nginx.com         goto adjust_use;
4035343Smax.romanov@nginx.com     }
4036343Smax.romanov@nginx.com 
4037343Smax.romanov@nginx.com     /* ? */
4038163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
4039343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4040343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
4041343Smax.romanov@nginx.com 
4042343Smax.romanov@nginx.com         goto adjust_use;
4043163Smax.romanov@nginx.com     }
4044163Smax.romanov@nginx.com 
4045367Smax.romanov@nginx.com     if (send_quit) {
4046507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
4047167Smax.romanov@nginx.com                   &app->name, app);
4048163Smax.romanov@nginx.com 
4049163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
4050163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
4051163Smax.romanov@nginx.com 
4052507Smax.romanov@nginx.com         if (port_unchained) {
4053507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
4054507Smax.romanov@nginx.com         }
4055507Smax.romanov@nginx.com 
4056343Smax.romanov@nginx.com         goto adjust_use;
4057163Smax.romanov@nginx.com     }
4058163Smax.romanov@nginx.com 
4059167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4060167Smax.romanov@nginx.com               &app->name, app);
4061141Smax.romanov@nginx.com 
4062343Smax.romanov@nginx.com adjust_use:
4063343Smax.romanov@nginx.com 
4064425Smax.romanov@nginx.com     if (request_failed > 0 || got_response > 0) {
4065425Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4066343Smax.romanov@nginx.com     }
4067141Smax.romanov@nginx.com }
4068141Smax.romanov@nginx.com 
4069141Smax.romanov@nginx.com 
4070343Smax.romanov@nginx.com void
4071343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4072141Smax.romanov@nginx.com {
4073507Smax.romanov@nginx.com     nxt_app_t         *app;
4074507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4075507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4076507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4077141Smax.romanov@nginx.com 
4078141Smax.romanov@nginx.com     app = port->app;
4079343Smax.romanov@nginx.com 
4080343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4081141Smax.romanov@nginx.com 
4082141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4083141Smax.romanov@nginx.com 
4084507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4085507Smax.romanov@nginx.com 
4086507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4087507Smax.romanov@nginx.com         app->idle_processes--;
4088507Smax.romanov@nginx.com 
4089507Smax.romanov@nginx.com         if (port->idle_start == 0
4090507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4091507Smax.romanov@nginx.com         {
4092507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4093507Smax.romanov@nginx.com 
4094507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4095507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4096507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4097507Smax.romanov@nginx.com 
4098507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4099507Smax.romanov@nginx.com 
4100507Smax.romanov@nginx.com             idle_port->idle_start = 0;
4101507Smax.romanov@nginx.com         }
4102343Smax.romanov@nginx.com     }
4103343Smax.romanov@nginx.com 
4104507Smax.romanov@nginx.com     app->processes--;
4105507Smax.romanov@nginx.com 
4106753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4107507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
4108507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
4109507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
4110507Smax.romanov@nginx.com 
4111507Smax.romanov@nginx.com     if (start_process) {
4112507Smax.romanov@nginx.com         app->pending_processes++;
4113163Smax.romanov@nginx.com     }
4114141Smax.romanov@nginx.com 
4115141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4116163Smax.romanov@nginx.com 
4117507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4118343Smax.romanov@nginx.com 
4119343Smax.romanov@nginx.com     if (unchain) {
4120343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4121163Smax.romanov@nginx.com     }
4122163Smax.romanov@nginx.com 
4123507Smax.romanov@nginx.com     if (start_process) {
4124507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4125507Smax.romanov@nginx.com     }
4126507Smax.romanov@nginx.com }
4127507Smax.romanov@nginx.com 
4128507Smax.romanov@nginx.com 
4129507Smax.romanov@nginx.com static void
4130507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4131507Smax.romanov@nginx.com {
4132507Smax.romanov@nginx.com     nxt_app_t           *app;
4133507Smax.romanov@nginx.com     nxt_bool_t          queued;
4134507Smax.romanov@nginx.com     nxt_port_t          *port;
4135507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4136507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4137507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4138507Smax.romanov@nginx.com 
4139507Smax.romanov@nginx.com     app = obj;
4140507Smax.romanov@nginx.com     queued = (data == app);
4141507Smax.romanov@nginx.com 
4142507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4143507Smax.romanov@nginx.com               &app->name, queued);
4144507Smax.romanov@nginx.com 
4145507Smax.romanov@nginx.com     engine = task->thread->engine;
4146507Smax.romanov@nginx.com 
4147507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
4148507Smax.romanov@nginx.com 
4149811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
4150507Smax.romanov@nginx.com     timeout = 0;
4151507Smax.romanov@nginx.com 
4152507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4153507Smax.romanov@nginx.com 
4154507Smax.romanov@nginx.com     if (queued) {
4155507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
4156343Smax.romanov@nginx.com     }
4157507Smax.romanov@nginx.com 
4158507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
4159507Smax.romanov@nginx.com 
4160551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4161507Smax.romanov@nginx.com 
4162507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
4163507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4164507Smax.romanov@nginx.com 
4165507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
4166507Smax.romanov@nginx.com 
4167507Smax.romanov@nginx.com         if (timeout > threshold) {
4168507Smax.romanov@nginx.com             break;
4169507Smax.romanov@nginx.com         }
4170507Smax.romanov@nginx.com 
4171507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4172507Smax.romanov@nginx.com         lnk->next = NULL;
4173507Smax.romanov@nginx.com 
4174507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4175507Smax.romanov@nginx.com 
4176507Smax.romanov@nginx.com         app->idle_processes--;
4177507Smax.romanov@nginx.com         app->processes--;
4178507Smax.romanov@nginx.com         port->app = NULL;
4179507Smax.romanov@nginx.com 
4180507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4181507Smax.romanov@nginx.com 
4182507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4183507Smax.romanov@nginx.com                   &app->name, port->pid);
4184507Smax.romanov@nginx.com 
4185507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4186507Smax.romanov@nginx.com 
4187507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4188507Smax.romanov@nginx.com 
4189507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4190507Smax.romanov@nginx.com     }
4191507Smax.romanov@nginx.com 
4192507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4193507Smax.romanov@nginx.com 
4194507Smax.romanov@nginx.com     if (timeout > threshold) {
4195753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4196507Smax.romanov@nginx.com 
4197507Smax.romanov@nginx.com     } else {
4198753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4199507Smax.romanov@nginx.com     }
4200507Smax.romanov@nginx.com 
4201507Smax.romanov@nginx.com     if (queued) {
4202507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4203507Smax.romanov@nginx.com     }
4204507Smax.romanov@nginx.com }
4205507Smax.romanov@nginx.com 
4206507Smax.romanov@nginx.com 
4207507Smax.romanov@nginx.com static void
4208507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4209507Smax.romanov@nginx.com {
4210753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4211753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4212507Smax.romanov@nginx.com 
4213507Smax.romanov@nginx.com     timer = obj;
4214753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4215753Smax.romanov@nginx.com 
4216753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4217753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4218753Smax.romanov@nginx.com     }
4219753Smax.romanov@nginx.com }
4220753Smax.romanov@nginx.com 
4221753Smax.romanov@nginx.com 
4222753Smax.romanov@nginx.com static void
4223753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4224753Smax.romanov@nginx.com {
4225753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4226753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4227753Smax.romanov@nginx.com 
4228753Smax.romanov@nginx.com     timer = obj;
4229753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4230753Smax.romanov@nginx.com 
4231753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4232507Smax.romanov@nginx.com }
4233507Smax.romanov@nginx.com 
4234507Smax.romanov@nginx.com 
4235507Smax.romanov@nginx.com static void
4236753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4237507Smax.romanov@nginx.com {
4238753Smax.romanov@nginx.com     nxt_app_t        *app;
4239753Smax.romanov@nginx.com     nxt_port_t       *port;
4240753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4241753Smax.romanov@nginx.com 
4242753Smax.romanov@nginx.com     app_joint = obj;
4243753Smax.romanov@nginx.com     app = app_joint->app;
4244753Smax.romanov@nginx.com 
4245753Smax.romanov@nginx.com     for ( ;; ) {
4246753Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
4247753Smax.romanov@nginx.com         if (port == NULL) {
4248753Smax.romanov@nginx.com             break;
4249753Smax.romanov@nginx.com         }
4250753Smax.romanov@nginx.com 
4251753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4252753Smax.romanov@nginx.com 
4253753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4254753Smax.romanov@nginx.com 
4255753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4256753Smax.romanov@nginx.com     }
4257753Smax.romanov@nginx.com 
4258753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
4259753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4260753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->requests));
4261753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4262753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4263753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4264753Smax.romanov@nginx.com 
4265753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
4266753Smax.romanov@nginx.com     nxt_free(app);
4267753Smax.romanov@nginx.com 
4268753Smax.romanov@nginx.com     app_joint->app = NULL;
4269753Smax.romanov@nginx.com 
4270753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4271753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4272753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4273753Smax.romanov@nginx.com 
4274753Smax.romanov@nginx.com     } else {
4275753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4276753Smax.romanov@nginx.com     }
4277141Smax.romanov@nginx.com }
4278141Smax.romanov@nginx.com 
4279141Smax.romanov@nginx.com 
4280427Smax.romanov@nginx.com static void
4281427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
4282141Smax.romanov@nginx.com {
4283427Smax.romanov@nginx.com     nxt_app_t           *app;
4284507Smax.romanov@nginx.com     nxt_bool_t          can_start_process;
4285427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4286427Smax.romanov@nginx.com 
4287427Smax.romanov@nginx.com     ra = state->ra;
4288427Smax.romanov@nginx.com     app = state->app;
4289427Smax.romanov@nginx.com 
4290427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
4291343Smax.romanov@nginx.com 
4292425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_app_requests))
4293425Smax.romanov@nginx.com     {
4294425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4295425Smax.romanov@nginx.com     }
4296425Smax.romanov@nginx.com 
4297425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_port_pending))
4298425Smax.romanov@nginx.com     {
4299427Smax.romanov@nginx.com         nxt_assert(ra->link_app_pending.next != NULL);
4300427Smax.romanov@nginx.com 
4301427Smax.romanov@nginx.com         nxt_queue_remove(&ra->link_app_pending);
4302427Smax.romanov@nginx.com         ra->link_app_pending.next = NULL;
4303427Smax.romanov@nginx.com 
4304425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4305425Smax.romanov@nginx.com     }
4306425Smax.romanov@nginx.com 
4307427Smax.romanov@nginx.com     state->failed_port = ra->app_port;
4308427Smax.romanov@nginx.com 
4309425Smax.romanov@nginx.com     if (ra->app_port != NULL) {
4310427Smax.romanov@nginx.com         state->failed_port_use_delta--;
4311427Smax.romanov@nginx.com 
4312427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
4313427Smax.romanov@nginx.com 
4314427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
4315427Smax.romanov@nginx.com             state->failed_port_use_delta--;
4316427Smax.romanov@nginx.com         }
4317427Smax.romanov@nginx.com 
4318427Smax.romanov@nginx.com         ra->app_port = NULL;
4319427Smax.romanov@nginx.com     }
4320427Smax.romanov@nginx.com 
4321507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
4322507Smax.romanov@nginx.com 
4323427Smax.romanov@nginx.com     state->port = NULL;
4324507Smax.romanov@nginx.com     state->start_process = 0;
4325427Smax.romanov@nginx.com 
4326427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
4327507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
4328427Smax.romanov@nginx.com     {
4329427Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
4330427Smax.romanov@nginx.com 
4331427Smax.romanov@nginx.com         if (nxt_slow_path(ra == NULL)) {
4332427Smax.romanov@nginx.com             goto fail;
4333427Smax.romanov@nginx.com         }
4334427Smax.romanov@nginx.com 
4335427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
4336427Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests, &ra->link_app_requests);
4337427Smax.romanov@nginx.com 
4338427Smax.romanov@nginx.com         } else {
4339427Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link_app_requests);
4340427Smax.romanov@nginx.com         }
4341427Smax.romanov@nginx.com 
4342427Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
4343427Smax.romanov@nginx.com 
4344427Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream);
4345427Smax.romanov@nginx.com 
4346507Smax.romanov@nginx.com         if (can_start_process) {
4347507Smax.romanov@nginx.com             app->pending_processes++;
4348507Smax.romanov@nginx.com             state->start_process = 1;
4349425Smax.romanov@nginx.com         }
4350425Smax.romanov@nginx.com 
4351425Smax.romanov@nginx.com     } else {
4352427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
4353427Smax.romanov@nginx.com 
4354427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
4355427Smax.romanov@nginx.com             ra = nxt_router_ra_create(task, ra);
4356427Smax.romanov@nginx.com 
4357427Smax.romanov@nginx.com             if (nxt_slow_path(ra == NULL)) {
4358427Smax.romanov@nginx.com                 goto fail;
4359351Smax.romanov@nginx.com             }
4360427Smax.romanov@nginx.com 
4361427Smax.romanov@nginx.com             ra->app_port = state->port;
4362427Smax.romanov@nginx.com 
4363427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
4364425Smax.romanov@nginx.com         }
4365507Smax.romanov@nginx.com 
4366507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
4367507Smax.romanov@nginx.com             app->pending_processes++;
4368507Smax.romanov@nginx.com             state->start_process = 1;
4369507Smax.romanov@nginx.com         }
4370343Smax.romanov@nginx.com     }
4371343Smax.romanov@nginx.com 
4372427Smax.romanov@nginx.com fail:
4373427Smax.romanov@nginx.com 
4374427Smax.romanov@nginx.com     state->shared_ra = ra;
4375427Smax.romanov@nginx.com }
4376427Smax.romanov@nginx.com 
4377427Smax.romanov@nginx.com 
4378427Smax.romanov@nginx.com static nxt_int_t
4379427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
4380427Smax.romanov@nginx.com {
4381427Smax.romanov@nginx.com     nxt_int_t           res;
4382427Smax.romanov@nginx.com     nxt_app_t           *app;
4383427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4384427Smax.romanov@nginx.com 
4385427Smax.romanov@nginx.com     ra = state->shared_ra;
4386427Smax.romanov@nginx.com     app = state->app;
4387427Smax.romanov@nginx.com 
4388427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
4389427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
4390425Smax.romanov@nginx.com     }
4391425Smax.romanov@nginx.com 
4392351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
4393427Smax.romanov@nginx.com         if (state->port != NULL) {
4394427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
4395425Smax.romanov@nginx.com         }
4396425Smax.romanov@nginx.com 
4397427Smax.romanov@nginx.com         nxt_router_ra_error(state->ra, 500,
4398427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
4399427Smax.romanov@nginx.com         nxt_router_ra_use(task, state->ra, -1);
4400427Smax.romanov@nginx.com 
4401351Smax.romanov@nginx.com         return NXT_ERROR;
4402351Smax.romanov@nginx.com     }
4403351Smax.romanov@nginx.com 
4404427Smax.romanov@nginx.com     if (state->port != NULL) {
4405343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
4406163Smax.romanov@nginx.com 
4407427Smax.romanov@nginx.com         ra->app_port = state->port;
4408343Smax.romanov@nginx.com 
4409507Smax.romanov@nginx.com         if (state->start_process) {
4410507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
4411507Smax.romanov@nginx.com         }
4412507Smax.romanov@nginx.com 
4413141Smax.romanov@nginx.com         return NXT_OK;
4414141Smax.romanov@nginx.com     }
4415141Smax.romanov@nginx.com 
4416507Smax.romanov@nginx.com     if (!state->start_process) {
4417507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
4418343Smax.romanov@nginx.com                   &app->name, app);
4419343Smax.romanov@nginx.com 
4420343Smax.romanov@nginx.com         return NXT_AGAIN;
4421343Smax.romanov@nginx.com     }
4422343Smax.romanov@nginx.com 
4423507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
4424343Smax.romanov@nginx.com 
4425343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4426507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start app process");
4427427Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
4428343Smax.romanov@nginx.com 
4429141Smax.romanov@nginx.com         return NXT_ERROR;
4430141Smax.romanov@nginx.com     }
4431141Smax.romanov@nginx.com 
4432141Smax.romanov@nginx.com     return NXT_AGAIN;
443388Smax.romanov@nginx.com }
443488Smax.romanov@nginx.com 
443588Smax.romanov@nginx.com 
4436427Smax.romanov@nginx.com static nxt_int_t
4437427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
4438427Smax.romanov@nginx.com {
4439427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4440427Smax.romanov@nginx.com 
4441427Smax.romanov@nginx.com     state.ra = ra;
4442427Smax.romanov@nginx.com     state.app = app;
4443427Smax.romanov@nginx.com 
4444427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4445427Smax.romanov@nginx.com 
4446427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
4447427Smax.romanov@nginx.com 
4448427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4449427Smax.romanov@nginx.com 
4450427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
4451427Smax.romanov@nginx.com }
4452427Smax.romanov@nginx.com 
4453427Smax.romanov@nginx.com 
4454431Sigor@sysoev.ru void
4455964Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar,
4456964Sigor@sysoev.ru     nxt_app_t *app)
445753Sigor@sysoev.ru {
4458431Sigor@sysoev.ru     nxt_int_t            res;
4459431Sigor@sysoev.ru     nxt_port_t           *port;
4460431Sigor@sysoev.ru     nxt_event_engine_t   *engine;
4461431Sigor@sysoev.ru     nxt_http_request_t   *r;
4462431Sigor@sysoev.ru     nxt_req_app_link_t   ra_local, *ra;
4463431Sigor@sysoev.ru     nxt_req_conn_link_t  *rc;
4464431Sigor@sysoev.ru 
4465431Sigor@sysoev.ru     r = ar->request;
446688Smax.romanov@nginx.com     engine = task->thread->engine;
446788Smax.romanov@nginx.com 
4468318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
4469318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4470318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
4471318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
4472122Smax.romanov@nginx.com 
447388Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
4474431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4475141Smax.romanov@nginx.com         return;
447688Smax.romanov@nginx.com     }
447788Smax.romanov@nginx.com 
4478318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
4479425Smax.romanov@nginx.com     rc->app = app;
4480425Smax.romanov@nginx.com 
4481425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4482425Smax.romanov@nginx.com 
4483431Sigor@sysoev.ru     rc->ap = ar;
4484346Smax.romanov@nginx.com 
4485351Smax.romanov@nginx.com     ra = &ra_local;
4486351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
4487167Smax.romanov@nginx.com 
4488427Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, ra);
4489141Smax.romanov@nginx.com 
4490141Smax.romanov@nginx.com     if (res != NXT_OK) {
4491141Smax.romanov@nginx.com         return;
4492141Smax.romanov@nginx.com     }
4493141Smax.romanov@nginx.com 
4494425Smax.romanov@nginx.com     ra = rc->ra;
4495167Smax.romanov@nginx.com     port = ra->app_port;
4496141Smax.romanov@nginx.com 
4497425Smax.romanov@nginx.com     nxt_assert(port != NULL);
4498141Smax.romanov@nginx.com 
4499318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
4500318Smax.romanov@nginx.com 
4501425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
4502167Smax.romanov@nginx.com }
4503167Smax.romanov@nginx.com 
4504167Smax.romanov@nginx.com 
4505167Smax.romanov@nginx.com static void
4506423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4507423Smax.romanov@nginx.com {
4508423Smax.romanov@nginx.com }
4509423Smax.romanov@nginx.com 
4510423Smax.romanov@nginx.com 
4511423Smax.romanov@nginx.com static void
4512425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
4513167Smax.romanov@nginx.com {
4514343Smax.romanov@nginx.com     uint32_t             request_failed;
4515743Smax.romanov@nginx.com     nxt_buf_t            *buf;
4516167Smax.romanov@nginx.com     nxt_int_t            res;
4517343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
4518167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
4519167Smax.romanov@nginx.com 
4520343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
4521343Smax.romanov@nginx.com 
4522343Smax.romanov@nginx.com     port = ra->app_port;
4523167Smax.romanov@nginx.com     reply_port = ra->reply_port;
4524167Smax.romanov@nginx.com     ap = ra->ap;
4525141Smax.romanov@nginx.com 
4526343Smax.romanov@nginx.com     request_failed = 1;
4527343Smax.romanov@nginx.com 
4528141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
4529141Smax.romanov@nginx.com                                              reply_port->id);
4530141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
4531141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
4532122Smax.romanov@nginx.com 
4533122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
4534423Smax.romanov@nginx.com             nxt_router_ra_error(ra, 500,
4535345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
4536343Smax.romanov@nginx.com             goto release_port;
4537122Smax.romanov@nginx.com         }
4538122Smax.romanov@nginx.com 
4539141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
454088Smax.romanov@nginx.com     }
454188Smax.romanov@nginx.com 
4542743Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, &ap->r, port,
4543743Smax.romanov@nginx.com                                  nxt_app_msg_prefix[port->app->type]);
4544743Smax.romanov@nginx.com 
4545743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
4546423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4547345Smax.romanov@nginx.com                             "Failed to prepare message for application");
4548343Smax.romanov@nginx.com         goto release_port;
4549122Smax.romanov@nginx.com     }
455088Smax.romanov@nginx.com 
4551507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4552743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4553743Smax.romanov@nginx.com                     port->socket.fd);
455488Smax.romanov@nginx.com 
4555343Smax.romanov@nginx.com     request_failed = 0;
4556343Smax.romanov@nginx.com 
4557743Smax.romanov@nginx.com     ra->msg_info.buf = buf;
4558743Smax.romanov@nginx.com     ra->msg_info.completion_handler = buf->completion_handler;
4559743Smax.romanov@nginx.com 
4560743Smax.romanov@nginx.com     for (; buf; buf = buf->next) {
4561743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
4562423Smax.romanov@nginx.com     }
4563423Smax.romanov@nginx.com 
4564743Smax.romanov@nginx.com     buf = ra->msg_info.buf;
4565743Smax.romanov@nginx.com 
4566423Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking,
4567423Smax.romanov@nginx.com                                      ra->stream);
4568423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4569423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4570423Smax.romanov@nginx.com                             "Failed to get tracking area");
4571423Smax.romanov@nginx.com         goto release_port;
4572423Smax.romanov@nginx.com     }
4573423Smax.romanov@nginx.com 
4574743Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA,
4575743Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, buf,
4576423Smax.romanov@nginx.com                                  &ra->msg_info.tracking);
4577122Smax.romanov@nginx.com 
4578122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4579423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4580345Smax.romanov@nginx.com                             "Failed to send message to application");
4581343Smax.romanov@nginx.com         goto release_port;
4582122Smax.romanov@nginx.com     }
4583343Smax.romanov@nginx.com 
4584343Smax.romanov@nginx.com release_port:
4585343Smax.romanov@nginx.com 
4586345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
4587345Smax.romanov@nginx.com 
4588425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
458953Sigor@sysoev.ru }
459053Sigor@sysoev.ru 
459153Sigor@sysoev.ru 
4592743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4593743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4594743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4595743Smax.romanov@nginx.com };
4596743Smax.romanov@nginx.com 
4597743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4598743Smax.romanov@nginx.com 
4599743Smax.romanov@nginx.com 
4600743Smax.romanov@nginx.com static nxt_http_field_t *
4601743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4602216Sigor@sysoev.ru {
4603743Smax.romanov@nginx.com     if (part == NULL) {
4604743Smax.romanov@nginx.com         return NULL;
4605216Sigor@sysoev.ru     }
4606216Sigor@sysoev.ru 
4607743Smax.romanov@nginx.com     while (part->nelts == 0) {
4608743Smax.romanov@nginx.com         part = part->next;
4609743Smax.romanov@nginx.com         if (part == NULL) {
4610743Smax.romanov@nginx.com             return NULL;
4611743Smax.romanov@nginx.com         }
4612216Sigor@sysoev.ru     }
4613216Sigor@sysoev.ru 
4614743Smax.romanov@nginx.com     i->part = part;
4615743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4616743Smax.romanov@nginx.com 
4617743Smax.romanov@nginx.com     return i->field;
4618743Smax.romanov@nginx.com }
4619743Smax.romanov@nginx.com 
4620743Smax.romanov@nginx.com 
4621743Smax.romanov@nginx.com static nxt_http_field_t *
4622743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4623743Smax.romanov@nginx.com {
4624743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4625743Smax.romanov@nginx.com }
4626743Smax.romanov@nginx.com 
4627743Smax.romanov@nginx.com 
4628743Smax.romanov@nginx.com static nxt_http_field_t *
4629743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4630743Smax.romanov@nginx.com {
4631743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4632743Smax.romanov@nginx.com 
4633743Smax.romanov@nginx.com     end += i->part->nelts;
4634743Smax.romanov@nginx.com     i->field++;
4635743Smax.romanov@nginx.com 
4636743Smax.romanov@nginx.com     if (i->field < end) {
4637743Smax.romanov@nginx.com         return i->field;
4638216Sigor@sysoev.ru     }
4639216Sigor@sysoev.ru 
4640743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4641216Sigor@sysoev.ru }
4642216Sigor@sysoev.ru 
4643216Sigor@sysoev.ru 
4644743Smax.romanov@nginx.com static nxt_buf_t *
4645743Smax.romanov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
4646743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix)
4647216Sigor@sysoev.ru {
4648743Smax.romanov@nginx.com     void                      *target_pos, *query_pos;
4649743Smax.romanov@nginx.com     u_char                    *pos, *end, *p, c;
4650743Smax.romanov@nginx.com     size_t                    fields_count, req_size, size, free_size;
4651743Smax.romanov@nginx.com     size_t                    copy_size;
4652743Smax.romanov@nginx.com     nxt_buf_t                 *b, *buf, *out, **tail;
4653743Smax.romanov@nginx.com     nxt_http_field_t          *field, *dup;
4654743Smax.romanov@nginx.com     nxt_unit_field_t          *dst_field;
4655743Smax.romanov@nginx.com     nxt_fields_iter_t         iter, dup_iter;
4656743Smax.romanov@nginx.com     nxt_unit_request_t        *req;
4657216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
4658216Sigor@sysoev.ru 
4659216Sigor@sysoev.ru     h = &r->header;
4660216Sigor@sysoev.ru 
4661743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
4662967Svbart@nginx.com                + h->method.length + 1
4663967Svbart@nginx.com                + h->version.length + 1
4664967Svbart@nginx.com                + r->remote.length + 1
4665967Svbart@nginx.com                + r->local.length + 1
4666967Svbart@nginx.com                + h->server_name.length + 1
4667967Svbart@nginx.com                + h->target.length + 1
4668967Svbart@nginx.com                + (h->path.start != h->target.start ? h->path.length + 1 : 0);
4669743Smax.romanov@nginx.com 
4670743Smax.romanov@nginx.com     fields_count = 0;
4671743Smax.romanov@nginx.com 
4672743Smax.romanov@nginx.com     nxt_list_each(field, h->fields) {
4673743Smax.romanov@nginx.com         fields_count++;
4674743Smax.romanov@nginx.com 
4675743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4676743Smax.romanov@nginx.com                     + field->value_length + 1;
4677743Smax.romanov@nginx.com     } nxt_list_loop;
4678743Smax.romanov@nginx.com 
4679743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4680743Smax.romanov@nginx.com 
4681743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4682743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4683743Smax.romanov@nginx.com                   (int) req_size);
4684743Smax.romanov@nginx.com 
4685743Smax.romanov@nginx.com         return NULL;
4686743Smax.romanov@nginx.com     }
4687743Smax.romanov@nginx.com 
4688743Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, port,
4689743Smax.romanov@nginx.com               nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE));
4690743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4691743Smax.romanov@nginx.com         return NULL;
4692743Smax.romanov@nginx.com     }
4693743Smax.romanov@nginx.com 
4694743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4695743Smax.romanov@nginx.com     out->mem.free += req_size;
4696743Smax.romanov@nginx.com 
4697743Smax.romanov@nginx.com     req->content_length = h->parsed_content_length;
4698743Smax.romanov@nginx.com 
4699743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4700743Smax.romanov@nginx.com 
4701743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4702743Smax.romanov@nginx.com 
4703743Smax.romanov@nginx.com     req->method_length = h->method.length;
4704743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
4705743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->method.start, h->method.length);
4706743Smax.romanov@nginx.com     *p++ = '\0';
4707743Smax.romanov@nginx.com 
4708743Smax.romanov@nginx.com     req->version_length = h->version.length;
4709743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
4710743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->version.start, h->version.length);
4711743Smax.romanov@nginx.com     *p++ = '\0';
4712743Smax.romanov@nginx.com 
4713743Smax.romanov@nginx.com     req->remote_length = r->remote.length;
4714743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
4715743Smax.romanov@nginx.com     p = nxt_cpymem(p, r->remote.start, r->remote.length);
4716743Smax.romanov@nginx.com     *p++ = '\0';
4717743Smax.romanov@nginx.com 
4718743Smax.romanov@nginx.com     req->local_length = r->local.length;
4719743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
4720743Smax.romanov@nginx.com     p = nxt_cpymem(p, r->local.start, r->local.length);
4721743Smax.romanov@nginx.com     *p++ = '\0';
4722743Smax.romanov@nginx.com 
4723967Svbart@nginx.com     req->server_name_length = h->server_name.length;
4724967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
4725967Svbart@nginx.com     p = nxt_cpymem(p, h->server_name.start, h->server_name.length);
4726967Svbart@nginx.com     *p++ = '\0';
4727967Svbart@nginx.com 
4728743Smax.romanov@nginx.com     target_pos = p;
4729743Smax.romanov@nginx.com     req->target_length = h->target.length;
4730743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
4731743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->target.start, h->target.length);
4732743Smax.romanov@nginx.com     *p++ = '\0';
4733743Smax.romanov@nginx.com 
4734743Smax.romanov@nginx.com     req->path_length = h->path.length;
4735216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
4736743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
4737277Sigor@sysoev.ru 
4738216Sigor@sysoev.ru     } else {
4739743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
4740743Smax.romanov@nginx.com         p = nxt_cpymem(p, h->path.start, h->path.length);
4741743Smax.romanov@nginx.com         *p++ = '\0';
4742305Smax.romanov@nginx.com     }
4743216Sigor@sysoev.ru 
4744743Smax.romanov@nginx.com     req->query_length = h->query.length;
4745743Smax.romanov@nginx.com     if (h->query.start != NULL) {
4746743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
4747743Smax.romanov@nginx.com                                    h->query.start - h->target.start);
4748743Smax.romanov@nginx.com 
4749743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
4750277Sigor@sysoev.ru 
4751216Sigor@sysoev.ru     } else {
4752743Smax.romanov@nginx.com         req->query.offset = 0;
4753216Sigor@sysoev.ru     }
4754216Sigor@sysoev.ru 
4755743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
4756743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
4757743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
4758743Smax.romanov@nginx.com 
4759743Smax.romanov@nginx.com     dst_field = req->fields;
4760743Smax.romanov@nginx.com 
4761743Smax.romanov@nginx.com     for (field = nxt_fields_first(h->fields, &iter);
4762743Smax.romanov@nginx.com          field != NULL;
4763743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
4764743Smax.romanov@nginx.com     {
4765743Smax.romanov@nginx.com         if (field->skip) {
4766743Smax.romanov@nginx.com             continue;
4767743Smax.romanov@nginx.com         }
4768743Smax.romanov@nginx.com 
4769743Smax.romanov@nginx.com         dst_field->hash = field->hash;
4770743Smax.romanov@nginx.com         dst_field->skip = 0;
4771743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
4772743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
4773743Smax.romanov@nginx.com 
4774967Svbart@nginx.com         if (field->value == h->content_length.start) {
4775743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
4776743Smax.romanov@nginx.com 
4777743Smax.romanov@nginx.com         } else if (field->value == h->content_type.start) {
4778743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
4779743Smax.romanov@nginx.com 
4780743Smax.romanov@nginx.com         } else if (field->value == h->cookie.start) {
4781743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
4782743Smax.romanov@nginx.com         }
4783743Smax.romanov@nginx.com 
4784743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
4785743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
4786743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
4787743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
4788743Smax.romanov@nginx.com 
4789743Smax.romanov@nginx.com         if (prefix->length != 0) {
4790743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4791743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
4792743Smax.romanov@nginx.com 
4793743Smax.romanov@nginx.com             end = field->name + field->name_length;
4794743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
4795743Smax.romanov@nginx.com                 c = *pos;
4796743Smax.romanov@nginx.com 
4797743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
4798743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
4799743Smax.romanov@nginx.com                     continue;
4800743Smax.romanov@nginx.com                 }
4801743Smax.romanov@nginx.com 
4802743Smax.romanov@nginx.com                 if (c == '-') {
4803743Smax.romanov@nginx.com                     *p++ = '_';
4804743Smax.romanov@nginx.com                     continue;
4805743Smax.romanov@nginx.com                 }
4806743Smax.romanov@nginx.com 
4807743Smax.romanov@nginx.com                 *p++ = c;
4808743Smax.romanov@nginx.com             }
4809743Smax.romanov@nginx.com 
4810743Smax.romanov@nginx.com         } else {
4811743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4812743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
4813743Smax.romanov@nginx.com         }
4814743Smax.romanov@nginx.com 
4815743Smax.romanov@nginx.com         *p++ = '\0';
4816743Smax.romanov@nginx.com 
4817743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
4818743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
4819743Smax.romanov@nginx.com 
4820743Smax.romanov@nginx.com         if (prefix->length != 0) {
4821743Smax.romanov@nginx.com             dup_iter = iter;
4822743Smax.romanov@nginx.com 
4823743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
4824743Smax.romanov@nginx.com                  dup != NULL;
4825743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
4826743Smax.romanov@nginx.com             {
4827743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
4828743Smax.romanov@nginx.com                     || dup->skip
4829743Smax.romanov@nginx.com                     || dup->hash != field->hash
4830743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
4831743Smax.romanov@nginx.com                 {
4832743Smax.romanov@nginx.com                     continue;
4833743Smax.romanov@nginx.com                 }
4834743Smax.romanov@nginx.com 
4835743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
4836743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
4837743Smax.romanov@nginx.com 
4838743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
4839743Smax.romanov@nginx.com 
4840743Smax.romanov@nginx.com                 dup->skip = 1;
4841743Smax.romanov@nginx.com             }
4842743Smax.romanov@nginx.com         }
4843743Smax.romanov@nginx.com 
4844743Smax.romanov@nginx.com         *p++ = '\0';
4845743Smax.romanov@nginx.com 
4846743Smax.romanov@nginx.com         dst_field++;
4847743Smax.romanov@nginx.com     }
4848743Smax.romanov@nginx.com 
4849743Smax.romanov@nginx.com     req->fields_count = dst_field - req->fields;
4850743Smax.romanov@nginx.com 
4851743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
4852743Smax.romanov@nginx.com 
4853743Smax.romanov@nginx.com     buf = out;
4854743Smax.romanov@nginx.com     tail = &buf->next;
4855216Sigor@sysoev.ru 
4856510Salexander.borisov@nginx.com     for (b = r->body.buf; b != NULL; b = b->next) {
4857743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
4858743Smax.romanov@nginx.com         pos = b->mem.pos;
4859743Smax.romanov@nginx.com 
4860743Smax.romanov@nginx.com         while (size > 0) {
4861743Smax.romanov@nginx.com             if (buf == NULL) {
4862743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
4863743Smax.romanov@nginx.com 
4864743Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, port, free_size);
4865743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
4866743Smax.romanov@nginx.com                     while (out != NULL) {
4867743Smax.romanov@nginx.com                         buf = out->next;
4868743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
4869743Smax.romanov@nginx.com                         out = buf;
4870743Smax.romanov@nginx.com                     }
4871743Smax.romanov@nginx.com                     return NULL;
4872743Smax.romanov@nginx.com                 }
4873743Smax.romanov@nginx.com 
4874743Smax.romanov@nginx.com                 *tail = buf;
4875743Smax.romanov@nginx.com                 tail = &buf->next;
4876743Smax.romanov@nginx.com 
4877743Smax.romanov@nginx.com             } else {
4878743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
4879743Smax.romanov@nginx.com                 if (free_size < size
4880743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
4881743Smax.romanov@nginx.com                        == NXT_OK)
4882743Smax.romanov@nginx.com                 {
4883743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
4884743Smax.romanov@nginx.com                 }
4885743Smax.romanov@nginx.com             }
4886743Smax.romanov@nginx.com 
4887743Smax.romanov@nginx.com             if (free_size > 0) {
4888743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
4889743Smax.romanov@nginx.com 
4890743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
4891743Smax.romanov@nginx.com 
4892743Smax.romanov@nginx.com                 size -= copy_size;
4893743Smax.romanov@nginx.com                 pos += copy_size;
4894743Smax.romanov@nginx.com 
4895743Smax.romanov@nginx.com                 if (size == 0) {
4896743Smax.romanov@nginx.com                     break;
4897743Smax.romanov@nginx.com                 }
4898743Smax.romanov@nginx.com             }
4899743Smax.romanov@nginx.com 
4900743Smax.romanov@nginx.com             buf = NULL;
4901743Smax.romanov@nginx.com         }
4902216Sigor@sysoev.ru     }
4903216Sigor@sysoev.ru 
4904743Smax.romanov@nginx.com     return out;
4905584Salexander.borisov@nginx.com }
4906584Salexander.borisov@nginx.com 
4907584Salexander.borisov@nginx.com 
490853Sigor@sysoev.ru static void
4909318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
4910318Smax.romanov@nginx.com {
4911615Smax.romanov@nginx.com     nxt_app_t                *app;
4912615Smax.romanov@nginx.com     nxt_bool_t               cancelled, unlinked;
4913615Smax.romanov@nginx.com     nxt_port_t               *port;
4914615Smax.romanov@nginx.com     nxt_timer_t              *timer;
4915615Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
4916615Smax.romanov@nginx.com     nxt_req_app_link_t       *pending_ra;
4917615Smax.romanov@nginx.com     nxt_app_parse_ctx_t      *ar;
4918615Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
4919615Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4920318Smax.romanov@nginx.com 
4921318Smax.romanov@nginx.com     timer = obj;
4922318Smax.romanov@nginx.com 
4923318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
4924318Smax.romanov@nginx.com 
4925431Sigor@sysoev.ru     ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
4926615Smax.romanov@nginx.com     rc = ar->timer_data;
4927615Smax.romanov@nginx.com     app = rc->app;
4928615Smax.romanov@nginx.com 
4929615Smax.romanov@nginx.com     if (app == NULL) {
4930615Smax.romanov@nginx.com         goto generate_error;
4931615Smax.romanov@nginx.com     }
4932615Smax.romanov@nginx.com 
4933615Smax.romanov@nginx.com     port = NULL;
4934615Smax.romanov@nginx.com     pending_ra = NULL;
4935615Smax.romanov@nginx.com 
4936615Smax.romanov@nginx.com     if (rc->app_port != NULL) {
4937615Smax.romanov@nginx.com         port = rc->app_port;
4938615Smax.romanov@nginx.com         rc->app_port = NULL;
4939615Smax.romanov@nginx.com     }
4940615Smax.romanov@nginx.com 
4941615Smax.romanov@nginx.com     if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) {
4942615Smax.romanov@nginx.com         port = rc->ra->app_port;
4943615Smax.romanov@nginx.com         rc->ra->app_port = NULL;
4944615Smax.romanov@nginx.com     }
4945615Smax.romanov@nginx.com 
4946615Smax.romanov@nginx.com     if (port == NULL) {
4947615Smax.romanov@nginx.com         goto generate_error;
4948431Sigor@sysoev.ru     }
4949615Smax.romanov@nginx.com 
4950615Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4951615Smax.romanov@nginx.com 
4952615Smax.romanov@nginx.com     unlinked = nxt_queue_chk_remove(&port->app_link);
4953615Smax.romanov@nginx.com 
4954615Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&port->pending_requests)) {
4955615Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
4956615Smax.romanov@nginx.com 
4957615Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
4958615Smax.romanov@nginx.com                                          link_port_pending);
4959615Smax.romanov@nginx.com 
4960615Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
4961615Smax.romanov@nginx.com 
4962615Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pending request #%uD found",
4963615Smax.romanov@nginx.com                   &app->name, pending_ra->stream);
4964615Smax.romanov@nginx.com 
4965615Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info,
4966615Smax.romanov@nginx.com                                           pending_ra->stream);
4967615Smax.romanov@nginx.com 
4968615Smax.romanov@nginx.com         if (cancelled) {
4969615Smax.romanov@nginx.com             nxt_router_ra_inc_use(pending_ra);
4970615Smax.romanov@nginx.com 
4971615Smax.romanov@nginx.com             state.ra = pending_ra;
4972615Smax.romanov@nginx.com             state.app = app;
4973615Smax.romanov@nginx.com 
4974615Smax.romanov@nginx.com             nxt_router_port_select(task, &state);
4975615Smax.romanov@nginx.com 
4976615Smax.romanov@nginx.com         } else {
4977615Smax.romanov@nginx.com             pending_ra = NULL;
4978615Smax.romanov@nginx.com         }
4979615Smax.romanov@nginx.com     }
4980615Smax.romanov@nginx.com 
4981615Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4982615Smax.romanov@nginx.com 
4983615Smax.romanov@nginx.com     if (pending_ra != NULL
4984615Smax.romanov@nginx.com         && nxt_router_port_post_select(task, &state) == NXT_OK)
4985615Smax.romanov@nginx.com     {
4986615Smax.romanov@nginx.com         nxt_router_app_prepare_request(task, pending_ra);
4987615Smax.romanov@nginx.com     }
4988615Smax.romanov@nginx.com 
4989615Smax.romanov@nginx.com     nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid);
4990615Smax.romanov@nginx.com 
4991615Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4992615Smax.romanov@nginx.com 
4993615Smax.romanov@nginx.com     nxt_port_use(task, port, unlinked ? -2 : -1);
4994615Smax.romanov@nginx.com 
4995615Smax.romanov@nginx.com generate_error:
4996615Smax.romanov@nginx.com 
4997615Smax.romanov@nginx.com     nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE);
4998615Smax.romanov@nginx.com 
4999615Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
5000318Smax.romanov@nginx.com }
5001