xref: /unit/src/nxt_router.c (revision 1007)
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;
65*1007Salexander.borisov@nginx.com     nxt_http_request_t       *request;
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;
78*1007Salexander.borisov@nginx.com     nxt_http_request_t   *request;
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);
267*1007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
268*1007Salexander.borisov@nginx.com     nxt_http_request_t *r, 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 
285*1007Salexander.borisov@nginx.com static nxt_int_t nxt_router_http_request_done(nxt_task_t *task,
286*1007Salexander.borisov@nginx.com     nxt_http_request_t *r);
287*1007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
288*1007Salexander.borisov@nginx.com     void *data);
289*1007Salexander.borisov@nginx.com 
290119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
29120Sigor@sysoev.ru 
292743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
293743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
294743Smax.romanov@nginx.com 
295743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
296804Svbart@nginx.com     &empty_prefix,
297743Smax.romanov@nginx.com     &http_prefix,
298743Smax.romanov@nginx.com     &http_prefix,
299743Smax.romanov@nginx.com     &http_prefix,
300743Smax.romanov@nginx.com     &http_prefix,
301977Smax.romanov@gmail.com     &empty_prefix,
302216Sigor@sysoev.ru };
303216Sigor@sysoev.ru 
304216Sigor@sysoev.ru 
305662Smax.romanov@nginx.com nxt_port_handlers_t  nxt_router_process_port_handlers = {
306662Smax.romanov@nginx.com     .quit         = nxt_worker_process_quit_handler,
307662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
308662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
309662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
310662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
311662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
312662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
313662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
314662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
315662Smax.romanov@nginx.com };
316662Smax.romanov@nginx.com 
317662Smax.romanov@nginx.com 
31820Sigor@sysoev.ru nxt_int_t
319141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
32020Sigor@sysoev.ru {
321141Smax.romanov@nginx.com     nxt_int_t      ret;
322662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
323141Smax.romanov@nginx.com     nxt_router_t   *router;
324141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
325141Smax.romanov@nginx.com 
326141Smax.romanov@nginx.com     rt = task->thread->runtime;
32753Sigor@sysoev.ru 
328771Sigor@sysoev.ru #if (NXT_TLS)
329771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
330771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
331771Sigor@sysoev.ru         return NXT_ERROR;
332771Sigor@sysoev.ru     }
333771Sigor@sysoev.ru 
334771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
335771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
336771Sigor@sysoev.ru         return ret;
337771Sigor@sysoev.ru     }
338771Sigor@sysoev.ru #endif
339771Sigor@sysoev.ru 
340431Sigor@sysoev.ru     ret = nxt_http_init(task, rt);
34188Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
34288Smax.romanov@nginx.com         return ret;
34388Smax.romanov@nginx.com     }
34488Smax.romanov@nginx.com 
34553Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
34653Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
34753Sigor@sysoev.ru         return NXT_ERROR;
34853Sigor@sysoev.ru     }
34953Sigor@sysoev.ru 
35053Sigor@sysoev.ru     nxt_queue_init(&router->engines);
35153Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
352133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
35353Sigor@sysoev.ru 
354119Smax.romanov@nginx.com     nxt_router = router;
355119Smax.romanov@nginx.com 
356662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
357662Smax.romanov@nginx.com     if (controller_port != NULL) {
358662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
359662Smax.romanov@nginx.com     }
360662Smax.romanov@nginx.com 
361115Sigor@sysoev.ru     return NXT_OK;
362115Sigor@sysoev.ru }
363115Sigor@sysoev.ru 
364115Sigor@sysoev.ru 
365343Smax.romanov@nginx.com static void
366662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
367662Smax.romanov@nginx.com {
368662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
369662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
370662Smax.romanov@nginx.com }
371662Smax.romanov@nginx.com 
372662Smax.romanov@nginx.com 
373662Smax.romanov@nginx.com static void
374507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
375507Smax.romanov@nginx.com     void *data)
376167Smax.romanov@nginx.com {
377343Smax.romanov@nginx.com     size_t         size;
378343Smax.romanov@nginx.com     uint32_t       stream;
379430Sigor@sysoev.ru     nxt_mp_t       *mp;
380648Svbart@nginx.com     nxt_int_t      ret;
381343Smax.romanov@nginx.com     nxt_app_t      *app;
382343Smax.romanov@nginx.com     nxt_buf_t      *b;
383343Smax.romanov@nginx.com     nxt_port_t     *main_port;
384343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
385343Smax.romanov@nginx.com 
386343Smax.romanov@nginx.com     app = data;
387167Smax.romanov@nginx.com 
388167Smax.romanov@nginx.com     rt = task->thread->runtime;
389240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
390167Smax.romanov@nginx.com 
391507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
392343Smax.romanov@nginx.com 
393343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
394343Smax.romanov@nginx.com 
395343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
396343Smax.romanov@nginx.com 
397343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
398343Smax.romanov@nginx.com         goto failed;
399167Smax.romanov@nginx.com     }
400167Smax.romanov@nginx.com 
401343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
402343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
403343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
404343Smax.romanov@nginx.com 
405753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
406753Smax.romanov@nginx.com 
407343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
408343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
409343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
410753Smax.romanov@nginx.com                                            -1, app->joint);
411343Smax.romanov@nginx.com 
412343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
413753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
414753Smax.romanov@nginx.com 
415343Smax.romanov@nginx.com         goto failed;
416343Smax.romanov@nginx.com     }
417343Smax.romanov@nginx.com 
418648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
419648Svbart@nginx.com                                 stream, port->id, b);
420648Svbart@nginx.com 
421648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
422648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
423753Smax.romanov@nginx.com 
424753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
425753Smax.romanov@nginx.com 
426648Svbart@nginx.com         goto failed;
427648Svbart@nginx.com     }
428343Smax.romanov@nginx.com 
429753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
430753Smax.romanov@nginx.com 
431343Smax.romanov@nginx.com     return;
432343Smax.romanov@nginx.com 
433343Smax.romanov@nginx.com failed:
434343Smax.romanov@nginx.com 
435648Svbart@nginx.com     if (b != NULL) {
436648Svbart@nginx.com         mp = b->data;
437648Svbart@nginx.com         nxt_mp_free(mp, b);
438648Svbart@nginx.com         nxt_mp_release(mp);
439648Svbart@nginx.com     }
440648Svbart@nginx.com 
441343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
442343Smax.romanov@nginx.com 
443507Smax.romanov@nginx.com     app->pending_processes--;
444343Smax.romanov@nginx.com 
445343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
446343Smax.romanov@nginx.com 
447343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
448167Smax.romanov@nginx.com }
449167Smax.romanov@nginx.com 
450167Smax.romanov@nginx.com 
451753Smax.romanov@nginx.com static void
452753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
453753Smax.romanov@nginx.com {
454753Smax.romanov@nginx.com     app_joint->use_count += i;
455753Smax.romanov@nginx.com 
456753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
457753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
458753Smax.romanov@nginx.com 
459753Smax.romanov@nginx.com         nxt_free(app_joint);
460753Smax.romanov@nginx.com     }
461753Smax.romanov@nginx.com }
462753Smax.romanov@nginx.com 
463753Smax.romanov@nginx.com 
464343Smax.romanov@nginx.com static nxt_int_t
465507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
466141Smax.romanov@nginx.com {
467343Smax.romanov@nginx.com     nxt_int_t      res;
468343Smax.romanov@nginx.com     nxt_port_t     *router_port;
469343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
470343Smax.romanov@nginx.com 
471343Smax.romanov@nginx.com     rt = task->thread->runtime;
472343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
473343Smax.romanov@nginx.com 
474343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
475343Smax.romanov@nginx.com 
476507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
477343Smax.romanov@nginx.com                         app);
478343Smax.romanov@nginx.com 
479343Smax.romanov@nginx.com     if (res == NXT_OK) {
480343Smax.romanov@nginx.com         return res;
481318Smax.romanov@nginx.com     }
482318Smax.romanov@nginx.com 
483343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
484343Smax.romanov@nginx.com 
485507Smax.romanov@nginx.com     app->pending_processes--;
486343Smax.romanov@nginx.com 
487343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
488343Smax.romanov@nginx.com 
489343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
490343Smax.romanov@nginx.com 
491343Smax.romanov@nginx.com     return NXT_ERROR;
492318Smax.romanov@nginx.com }
493318Smax.romanov@nginx.com 
494318Smax.romanov@nginx.com 
495351Smax.romanov@nginx.com nxt_inline void
496351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
497351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
498167Smax.romanov@nginx.com {
499318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
500351Smax.romanov@nginx.com 
501318Smax.romanov@nginx.com     engine = task->thread->engine;
502167Smax.romanov@nginx.com 
503167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
504167Smax.romanov@nginx.com 
505318Smax.romanov@nginx.com     ra->stream = rc->stream;
506425Smax.romanov@nginx.com     ra->use_count = 1;
507167Smax.romanov@nginx.com     ra->rc = rc;
508318Smax.romanov@nginx.com     rc->ra = ra;
509318Smax.romanov@nginx.com     ra->reply_port = engine->port;
510*1007Salexander.borisov@nginx.com     ra->request = rc->request;
511167Smax.romanov@nginx.com 
512167Smax.romanov@nginx.com     ra->work.handler = NULL;
513318Smax.romanov@nginx.com     ra->work.task = &engine->task;
514167Smax.romanov@nginx.com     ra->work.obj = ra;
515318Smax.romanov@nginx.com     ra->work.data = engine;
516351Smax.romanov@nginx.com }
517351Smax.romanov@nginx.com 
518351Smax.romanov@nginx.com 
519351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
520351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
521351Smax.romanov@nginx.com {
522351Smax.romanov@nginx.com     nxt_mp_t            *mp;
523351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
524351Smax.romanov@nginx.com 
525425Smax.romanov@nginx.com     if (ra_src->mem_pool != NULL) {
526425Smax.romanov@nginx.com         return ra_src;
527425Smax.romanov@nginx.com     }
528425Smax.romanov@nginx.com 
529*1007Salexander.borisov@nginx.com     mp = ra_src->request->mem_pool;
530351Smax.romanov@nginx.com 
531430Sigor@sysoev.ru     ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t));
532351Smax.romanov@nginx.com 
533351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
534351Smax.romanov@nginx.com 
535351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
536351Smax.romanov@nginx.com         ra_src->rc = NULL;
537351Smax.romanov@nginx.com 
538351Smax.romanov@nginx.com         return NULL;
539351Smax.romanov@nginx.com     }
540351Smax.romanov@nginx.com 
541430Sigor@sysoev.ru     nxt_mp_retain(mp);
542430Sigor@sysoev.ru 
543351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
544351Smax.romanov@nginx.com 
545351Smax.romanov@nginx.com     ra->mem_pool = mp;
546167Smax.romanov@nginx.com 
547167Smax.romanov@nginx.com     return ra;
548167Smax.romanov@nginx.com }
549167Smax.romanov@nginx.com 
550167Smax.romanov@nginx.com 
551423Smax.romanov@nginx.com nxt_inline nxt_bool_t
552423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
553423Smax.romanov@nginx.com     uint32_t stream)
554423Smax.romanov@nginx.com {
555423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
556423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
557423Smax.romanov@nginx.com 
558423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
559423Smax.romanov@nginx.com         return 0;
560423Smax.romanov@nginx.com     }
561423Smax.romanov@nginx.com 
562423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
563423Smax.romanov@nginx.com                                               stream);
564423Smax.romanov@nginx.com 
565423Smax.romanov@nginx.com     if (cancelled) {
566423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
567423Smax.romanov@nginx.com     }
568423Smax.romanov@nginx.com 
569423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
570423Smax.romanov@nginx.com         next = b->next;
571423Smax.romanov@nginx.com 
572423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
573423Smax.romanov@nginx.com 
574423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
575423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
576423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
577423Smax.romanov@nginx.com         }
578423Smax.romanov@nginx.com     }
579423Smax.romanov@nginx.com 
580423Smax.romanov@nginx.com     msg_info->buf = NULL;
581423Smax.romanov@nginx.com 
582423Smax.romanov@nginx.com     return cancelled;
583423Smax.romanov@nginx.com }
584423Smax.romanov@nginx.com 
585423Smax.romanov@nginx.com 
586167Smax.romanov@nginx.com static void
587425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra);
588425Smax.romanov@nginx.com 
589425Smax.romanov@nginx.com 
590425Smax.romanov@nginx.com static void
591425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data)
592167Smax.romanov@nginx.com {
593425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
594425Smax.romanov@nginx.com 
595425Smax.romanov@nginx.com     ra = obj;
596425Smax.romanov@nginx.com 
597425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
598425Smax.romanov@nginx.com 
599425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
600425Smax.romanov@nginx.com }
601425Smax.romanov@nginx.com 
602425Smax.romanov@nginx.com 
603425Smax.romanov@nginx.com static void
604425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra)
605425Smax.romanov@nginx.com {
606343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
607343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
608318Smax.romanov@nginx.com 
609425Smax.romanov@nginx.com     engine = ra->work.data;
610318Smax.romanov@nginx.com 
611343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
612425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
613425Smax.romanov@nginx.com 
614425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_update_peer_handler;
615318Smax.romanov@nginx.com         ra->work.task = &engine->task;
616318Smax.romanov@nginx.com         ra->work.next = NULL;
617318Smax.romanov@nginx.com 
618425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post update peer to %p",
619318Smax.romanov@nginx.com                   ra->stream, engine);
620318Smax.romanov@nginx.com 
621318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
622318Smax.romanov@nginx.com 
623318Smax.romanov@nginx.com         return;
624318Smax.romanov@nginx.com     }
625318Smax.romanov@nginx.com 
626425Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD update peer", ra->stream);
627425Smax.romanov@nginx.com 
628425Smax.romanov@nginx.com     rc = ra->rc;
629425Smax.romanov@nginx.com 
630425Smax.romanov@nginx.com     if (rc != NULL && ra->app_port != NULL) {
631425Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid);
632425Smax.romanov@nginx.com     }
633425Smax.romanov@nginx.com 
634425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
635425Smax.romanov@nginx.com }
636425Smax.romanov@nginx.com 
637425Smax.romanov@nginx.com 
638425Smax.romanov@nginx.com static void
639425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra)
640425Smax.romanov@nginx.com {
641431Sigor@sysoev.ru     nxt_mp_t                *mp;
642431Sigor@sysoev.ru     nxt_req_conn_link_t     *rc;
643425Smax.romanov@nginx.com 
644425Smax.romanov@nginx.com     nxt_assert(task->thread->engine == ra->work.data);
645425Smax.romanov@nginx.com     nxt_assert(ra->use_count == 0);
646425Smax.romanov@nginx.com 
647343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
648343Smax.romanov@nginx.com 
649343Smax.romanov@nginx.com     rc = ra->rc;
650343Smax.romanov@nginx.com 
651343Smax.romanov@nginx.com     if (rc != NULL) {
652423Smax.romanov@nginx.com         if (nxt_slow_path(ra->err_code != 0)) {
653*1007Salexander.borisov@nginx.com             nxt_http_request_error(task, rc->request, ra->err_code);
654423Smax.romanov@nginx.com 
655423Smax.romanov@nginx.com         } else {
656423Smax.romanov@nginx.com             rc->app_port = ra->app_port;
657423Smax.romanov@nginx.com             rc->msg_info = ra->msg_info;
658423Smax.romanov@nginx.com 
659425Smax.romanov@nginx.com             if (rc->app->timeout != 0) {
660*1007Salexander.borisov@nginx.com                 rc->request->timer.handler = nxt_router_app_timeout;
661*1007Salexander.borisov@nginx.com                 rc->request->timer_data = rc;
662*1007Salexander.borisov@nginx.com                 nxt_timer_add(task->thread->engine, &rc->request->timer,
663425Smax.romanov@nginx.com                               rc->app->timeout);
664425Smax.romanov@nginx.com             }
665425Smax.romanov@nginx.com 
666423Smax.romanov@nginx.com             ra->app_port = NULL;
667423Smax.romanov@nginx.com             ra->msg_info.buf = NULL;
668423Smax.romanov@nginx.com         }
669343Smax.romanov@nginx.com 
670343Smax.romanov@nginx.com         rc->ra = NULL;
671343Smax.romanov@nginx.com         ra->rc = NULL;
672343Smax.romanov@nginx.com     }
673343Smax.romanov@nginx.com 
674343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
675343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
676343Smax.romanov@nginx.com 
677343Smax.romanov@nginx.com         ra->app_port = NULL;
678167Smax.romanov@nginx.com     }
679167Smax.romanov@nginx.com 
680423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
681423Smax.romanov@nginx.com 
682430Sigor@sysoev.ru     mp = ra->mem_pool;
683430Sigor@sysoev.ru 
684430Sigor@sysoev.ru     if (mp != NULL) {
685430Sigor@sysoev.ru         nxt_mp_free(mp, ra);
686430Sigor@sysoev.ru         nxt_mp_release(mp);
687351Smax.romanov@nginx.com     }
688167Smax.romanov@nginx.com }
689167Smax.romanov@nginx.com 
690167Smax.romanov@nginx.com 
691425Smax.romanov@nginx.com static void
692425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data)
693425Smax.romanov@nginx.com {
694425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
695425Smax.romanov@nginx.com 
696425Smax.romanov@nginx.com     ra = obj;
697425Smax.romanov@nginx.com 
698425Smax.romanov@nginx.com     nxt_assert(ra->work.data == data);
699425Smax.romanov@nginx.com 
700425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, -1);
701425Smax.romanov@nginx.com 
702425Smax.romanov@nginx.com     nxt_router_ra_release(task, ra);
703425Smax.romanov@nginx.com }
704425Smax.romanov@nginx.com 
705425Smax.romanov@nginx.com 
706425Smax.romanov@nginx.com static void
707425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i)
708425Smax.romanov@nginx.com {
709425Smax.romanov@nginx.com     int                 c;
710425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
711425Smax.romanov@nginx.com 
712425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, i);
713425Smax.romanov@nginx.com 
714425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
715425Smax.romanov@nginx.com         engine = ra->work.data;
716425Smax.romanov@nginx.com 
717425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
718425Smax.romanov@nginx.com             nxt_router_ra_release(task, ra);
719425Smax.romanov@nginx.com 
720425Smax.romanov@nginx.com             return;
721425Smax.romanov@nginx.com         }
722425Smax.romanov@nginx.com 
723425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
724425Smax.romanov@nginx.com 
725425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release_handler;
726425Smax.romanov@nginx.com         ra->work.task = &engine->task;
727425Smax.romanov@nginx.com         ra->work.next = NULL;
728425Smax.romanov@nginx.com 
729425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
730425Smax.romanov@nginx.com                   ra->stream, engine);
731425Smax.romanov@nginx.com 
732425Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
733425Smax.romanov@nginx.com     }
734425Smax.romanov@nginx.com }
735425Smax.romanov@nginx.com 
736425Smax.romanov@nginx.com 
737423Smax.romanov@nginx.com nxt_inline void
738521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str)
739345Smax.romanov@nginx.com {
740423Smax.romanov@nginx.com     ra->app_port = NULL;
741423Smax.romanov@nginx.com     ra->err_code = code;
742423Smax.romanov@nginx.com     ra->err_str = str;
743345Smax.romanov@nginx.com }
744345Smax.romanov@nginx.com 
745345Smax.romanov@nginx.com 
746427Smax.romanov@nginx.com nxt_inline void
747427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
748427Smax.romanov@nginx.com {
749427Smax.romanov@nginx.com     nxt_queue_insert_tail(&ra->app_port->pending_requests,
750427Smax.romanov@nginx.com                           &ra->link_port_pending);
751427Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &ra->link_app_pending);
752427Smax.romanov@nginx.com 
753427Smax.romanov@nginx.com     nxt_router_ra_inc_use(ra);
754427Smax.romanov@nginx.com 
755427Smax.romanov@nginx.com     ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout;
756427Smax.romanov@nginx.com 
757427Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream);
758427Smax.romanov@nginx.com }
759427Smax.romanov@nginx.com 
760427Smax.romanov@nginx.com 
761425Smax.romanov@nginx.com nxt_inline nxt_bool_t
762425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
763425Smax.romanov@nginx.com {
764425Smax.romanov@nginx.com     if (lnk->next != NULL) {
765425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
766425Smax.romanov@nginx.com 
767425Smax.romanov@nginx.com         lnk->next = NULL;
768425Smax.romanov@nginx.com 
769425Smax.romanov@nginx.com         return 1;
770425Smax.romanov@nginx.com     }
771425Smax.romanov@nginx.com 
772425Smax.romanov@nginx.com     return 0;
773425Smax.romanov@nginx.com }
774425Smax.romanov@nginx.com 
775425Smax.romanov@nginx.com 
776343Smax.romanov@nginx.com nxt_inline void
777343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
778343Smax.romanov@nginx.com {
779425Smax.romanov@nginx.com     int                 ra_use_delta;
780343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
781343Smax.romanov@nginx.com 
782343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
783343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
784343Smax.romanov@nginx.com 
785343Smax.romanov@nginx.com         rc->app_port = NULL;
786343Smax.romanov@nginx.com     }
787343Smax.romanov@nginx.com 
788423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &rc->msg_info, rc->stream);
789423Smax.romanov@nginx.com 
790343Smax.romanov@nginx.com     ra = rc->ra;
791343Smax.romanov@nginx.com 
792343Smax.romanov@nginx.com     if (ra != NULL) {
793343Smax.romanov@nginx.com         rc->ra = NULL;
794343Smax.romanov@nginx.com         ra->rc = NULL;
795343Smax.romanov@nginx.com 
796425Smax.romanov@nginx.com         ra_use_delta = 0;
797425Smax.romanov@nginx.com 
798343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
799343Smax.romanov@nginx.com 
800425Smax.romanov@nginx.com         if (ra->link_app_requests.next == NULL
801427Smax.romanov@nginx.com             && ra->link_port_pending.next == NULL
802427Smax.romanov@nginx.com             && ra->link_app_pending.next == NULL)
803425Smax.romanov@nginx.com         {
804425Smax.romanov@nginx.com             ra = NULL;
805343Smax.romanov@nginx.com 
806343Smax.romanov@nginx.com         } else {
807425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests);
808425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending);
809427Smax.romanov@nginx.com             nxt_queue_chk_remove(&ra->link_app_pending);
810343Smax.romanov@nginx.com         }
811343Smax.romanov@nginx.com 
812343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
813425Smax.romanov@nginx.com 
814425Smax.romanov@nginx.com         if (ra != NULL) {
815425Smax.romanov@nginx.com             nxt_router_ra_use(task, ra, ra_use_delta);
816425Smax.romanov@nginx.com         }
817343Smax.romanov@nginx.com     }
818343Smax.romanov@nginx.com 
819343Smax.romanov@nginx.com     if (rc->app != NULL) {
820343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
821343Smax.romanov@nginx.com 
822343Smax.romanov@nginx.com         rc->app = NULL;
823343Smax.romanov@nginx.com     }
824343Smax.romanov@nginx.com 
825*1007Salexander.borisov@nginx.com     if (rc->request != NULL) {
826*1007Salexander.borisov@nginx.com         rc->request->timer_data = NULL;
827*1007Salexander.borisov@nginx.com 
828*1007Salexander.borisov@nginx.com         nxt_router_http_request_done(task, rc->request);
829*1007Salexander.borisov@nginx.com 
830*1007Salexander.borisov@nginx.com         rc->request = NULL;
831346Smax.romanov@nginx.com     }
832343Smax.romanov@nginx.com }
833343Smax.romanov@nginx.com 
834343Smax.romanov@nginx.com 
835141Smax.romanov@nginx.com void
836141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
837141Smax.romanov@nginx.com {
838141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
839141Smax.romanov@nginx.com 
840670Smax.romanov@nginx.com     if (msg->u.new_port != NULL
841670Smax.romanov@nginx.com         && msg->u.new_port->type == NXT_PROCESS_CONTROLLER)
842670Smax.romanov@nginx.com     {
843662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
844662Smax.romanov@nginx.com     }
845662Smax.romanov@nginx.com 
846192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
847141Smax.romanov@nginx.com         return;
848141Smax.romanov@nginx.com     }
849141Smax.romanov@nginx.com 
850426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
851426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
852347Smax.romanov@nginx.com     {
853192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
854141Smax.romanov@nginx.com     }
855192Smax.romanov@nginx.com 
856192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
857141Smax.romanov@nginx.com }
858141Smax.romanov@nginx.com 
859141Smax.romanov@nginx.com 
860139Sigor@sysoev.ru void
861139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
862115Sigor@sysoev.ru {
863198Sigor@sysoev.ru     nxt_int_t               ret;
864139Sigor@sysoev.ru     nxt_buf_t               *b;
865139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
866139Sigor@sysoev.ru 
867139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
868139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
869139Sigor@sysoev.ru         return;
87053Sigor@sysoev.ru     }
87153Sigor@sysoev.ru 
872494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
873423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
874493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
875423Smax.romanov@nginx.com 
876591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
877139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
878139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
879198Sigor@sysoev.ru                                        msg->port_msg.pid,
880198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
881198Sigor@sysoev.ru 
882779Smax.romanov@nginx.com     if (nxt_slow_path(tmcf->port == NULL)) {
883779Smax.romanov@nginx.com         nxt_alert(task, "reply port not found");
884779Smax.romanov@nginx.com 
885779Smax.romanov@nginx.com         return;
886779Smax.romanov@nginx.com     }
887779Smax.romanov@nginx.com 
888779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
889779Smax.romanov@nginx.com 
890591Sigor@sysoev.ru     b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool,
891591Sigor@sysoev.ru                                msg->buf, msg->size);
892551Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
893551Smax.romanov@nginx.com         nxt_router_conf_error(task, tmcf);
894551Smax.romanov@nginx.com 
895551Smax.romanov@nginx.com         return;
896551Smax.romanov@nginx.com     }
897551Smax.romanov@nginx.com 
898198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
899198Sigor@sysoev.ru 
900198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
901198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
902198Sigor@sysoev.ru 
903198Sigor@sysoev.ru     } else {
904198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
905139Sigor@sysoev.ru     }
90653Sigor@sysoev.ru }
90753Sigor@sysoev.ru 
90853Sigor@sysoev.ru 
909347Smax.romanov@nginx.com static void
910507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
911507Smax.romanov@nginx.com     void *data)
912347Smax.romanov@nginx.com {
913347Smax.romanov@nginx.com     union {
914347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
915347Smax.romanov@nginx.com         void       *data;
916347Smax.romanov@nginx.com     } u;
917347Smax.romanov@nginx.com 
918347Smax.romanov@nginx.com     u.data = data;
919347Smax.romanov@nginx.com 
920347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
921347Smax.romanov@nginx.com }
922347Smax.romanov@nginx.com 
923347Smax.romanov@nginx.com 
924192Smax.romanov@nginx.com void
925192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
926192Smax.romanov@nginx.com {
927347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
928318Smax.romanov@nginx.com 
929192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
930192Smax.romanov@nginx.com 
931192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
932192Smax.romanov@nginx.com         return;
933192Smax.romanov@nginx.com     }
934192Smax.romanov@nginx.com 
935318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
936318Smax.romanov@nginx.com     {
937507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
938347Smax.romanov@nginx.com                       msg->u.data);
939318Smax.romanov@nginx.com     }
940318Smax.romanov@nginx.com     nxt_queue_loop;
941318Smax.romanov@nginx.com 
942192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
943192Smax.romanov@nginx.com 
944192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
945192Smax.romanov@nginx.com }
946192Smax.romanov@nginx.com 
947192Smax.romanov@nginx.com 
94853Sigor@sysoev.ru static nxt_router_temp_conf_t *
949139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
95053Sigor@sysoev.ru {
95165Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
95253Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
95353Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
95453Sigor@sysoev.ru 
95565Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
95653Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
95753Sigor@sysoev.ru         return NULL;
95853Sigor@sysoev.ru     }
95953Sigor@sysoev.ru 
96065Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
96153Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
96253Sigor@sysoev.ru         goto fail;
96353Sigor@sysoev.ru     }
96453Sigor@sysoev.ru 
96553Sigor@sysoev.ru     rtcf->mem_pool = mp;
96653Sigor@sysoev.ru 
96765Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
96853Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
96953Sigor@sysoev.ru         goto fail;
97053Sigor@sysoev.ru     }
97153Sigor@sysoev.ru 
97265Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
97353Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
97453Sigor@sysoev.ru         goto temp_fail;
97553Sigor@sysoev.ru     }
97653Sigor@sysoev.ru 
97753Sigor@sysoev.ru     tmcf->mem_pool = tmp;
978591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
979139Sigor@sysoev.ru     tmcf->count = 1;
980139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
98153Sigor@sysoev.ru 
98253Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
98353Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
98453Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
98553Sigor@sysoev.ru         goto temp_fail;
98653Sigor@sysoev.ru     }
98753Sigor@sysoev.ru 
98853Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
98953Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
99053Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
99153Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
99253Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
993416Smax.romanov@nginx.com 
994774Svbart@nginx.com #if (NXT_TLS)
995774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
996774Svbart@nginx.com #endif
997774Svbart@nginx.com 
998133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
999133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
100053Sigor@sysoev.ru 
100153Sigor@sysoev.ru     return tmcf;
100253Sigor@sysoev.ru 
100353Sigor@sysoev.ru temp_fail:
100453Sigor@sysoev.ru 
100565Sigor@sysoev.ru     nxt_mp_destroy(tmp);
100653Sigor@sysoev.ru 
100753Sigor@sysoev.ru fail:
100853Sigor@sysoev.ru 
100965Sigor@sysoev.ru     nxt_mp_destroy(mp);
101053Sigor@sysoev.ru 
101153Sigor@sysoev.ru     return NULL;
101253Sigor@sysoev.ru }
101353Sigor@sysoev.ru 
101453Sigor@sysoev.ru 
1015507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1016507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
1017507Smax.romanov@nginx.com {
1018507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
1019507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
1020507Smax.romanov@nginx.com }
1021507Smax.romanov@nginx.com 
1022507Smax.romanov@nginx.com 
1023507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1024507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
1025507Smax.romanov@nginx.com {
1026507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
1027507Smax.romanov@nginx.com             < app->spare_processes;
1028507Smax.romanov@nginx.com }
1029507Smax.romanov@nginx.com 
1030507Smax.romanov@nginx.com 
1031198Sigor@sysoev.ru static void
1032198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1033139Sigor@sysoev.ru {
1034139Sigor@sysoev.ru     nxt_int_t                    ret;
1035507Smax.romanov@nginx.com     nxt_app_t                    *app;
1036139Sigor@sysoev.ru     nxt_router_t                 *router;
1037139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1038198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1039198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1040630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1041198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1042139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1043774Svbart@nginx.com #if (NXT_TLS)
1044774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
1045774Svbart@nginx.com #endif
1046139Sigor@sysoev.ru 
1047198Sigor@sysoev.ru     tmcf = obj;
1048198Sigor@sysoev.ru 
1049198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
1050198Sigor@sysoev.ru 
1051198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
1052198Sigor@sysoev.ru         nxt_queue_remove(qlk);
1053198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
1054198Sigor@sysoev.ru 
1055198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1056198Sigor@sysoev.ru 
1057198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1058198Sigor@sysoev.ru 
1059198Sigor@sysoev.ru         return;
1060139Sigor@sysoev.ru     }
1061139Sigor@sysoev.ru 
1062774Svbart@nginx.com #if (NXT_TLS)
1063774Svbart@nginx.com     qlk = nxt_queue_first(&tmcf->tls);
1064774Svbart@nginx.com 
1065774Svbart@nginx.com     if (qlk != nxt_queue_tail(&tmcf->tls)) {
1066774Svbart@nginx.com         nxt_queue_remove(qlk);
1067774Svbart@nginx.com 
1068774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1069774Svbart@nginx.com 
1070774Svbart@nginx.com         nxt_router_tls_rpc_create(task, tmcf, tls);
1071774Svbart@nginx.com         return;
1072774Svbart@nginx.com     }
1073774Svbart@nginx.com #endif
1074774Svbart@nginx.com 
1075507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1076507Smax.romanov@nginx.com 
1077507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1078507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1079507Smax.romanov@nginx.com             return;
1080507Smax.romanov@nginx.com         }
1081507Smax.romanov@nginx.com 
1082507Smax.romanov@nginx.com     } nxt_queue_loop;
1083507Smax.romanov@nginx.com 
1084630Svbart@nginx.com     rtcf = tmcf->router_conf;
1085630Svbart@nginx.com 
1086630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1087630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1088630Svbart@nginx.com         return;
1089630Svbart@nginx.com     }
1090630Svbart@nginx.com 
1091139Sigor@sysoev.ru     rt = task->thread->runtime;
1092139Sigor@sysoev.ru 
1093139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1094139Sigor@sysoev.ru 
1095630Svbart@nginx.com     router = rtcf->router;
1096198Sigor@sysoev.ru 
1097139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1098139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1099198Sigor@sysoev.ru         goto fail;
1100139Sigor@sysoev.ru     }
1101139Sigor@sysoev.ru 
1102139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1103139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1104198Sigor@sysoev.ru         goto fail;
1105139Sigor@sysoev.ru     }
1106139Sigor@sysoev.ru 
1107343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1108139Sigor@sysoev.ru 
1109315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1110139Sigor@sysoev.ru 
1111139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
1112139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
1113139Sigor@sysoev.ru 
1114630Svbart@nginx.com     router->access_log = rtcf->access_log;
1115630Svbart@nginx.com 
1116198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1117198Sigor@sysoev.ru 
1118198Sigor@sysoev.ru     return;
1119198Sigor@sysoev.ru 
1120198Sigor@sysoev.ru fail:
1121198Sigor@sysoev.ru 
1122198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1123198Sigor@sysoev.ru 
1124198Sigor@sysoev.ru     return;
1125139Sigor@sysoev.ru }
1126139Sigor@sysoev.ru 
1127139Sigor@sysoev.ru 
1128139Sigor@sysoev.ru static void
1129139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1130139Sigor@sysoev.ru {
1131153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1132153Sigor@sysoev.ru 
1133153Sigor@sysoev.ru     job = obj;
1134153Sigor@sysoev.ru 
1135198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1136139Sigor@sysoev.ru }
1137139Sigor@sysoev.ru 
1138139Sigor@sysoev.ru 
1139139Sigor@sysoev.ru static void
1140198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1141139Sigor@sysoev.ru {
1142139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
1143139Sigor@sysoev.ru 
1144139Sigor@sysoev.ru     if (--tmcf->count == 0) {
1145193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1146139Sigor@sysoev.ru     }
1147139Sigor@sysoev.ru }
1148139Sigor@sysoev.ru 
1149139Sigor@sysoev.ru 
1150139Sigor@sysoev.ru static void
1151139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1152139Sigor@sysoev.ru {
1153507Smax.romanov@nginx.com     nxt_app_t          *app;
1154568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1155148Sigor@sysoev.ru     nxt_socket_t       s;
1156149Sigor@sysoev.ru     nxt_router_t       *router;
1157148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1158148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1159630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1160148Sigor@sysoev.ru 
1161564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1162198Sigor@sysoev.ru 
1163148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
1164148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
1165148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1166148Sigor@sysoev.ru     {
1167148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1168359Sigor@sysoev.ru         s = skcf->listen->socket;
1169148Sigor@sysoev.ru 
1170148Sigor@sysoev.ru         if (s != -1) {
1171148Sigor@sysoev.ru             nxt_socket_close(task, s);
1172148Sigor@sysoev.ru         }
1173148Sigor@sysoev.ru 
1174359Sigor@sysoev.ru         nxt_free(skcf->listen);
1175148Sigor@sysoev.ru     }
1176148Sigor@sysoev.ru 
1177568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
1178568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->updating);
1179568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->pending);
1180568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->creating);
1181568Smax.romanov@nginx.com 
1182964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1183964Sigor@sysoev.ru 
1184964Sigor@sysoev.ru     nxt_http_routes_cleanup(task, rtcf->routes);
1185964Sigor@sysoev.ru 
1186568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1187568Smax.romanov@nginx.com 
1188964Sigor@sysoev.ru         if (skcf->pass != NULL) {
1189964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
1190568Smax.romanov@nginx.com         }
1191568Smax.romanov@nginx.com 
1192568Smax.romanov@nginx.com     } nxt_queue_loop;
1193568Smax.romanov@nginx.com 
1194507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1195507Smax.romanov@nginx.com 
1196753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1197507Smax.romanov@nginx.com 
1198507Smax.romanov@nginx.com     } nxt_queue_loop;
1199507Smax.romanov@nginx.com 
1200630Svbart@nginx.com     router = rtcf->router;
1201149Sigor@sysoev.ru 
1202149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1203149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1204149Sigor@sysoev.ru 
1205416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1206416Smax.romanov@nginx.com 
1207148Sigor@sysoev.ru     // TODO: new engines and threads
1208148Sigor@sysoev.ru 
1209630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1210630Svbart@nginx.com 
1211630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1212139Sigor@sysoev.ru 
1213193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1214139Sigor@sysoev.ru }
1215139Sigor@sysoev.ru 
1216139Sigor@sysoev.ru 
1217139Sigor@sysoev.ru static void
1218139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1219193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1220139Sigor@sysoev.ru {
1221193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1222779Smax.romanov@nginx.com 
1223779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1224779Smax.romanov@nginx.com 
1225779Smax.romanov@nginx.com     tmcf->port = NULL;
1226139Sigor@sysoev.ru }
1227139Sigor@sysoev.ru 
1228139Sigor@sysoev.ru 
1229115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1230115Sigor@sysoev.ru     {
1231133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1232115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1233115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1234115Sigor@sysoev.ru     },
1235115Sigor@sysoev.ru };
1236115Sigor@sysoev.ru 
1237115Sigor@sysoev.ru 
1238133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1239115Sigor@sysoev.ru     {
1240133Sigor@sysoev.ru         nxt_string("type"),
1241115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1242133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1243115Sigor@sysoev.ru     },
1244115Sigor@sysoev.ru 
1245115Sigor@sysoev.ru     {
1246507Smax.romanov@nginx.com         nxt_string("limits"),
1247507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1248507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1249133Sigor@sysoev.ru     },
1250318Smax.romanov@nginx.com 
1251318Smax.romanov@nginx.com     {
1252507Smax.romanov@nginx.com         nxt_string("processes"),
1253507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1254507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1255507Smax.romanov@nginx.com     },
1256507Smax.romanov@nginx.com 
1257507Smax.romanov@nginx.com     {
1258507Smax.romanov@nginx.com         nxt_string("processes"),
1259318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1260507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1261318Smax.romanov@nginx.com     },
1262318Smax.romanov@nginx.com };
1263318Smax.romanov@nginx.com 
1264318Smax.romanov@nginx.com 
1265318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1266318Smax.romanov@nginx.com     {
1267318Smax.romanov@nginx.com         nxt_string("timeout"),
1268318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1269318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1270318Smax.romanov@nginx.com     },
1271318Smax.romanov@nginx.com 
1272318Smax.romanov@nginx.com     {
1273427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1274427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1275427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1276427Smax.romanov@nginx.com     },
1277427Smax.romanov@nginx.com 
1278427Smax.romanov@nginx.com     {
1279318Smax.romanov@nginx.com         nxt_string("requests"),
1280318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1281318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1282318Smax.romanov@nginx.com     },
1283133Sigor@sysoev.ru };
1284133Sigor@sysoev.ru 
1285133Sigor@sysoev.ru 
1286507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1287507Smax.romanov@nginx.com     {
1288507Smax.romanov@nginx.com         nxt_string("spare"),
1289507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1290507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1291507Smax.romanov@nginx.com     },
1292507Smax.romanov@nginx.com 
1293507Smax.romanov@nginx.com     {
1294507Smax.romanov@nginx.com         nxt_string("max"),
1295507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1296507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1297507Smax.romanov@nginx.com     },
1298507Smax.romanov@nginx.com 
1299507Smax.romanov@nginx.com     {
1300507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1301507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1302507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1303507Smax.romanov@nginx.com     },
1304507Smax.romanov@nginx.com };
1305507Smax.romanov@nginx.com 
1306507Smax.romanov@nginx.com 
1307133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1308133Sigor@sysoev.ru     {
1309964Sigor@sysoev.ru         nxt_string("pass"),
1310964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1311964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1312964Sigor@sysoev.ru     },
1313964Sigor@sysoev.ru 
1314964Sigor@sysoev.ru     {
1315133Sigor@sysoev.ru         nxt_string("application"),
1316964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1317133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1318115Sigor@sysoev.ru     },
1319115Sigor@sysoev.ru };
1320115Sigor@sysoev.ru 
1321115Sigor@sysoev.ru 
1322115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1323115Sigor@sysoev.ru     {
1324115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1325115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1326115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1327115Sigor@sysoev.ru     },
1328115Sigor@sysoev.ru 
1329115Sigor@sysoev.ru     {
1330115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1331115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1332115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1333115Sigor@sysoev.ru     },
1334115Sigor@sysoev.ru 
1335115Sigor@sysoev.ru     {
1336206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1337206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1338206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1339206Smax.romanov@nginx.com     },
1340206Smax.romanov@nginx.com 
1341206Smax.romanov@nginx.com     {
1342206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1343206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1344206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1345206Smax.romanov@nginx.com     },
1346206Smax.romanov@nginx.com 
1347206Smax.romanov@nginx.com     {
1348206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1349206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1350206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1351206Smax.romanov@nginx.com     },
1352206Smax.romanov@nginx.com 
1353206Smax.romanov@nginx.com     {
1354431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1355431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1356431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1357431Sigor@sysoev.ru     },
1358431Sigor@sysoev.ru 
1359431Sigor@sysoev.ru     {
1360115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1361115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1362115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1363115Sigor@sysoev.ru     },
1364206Smax.romanov@nginx.com 
1365206Smax.romanov@nginx.com     {
1366206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1367206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1368206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1369206Smax.romanov@nginx.com     },
1370431Sigor@sysoev.ru 
1371431Sigor@sysoev.ru     {
1372431Sigor@sysoev.ru         nxt_string("send_timeout"),
1373431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1374431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1375431Sigor@sysoev.ru     },
1376115Sigor@sysoev.ru };
1377115Sigor@sysoev.ru 
1378115Sigor@sysoev.ru 
137953Sigor@sysoev.ru static nxt_int_t
1380115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1381115Sigor@sysoev.ru     u_char *start, u_char *end)
138253Sigor@sysoev.ru {
1383133Sigor@sysoev.ru     u_char                      *p;
1384133Sigor@sysoev.ru     size_t                      size;
1385115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1386115Sigor@sysoev.ru     uint32_t                    next;
1387115Sigor@sysoev.ru     nxt_int_t                   ret;
1388630Svbart@nginx.com     nxt_str_t                   name, path;
1389133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1390359Sigor@sysoev.ru     nxt_router_t                *router;
1391753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
1392630Svbart@nginx.com     nxt_conf_value_t            *conf, *http, *value;
1393133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1394133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1395964Sigor@sysoev.ru     nxt_conf_value_t            *routes_conf;
1396115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1397964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1398507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1399216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1400133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1401630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1402115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1403774Svbart@nginx.com #if (NXT_TLS)
1404774Svbart@nginx.com     nxt_router_tlssock_t        *tls;
1405774Svbart@nginx.com #endif
1406115Sigor@sysoev.ru 
1407716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1408133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1409115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1410964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1411630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1412774Svbart@nginx.com #if (NXT_TLS)
1413774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1414774Svbart@nginx.com #endif
1415115Sigor@sysoev.ru 
1416208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1417115Sigor@sysoev.ru     if (conf == NULL) {
1418564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1419115Sigor@sysoev.ru         return NXT_ERROR;
1420115Sigor@sysoev.ru     }
1421115Sigor@sysoev.ru 
1422591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1423213Svbart@nginx.com 
1424213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1425591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1426115Sigor@sysoev.ru     if (ret != NXT_OK) {
1427564Svbart@nginx.com         nxt_alert(task, "root map error");
1428115Sigor@sysoev.ru         return NXT_ERROR;
1429115Sigor@sysoev.ru     }
1430115Sigor@sysoev.ru 
1431591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1432591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1433117Sigor@sysoev.ru     }
1434117Sigor@sysoev.ru 
1435133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1436133Sigor@sysoev.ru     if (applications == NULL) {
1437564Svbart@nginx.com         nxt_alert(task, "no \"applications\" block");
1438115Sigor@sysoev.ru         return NXT_ERROR;
1439115Sigor@sysoev.ru     }
1440115Sigor@sysoev.ru 
1441591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1442359Sigor@sysoev.ru 
1443133Sigor@sysoev.ru     next = 0;
1444133Sigor@sysoev.ru 
1445133Sigor@sysoev.ru     for ( ;; ) {
1446133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1447133Sigor@sysoev.ru         if (application == NULL) {
1448133Sigor@sysoev.ru             break;
1449133Sigor@sysoev.ru         }
1450133Sigor@sysoev.ru 
1451133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1452133Sigor@sysoev.ru 
1453144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1454144Smax.romanov@nginx.com 
1455144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1456133Sigor@sysoev.ru         if (app == NULL) {
1457133Sigor@sysoev.ru             goto fail;
1458133Sigor@sysoev.ru         }
1459133Sigor@sysoev.ru 
1460144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1461144Smax.romanov@nginx.com 
1462144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1463144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1464133Sigor@sysoev.ru 
1465133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1466133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1467133Sigor@sysoev.ru 
1468144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1469144Smax.romanov@nginx.com 
1470133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1471133Sigor@sysoev.ru 
1472359Sigor@sysoev.ru         prev = nxt_router_app_find(&router->apps, &name);
1473133Sigor@sysoev.ru 
1474133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1475133Sigor@sysoev.ru             nxt_free(app);
1476133Sigor@sysoev.ru 
1477133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1478133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1479133Sigor@sysoev.ru             continue;
1480133Sigor@sysoev.ru         }
1481133Sigor@sysoev.ru 
1482507Smax.romanov@nginx.com         apcf.processes = 1;
1483507Smax.romanov@nginx.com         apcf.max_processes = 1;
1484537Svbart@nginx.com         apcf.spare_processes = 0;
1485318Smax.romanov@nginx.com         apcf.timeout = 0;
1486427Smax.romanov@nginx.com         apcf.res_timeout = 1000;
1487507Smax.romanov@nginx.com         apcf.idle_timeout = 15000;
1488318Smax.romanov@nginx.com         apcf.requests = 0;
1489318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1490507Smax.romanov@nginx.com         apcf.processes_value = NULL;
1491263Smax.romanov@nginx.com 
1492753Smax.romanov@nginx.com         app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
1493753Smax.romanov@nginx.com         if (nxt_slow_path(app_joint == NULL)) {
1494753Smax.romanov@nginx.com             goto app_fail;
1495753Smax.romanov@nginx.com         }
1496753Smax.romanov@nginx.com 
1497753Smax.romanov@nginx.com         nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
1498753Smax.romanov@nginx.com 
1499213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1500136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1501133Sigor@sysoev.ru         if (ret != NXT_OK) {
1502564Svbart@nginx.com             nxt_alert(task, "application map error");
1503133Sigor@sysoev.ru             goto app_fail;
1504133Sigor@sysoev.ru         }
1505115Sigor@sysoev.ru 
1506318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1507318Smax.romanov@nginx.com 
1508318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1509564Svbart@nginx.com                 nxt_alert(task, "application limits is not object");
1510318Smax.romanov@nginx.com                 goto app_fail;
1511318Smax.romanov@nginx.com             }
1512318Smax.romanov@nginx.com 
1513318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1514318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1515318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1516318Smax.romanov@nginx.com                                       &apcf);
1517318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1518564Svbart@nginx.com                 nxt_alert(task, "application limits map error");
1519318Smax.romanov@nginx.com                 goto app_fail;
1520318Smax.romanov@nginx.com             }
1521318Smax.romanov@nginx.com         }
1522318Smax.romanov@nginx.com 
1523507Smax.romanov@nginx.com         if (apcf.processes_value != NULL
1524507Smax.romanov@nginx.com             && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1525507Smax.romanov@nginx.com         {
1526507Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.processes_value,
1527507Smax.romanov@nginx.com                                       nxt_router_app_processes_conf,
1528507Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_processes_conf),
1529507Smax.romanov@nginx.com                                       &apcf);
1530507Smax.romanov@nginx.com             if (ret != NXT_OK) {
1531564Svbart@nginx.com                 nxt_alert(task, "application processes map error");
1532507Smax.romanov@nginx.com                 goto app_fail;
1533507Smax.romanov@nginx.com             }
1534507Smax.romanov@nginx.com 
1535507Smax.romanov@nginx.com         } else {
1536507Smax.romanov@nginx.com             apcf.max_processes = apcf.processes;
1537507Smax.romanov@nginx.com             apcf.spare_processes = apcf.processes;
1538507Smax.romanov@nginx.com         }
1539507Smax.romanov@nginx.com 
1540133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1541507Smax.romanov@nginx.com         nxt_debug(task, "application processes: %D", apcf.processes);
1542507Smax.romanov@nginx.com         nxt_debug(task, "application request timeout: %M", apcf.timeout);
1543507Smax.romanov@nginx.com         nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout);
1544318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1545133Sigor@sysoev.ru 
1546216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1547216Sigor@sysoev.ru 
1548216Sigor@sysoev.ru         if (lang == NULL) {
1549564Svbart@nginx.com             nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1550141Smax.romanov@nginx.com             goto app_fail;
1551141Smax.romanov@nginx.com         }
1552141Smax.romanov@nginx.com 
1553216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1554216Sigor@sysoev.ru 
1555133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1556133Sigor@sysoev.ru         if (ret != NXT_OK) {
1557133Sigor@sysoev.ru             goto app_fail;
1558133Sigor@sysoev.ru         }
1559133Sigor@sysoev.ru 
1560141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1561507Smax.romanov@nginx.com         nxt_queue_init(&app->spare_ports);
1562507Smax.romanov@nginx.com         nxt_queue_init(&app->idle_ports);
1563141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1564427Smax.romanov@nginx.com         nxt_queue_init(&app->pending);
1565141Smax.romanov@nginx.com 
1566144Smax.romanov@nginx.com         app->name.length = name.length;
1567144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1568144Smax.romanov@nginx.com 
1569356Svbart@nginx.com         app->type = lang->type;
1570507Smax.romanov@nginx.com         app->max_processes = apcf.max_processes;
1571507Smax.romanov@nginx.com         app->spare_processes = apcf.spare_processes;
1572507Smax.romanov@nginx.com         app->max_pending_processes = apcf.spare_processes
1573507Smax.romanov@nginx.com                                       ? apcf.spare_processes : 1;
1574318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1575427Smax.romanov@nginx.com         app->res_timeout = apcf.res_timeout * 1000000;
1576507Smax.romanov@nginx.com         app->idle_timeout = apcf.idle_timeout;
1577343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1578428Smax.romanov@nginx.com         app->max_requests = apcf.requests;
1579133Sigor@sysoev.ru 
1580507Smax.romanov@nginx.com         engine = task->thread->engine;
1581507Smax.romanov@nginx.com 
1582507Smax.romanov@nginx.com         app->engine = engine;
1583507Smax.romanov@nginx.com 
1584507Smax.romanov@nginx.com         app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1585507Smax.romanov@nginx.com         app->adjust_idle_work.task = &engine->task;
1586507Smax.romanov@nginx.com         app->adjust_idle_work.obj = app;
1587507Smax.romanov@nginx.com 
1588133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1589343Smax.romanov@nginx.com 
1590343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1591753Smax.romanov@nginx.com 
1592753Smax.romanov@nginx.com         app->joint = app_joint;
1593753Smax.romanov@nginx.com 
1594753Smax.romanov@nginx.com         app_joint->use_count = 1;
1595753Smax.romanov@nginx.com         app_joint->app = app;
1596753Smax.romanov@nginx.com 
1597811Svbart@nginx.com         app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
1598753Smax.romanov@nginx.com         app_joint->idle_timer.work_queue = &engine->fast_work_queue;
1599753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
1600753Smax.romanov@nginx.com         app_joint->idle_timer.task = &engine->task;
1601753Smax.romanov@nginx.com         app_joint->idle_timer.log = app_joint->idle_timer.task->log;
1602753Smax.romanov@nginx.com 
1603753Smax.romanov@nginx.com         app_joint->free_app_work.handler = nxt_router_free_app;
1604753Smax.romanov@nginx.com         app_joint->free_app_work.task = &engine->task;
1605753Smax.romanov@nginx.com         app_joint->free_app_work.obj = app_joint;
1606133Sigor@sysoev.ru     }
1607133Sigor@sysoev.ru 
1608964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1609964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1610964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1611964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1612964Sigor@sysoev.ru             return NXT_ERROR;
1613964Sigor@sysoev.ru         }
1614964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1615964Sigor@sysoev.ru     }
1616964Sigor@sysoev.ru 
1617133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1618133Sigor@sysoev.ru #if 0
1619133Sigor@sysoev.ru     if (http == NULL) {
1620564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1621133Sigor@sysoev.ru         return NXT_ERROR;
1622133Sigor@sysoev.ru     }
1623133Sigor@sysoev.ru #endif
1624133Sigor@sysoev.ru 
1625133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1626115Sigor@sysoev.ru     if (listeners == NULL) {
1627564Svbart@nginx.com         nxt_alert(task, "no \"listeners\" block");
1628115Sigor@sysoev.ru         return NXT_ERROR;
1629115Sigor@sysoev.ru     }
163053Sigor@sysoev.ru 
1631133Sigor@sysoev.ru     next = 0;
163253Sigor@sysoev.ru 
1633115Sigor@sysoev.ru     for ( ;; ) {
1634115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1635115Sigor@sysoev.ru         if (listener == NULL) {
1636115Sigor@sysoev.ru             break;
1637115Sigor@sysoev.ru         }
163853Sigor@sysoev.ru 
1639359Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, tmcf, &name);
1640115Sigor@sysoev.ru         if (skcf == NULL) {
1641133Sigor@sysoev.ru             goto fail;
1642115Sigor@sysoev.ru         }
164353Sigor@sysoev.ru 
1644770Smax.romanov@nginx.com         nxt_memzero(&lscf, sizeof(lscf));
1645770Smax.romanov@nginx.com 
1646213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1647136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1648115Sigor@sysoev.ru         if (ret != NXT_OK) {
1649564Svbart@nginx.com             nxt_alert(task, "listener map error");
1650133Sigor@sysoev.ru             goto fail;
1651115Sigor@sysoev.ru         }
165253Sigor@sysoev.ru 
1653133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1654133Sigor@sysoev.ru 
1655133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1656133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1657133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1658206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1659206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1660715Svbart@nginx.com         skcf->max_body_size = 8 * 1024 * 1024;
1661715Svbart@nginx.com         skcf->idle_timeout = 180 * 1000;
1662715Svbart@nginx.com         skcf->header_read_timeout = 30 * 1000;
1663715Svbart@nginx.com         skcf->body_read_timeout = 30 * 1000;
1664715Svbart@nginx.com         skcf->send_timeout = 30 * 1000;
166553Sigor@sysoev.ru 
1666133Sigor@sysoev.ru         if (http != NULL) {
1667213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1668136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1669133Sigor@sysoev.ru             if (ret != NXT_OK) {
1670564Svbart@nginx.com                 nxt_alert(task, "http map error");
1671133Sigor@sysoev.ru                 goto fail;
1672133Sigor@sysoev.ru             }
1673115Sigor@sysoev.ru         }
1674115Sigor@sysoev.ru 
1675774Svbart@nginx.com #if (NXT_TLS)
1676774Svbart@nginx.com 
1677774Svbart@nginx.com         value = nxt_conf_get_path(listener, &certificate_path);
1678774Svbart@nginx.com 
1679774Svbart@nginx.com         if (value != NULL) {
1680774Svbart@nginx.com             nxt_conf_get_string(value, &name);
1681774Svbart@nginx.com 
1682774Svbart@nginx.com             tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
1683774Svbart@nginx.com             if (nxt_slow_path(tls == NULL)) {
1684774Svbart@nginx.com                 goto fail;
1685774Svbart@nginx.com             }
1686774Svbart@nginx.com 
1687774Svbart@nginx.com             tls->name = name;
1688774Svbart@nginx.com             tls->conf = skcf;
1689774Svbart@nginx.com 
1690774Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1691774Svbart@nginx.com         }
1692774Svbart@nginx.com 
1693774Svbart@nginx.com #endif
1694774Svbart@nginx.com 
1695431Sigor@sysoev.ru         skcf->listen->handler = nxt_http_conn_init;
1696591Sigor@sysoev.ru         skcf->router_conf = tmcf->router_conf;
1697160Sigor@sysoev.ru         skcf->router_conf->count++;
1698770Smax.romanov@nginx.com 
1699964Sigor@sysoev.ru         if (lscf.pass.length != 0) {
1700964Sigor@sysoev.ru             skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass);
1701964Sigor@sysoev.ru 
1702964Sigor@sysoev.ru         /* COMPATIBILITY: listener application. */
1703964Sigor@sysoev.ru         } else if (lscf.application.length > 0) {
1704964Sigor@sysoev.ru             skcf->pass = nxt_http_pass_application(task, tmcf,
1705964Sigor@sysoev.ru                                                    &lscf.application);
1706770Smax.romanov@nginx.com         }
1707115Sigor@sysoev.ru     }
170853Sigor@sysoev.ru 
1709630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1710630Svbart@nginx.com 
1711630Svbart@nginx.com     if (value != NULL) {
1712630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1713630Svbart@nginx.com 
1714630Svbart@nginx.com         access_log = router->access_log;
1715630Svbart@nginx.com 
1716630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1717630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1718630Svbart@nginx.com             access_log->count++;
1719630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1720630Svbart@nginx.com 
1721630Svbart@nginx.com         } else {
1722630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1723630Svbart@nginx.com                                     + path.length);
1724630Svbart@nginx.com             if (access_log == NULL) {
1725630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1726630Svbart@nginx.com                 goto fail;
1727630Svbart@nginx.com             }
1728630Svbart@nginx.com 
1729630Svbart@nginx.com             access_log->fd = -1;
1730630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1731630Svbart@nginx.com             access_log->count = 1;
1732630Svbart@nginx.com 
1733630Svbart@nginx.com             access_log->path.length = path.length;
1734630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1735630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1736630Svbart@nginx.com 
1737630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1738630Svbart@nginx.com         }
1739630Svbart@nginx.com 
1740630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1741630Svbart@nginx.com     }
1742630Svbart@nginx.com 
1743964Sigor@sysoev.ru     nxt_http_routes_resolve(task, tmcf);
1744964Sigor@sysoev.ru 
1745359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1746359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1747198Sigor@sysoev.ru 
174853Sigor@sysoev.ru     return NXT_OK;
1749133Sigor@sysoev.ru 
1750133Sigor@sysoev.ru app_fail:
1751133Sigor@sysoev.ru 
1752133Sigor@sysoev.ru     nxt_free(app);
1753133Sigor@sysoev.ru 
1754133Sigor@sysoev.ru fail:
1755133Sigor@sysoev.ru 
1756141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1757141Smax.romanov@nginx.com 
1758141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1759133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1760133Sigor@sysoev.ru         nxt_free(app);
1761141Smax.romanov@nginx.com 
1762141Smax.romanov@nginx.com     } nxt_queue_loop;
1763133Sigor@sysoev.ru 
1764133Sigor@sysoev.ru     return NXT_ERROR;
1765133Sigor@sysoev.ru }
1766133Sigor@sysoev.ru 
1767133Sigor@sysoev.ru 
1768133Sigor@sysoev.ru static nxt_app_t *
1769133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1770133Sigor@sysoev.ru {
1771141Smax.romanov@nginx.com     nxt_app_t  *app;
1772141Smax.romanov@nginx.com 
1773141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1774133Sigor@sysoev.ru 
1775133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1776133Sigor@sysoev.ru             return app;
1777133Sigor@sysoev.ru         }
1778141Smax.romanov@nginx.com 
1779141Smax.romanov@nginx.com     } nxt_queue_loop;
1780133Sigor@sysoev.ru 
1781133Sigor@sysoev.ru     return NULL;
1782133Sigor@sysoev.ru }
1783133Sigor@sysoev.ru 
1784133Sigor@sysoev.ru 
1785964Sigor@sysoev.ru nxt_app_t *
1786133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1787133Sigor@sysoev.ru {
1788133Sigor@sysoev.ru     nxt_app_t  *app;
1789133Sigor@sysoev.ru 
1790133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1791133Sigor@sysoev.ru 
1792133Sigor@sysoev.ru     if (app == NULL) {
1793134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1794133Sigor@sysoev.ru     }
1795133Sigor@sysoev.ru 
1796133Sigor@sysoev.ru     return app;
179753Sigor@sysoev.ru }
179853Sigor@sysoev.ru 
179953Sigor@sysoev.ru 
180053Sigor@sysoev.ru static nxt_socket_conf_t *
1801359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1802359Sigor@sysoev.ru     nxt_str_t *name)
180353Sigor@sysoev.ru {
1804359Sigor@sysoev.ru     size_t               size;
1805359Sigor@sysoev.ru     nxt_int_t            ret;
1806359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1807359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1808359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1809359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1810359Sigor@sysoev.ru 
1811359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1812359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1813564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1814359Sigor@sysoev.ru         return NULL;
1815359Sigor@sysoev.ru     }
1816359Sigor@sysoev.ru 
1817359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1818359Sigor@sysoev.ru 
1819359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1820493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1821359Sigor@sysoev.ru 
1822591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1823163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
182453Sigor@sysoev.ru         return NULL;
182553Sigor@sysoev.ru     }
182653Sigor@sysoev.ru 
1827359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1828359Sigor@sysoev.ru 
1829359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1830359Sigor@sysoev.ru 
1831359Sigor@sysoev.ru     if (ret != NXT_OK) {
1832359Sigor@sysoev.ru 
1833359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1834359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1835359Sigor@sysoev.ru             return NULL;
1836359Sigor@sysoev.ru         }
1837359Sigor@sysoev.ru 
1838359Sigor@sysoev.ru         skcf->listen = ls;
1839359Sigor@sysoev.ru 
1840359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1841359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1842359Sigor@sysoev.ru 
1843359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1844359Sigor@sysoev.ru 
1845359Sigor@sysoev.ru         ls->socket = -1;
1846359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1847359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1848359Sigor@sysoev.ru         ls->read_after_accept = 1;
1849359Sigor@sysoev.ru     }
1850359Sigor@sysoev.ru 
1851359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1852359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1853359Sigor@sysoev.ru     case AF_UNIX:
1854359Sigor@sysoev.ru         wildcard = 0;
1855359Sigor@sysoev.ru         break;
1856359Sigor@sysoev.ru #endif
1857359Sigor@sysoev.ru #if (NXT_INET6)
1858359Sigor@sysoev.ru     case AF_INET6:
1859359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1860359Sigor@sysoev.ru         break;
1861359Sigor@sysoev.ru #endif
1862359Sigor@sysoev.ru     case AF_INET:
1863359Sigor@sysoev.ru     default:
1864359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1865359Sigor@sysoev.ru         break;
1866359Sigor@sysoev.ru     }
1867359Sigor@sysoev.ru 
1868359Sigor@sysoev.ru     if (!wildcard) {
1869591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
1870359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1871359Sigor@sysoev.ru             return NULL;
1872359Sigor@sysoev.ru         }
1873359Sigor@sysoev.ru 
1874359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1875359Sigor@sysoev.ru     }
1876163Smax.romanov@nginx.com 
1877163Smax.romanov@nginx.com     return skcf;
187853Sigor@sysoev.ru }
187953Sigor@sysoev.ru 
188053Sigor@sysoev.ru 
1881359Sigor@sysoev.ru static nxt_int_t
1882359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1883359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
188453Sigor@sysoev.ru {
1885359Sigor@sysoev.ru     nxt_router_t       *router;
1886359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1887359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1888359Sigor@sysoev.ru 
1889591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1890359Sigor@sysoev.ru 
1891359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
1892359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
1893359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
189453Sigor@sysoev.ru     {
1895359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1896359Sigor@sysoev.ru 
1897359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
1898359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
1899359Sigor@sysoev.ru 
1900359Sigor@sysoev.ru             nxt_queue_remove(qlk);
1901359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
1902359Sigor@sysoev.ru 
1903359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
1904359Sigor@sysoev.ru 
1905359Sigor@sysoev.ru             return NXT_OK;
190653Sigor@sysoev.ru         }
190753Sigor@sysoev.ru     }
190853Sigor@sysoev.ru 
1909359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
1910359Sigor@sysoev.ru 
1911359Sigor@sysoev.ru     return NXT_DECLINED;
191253Sigor@sysoev.ru }
191353Sigor@sysoev.ru 
191453Sigor@sysoev.ru 
1915198Sigor@sysoev.ru static void
1916198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1917198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1918198Sigor@sysoev.ru {
1919358Sigor@sysoev.ru     size_t            size;
1920198Sigor@sysoev.ru     uint32_t          stream;
1921648Svbart@nginx.com     nxt_int_t         ret;
1922198Sigor@sysoev.ru     nxt_buf_t         *b;
1923198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1924198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1925198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1926198Sigor@sysoev.ru 
1927198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1928198Sigor@sysoev.ru     if (rpc == NULL) {
1929198Sigor@sysoev.ru         goto fail;
1930198Sigor@sysoev.ru     }
1931198Sigor@sysoev.ru 
1932198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1933198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1934198Sigor@sysoev.ru 
1935359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
1936358Sigor@sysoev.ru 
1937358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1938198Sigor@sysoev.ru     if (b == NULL) {
1939198Sigor@sysoev.ru         goto fail;
1940198Sigor@sysoev.ru     }
1941198Sigor@sysoev.ru 
1942359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
1943198Sigor@sysoev.ru 
1944198Sigor@sysoev.ru     rt = task->thread->runtime;
1945240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1946198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1947198Sigor@sysoev.ru 
1948198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1949198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1950198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1951198Sigor@sysoev.ru                                            main_port->pid, rpc);
1952645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
1953198Sigor@sysoev.ru         goto fail;
1954198Sigor@sysoev.ru     }
1955198Sigor@sysoev.ru 
1956648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1957648Svbart@nginx.com                                 stream, router_port->id, b);
1958648Svbart@nginx.com 
1959648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1960648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
1961648Svbart@nginx.com         goto fail;
1962648Svbart@nginx.com     }
1963198Sigor@sysoev.ru 
1964198Sigor@sysoev.ru     return;
1965198Sigor@sysoev.ru 
1966198Sigor@sysoev.ru fail:
1967198Sigor@sysoev.ru 
1968198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1969198Sigor@sysoev.ru }
1970198Sigor@sysoev.ru 
1971198Sigor@sysoev.ru 
1972198Sigor@sysoev.ru static void
1973198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1974198Sigor@sysoev.ru     void *data)
197553Sigor@sysoev.ru {
1976359Sigor@sysoev.ru     nxt_int_t         ret;
1977359Sigor@sysoev.ru     nxt_socket_t      s;
1978359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
197953Sigor@sysoev.ru 
1980198Sigor@sysoev.ru     rpc = data;
1981198Sigor@sysoev.ru 
1982198Sigor@sysoev.ru     s = msg->fd;
1983198Sigor@sysoev.ru 
1984198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1985198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1986198Sigor@sysoev.ru         goto fail;
198753Sigor@sysoev.ru     }
198853Sigor@sysoev.ru 
1989359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
1990198Sigor@sysoev.ru 
1991198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1992198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1993198Sigor@sysoev.ru         goto fail;
1994198Sigor@sysoev.ru     }
1995198Sigor@sysoev.ru 
1996359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
1997198Sigor@sysoev.ru 
1998198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1999198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2000198Sigor@sysoev.ru 
2001198Sigor@sysoev.ru     return;
2002148Sigor@sysoev.ru 
2003148Sigor@sysoev.ru fail:
2004148Sigor@sysoev.ru 
2005148Sigor@sysoev.ru     nxt_socket_close(task, s);
2006148Sigor@sysoev.ru 
2007198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2008198Sigor@sysoev.ru }
2009198Sigor@sysoev.ru 
2010198Sigor@sysoev.ru 
2011198Sigor@sysoev.ru static void
2012198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2013198Sigor@sysoev.ru     void *data)
2014198Sigor@sysoev.ru {
2015955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2016955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2017955Svbart@nginx.com 
2018955Svbart@nginx.com     rpc = data;
2019955Svbart@nginx.com     tmcf = rpc->temp_conf;
2020955Svbart@nginx.com 
2021955Svbart@nginx.com #if 0
2022198Sigor@sysoev.ru     u_char                  *p;
2023198Sigor@sysoev.ru     size_t                  size;
2024198Sigor@sysoev.ru     uint8_t                 error;
2025198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2026198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2027198Sigor@sysoev.ru 
2028198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2029198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2030198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2031198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2032198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2033198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2034198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2035198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2036198Sigor@sysoev.ru     };
2037198Sigor@sysoev.ru 
2038359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2039352Smax.romanov@nginx.com 
2040352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2041352Smax.romanov@nginx.com 
2042551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2043551Smax.romanov@nginx.com         return;
2044551Smax.romanov@nginx.com     }
2045352Smax.romanov@nginx.com 
2046198Sigor@sysoev.ru     p = in->mem.pos;
2047198Sigor@sysoev.ru 
2048198Sigor@sysoev.ru     error = *p++;
2049198Sigor@sysoev.ru 
2050703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2051703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2052198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2053198Sigor@sysoev.ru 
2054198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2055198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2056198Sigor@sysoev.ru         return;
2057198Sigor@sysoev.ru     }
2058198Sigor@sysoev.ru 
2059198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2060198Sigor@sysoev.ru                         "listen socket error: "
2061198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2062493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2063198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2064198Sigor@sysoev.ru 
2065198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2066955Svbart@nginx.com #endif
2067198Sigor@sysoev.ru 
2068198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
206953Sigor@sysoev.ru }
207053Sigor@sysoev.ru 
207153Sigor@sysoev.ru 
2072774Svbart@nginx.com #if (NXT_TLS)
2073774Svbart@nginx.com 
2074774Svbart@nginx.com static void
2075774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2076774Svbart@nginx.com     nxt_router_tlssock_t *tls)
2077774Svbart@nginx.com {
2078774Svbart@nginx.com     nxt_socket_rpc_t  *rpc;
2079774Svbart@nginx.com 
2080774Svbart@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2081774Svbart@nginx.com     if (rpc == NULL) {
2082774Svbart@nginx.com         nxt_router_conf_error(task, tmcf);
2083774Svbart@nginx.com         return;
2084774Svbart@nginx.com     }
2085774Svbart@nginx.com 
2086774Svbart@nginx.com     rpc->socket_conf = tls->conf;
2087774Svbart@nginx.com     rpc->temp_conf = tmcf;
2088774Svbart@nginx.com 
2089774Svbart@nginx.com     nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
2090774Svbart@nginx.com                        nxt_router_tls_rpc_handler, rpc);
2091774Svbart@nginx.com }
2092774Svbart@nginx.com 
2093774Svbart@nginx.com 
2094774Svbart@nginx.com static void
2095774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2096774Svbart@nginx.com     void *data)
2097774Svbart@nginx.com {
2098774Svbart@nginx.com     nxt_mp_t               *mp;
2099774Svbart@nginx.com     nxt_int_t              ret;
2100774Svbart@nginx.com     nxt_tls_conf_t         *tlscf;
2101774Svbart@nginx.com     nxt_socket_rpc_t       *rpc;
2102774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf;
2103774Svbart@nginx.com 
2104774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2105774Svbart@nginx.com 
2106774Svbart@nginx.com     rpc = data;
2107774Svbart@nginx.com     tmcf = rpc->temp_conf;
2108774Svbart@nginx.com 
2109774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2110774Svbart@nginx.com         goto fail;
2111774Svbart@nginx.com     }
2112774Svbart@nginx.com 
2113774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2114774Svbart@nginx.com 
2115774Svbart@nginx.com     tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2116774Svbart@nginx.com     if (nxt_slow_path(tlscf == NULL)) {
2117774Svbart@nginx.com         goto fail;
2118774Svbart@nginx.com     }
2119774Svbart@nginx.com 
2120774Svbart@nginx.com     tlscf->chain_file = msg->fd;
2121774Svbart@nginx.com 
2122774Svbart@nginx.com     ret = task->thread->runtime->tls->server_init(task, tlscf);
2123774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2124774Svbart@nginx.com         goto fail;
2125774Svbart@nginx.com     }
2126774Svbart@nginx.com 
2127774Svbart@nginx.com     rpc->socket_conf->tls = tlscf;
2128774Svbart@nginx.com 
2129774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2130774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2131774Svbart@nginx.com     return;
2132774Svbart@nginx.com 
2133774Svbart@nginx.com fail:
2134774Svbart@nginx.com 
2135774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2136774Svbart@nginx.com }
2137774Svbart@nginx.com 
2138774Svbart@nginx.com #endif
2139774Svbart@nginx.com 
2140774Svbart@nginx.com 
2141507Smax.romanov@nginx.com static void
2142507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2143507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2144507Smax.romanov@nginx.com {
2145507Smax.romanov@nginx.com     size_t         size;
2146507Smax.romanov@nginx.com     uint32_t       stream;
2147648Svbart@nginx.com     nxt_int_t      ret;
2148507Smax.romanov@nginx.com     nxt_buf_t      *b;
2149507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
2150507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2151507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2152507Smax.romanov@nginx.com 
2153507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2154507Smax.romanov@nginx.com     if (rpc == NULL) {
2155507Smax.romanov@nginx.com         goto fail;
2156507Smax.romanov@nginx.com     }
2157507Smax.romanov@nginx.com 
2158507Smax.romanov@nginx.com     rpc->app = app;
2159507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2160507Smax.romanov@nginx.com 
2161507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
2162507Smax.romanov@nginx.com 
2163507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
2164507Smax.romanov@nginx.com 
2165507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2166507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2167507Smax.romanov@nginx.com         goto fail;
2168507Smax.romanov@nginx.com     }
2169507Smax.romanov@nginx.com 
2170507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
2171507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
2172507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2173507Smax.romanov@nginx.com 
2174507Smax.romanov@nginx.com     rt = task->thread->runtime;
2175507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2176507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2177507Smax.romanov@nginx.com 
2178507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2179507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
2180507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
2181507Smax.romanov@nginx.com                                            -1, rpc);
2182507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2183507Smax.romanov@nginx.com         goto fail;
2184507Smax.romanov@nginx.com     }
2185507Smax.romanov@nginx.com 
2186648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2187648Svbart@nginx.com                                 stream, router_port->id, b);
2188648Svbart@nginx.com 
2189648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2190648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2191648Svbart@nginx.com         goto fail;
2192648Svbart@nginx.com     }
2193648Svbart@nginx.com 
2194507Smax.romanov@nginx.com     app->pending_processes++;
2195507Smax.romanov@nginx.com 
2196507Smax.romanov@nginx.com     return;
2197507Smax.romanov@nginx.com 
2198507Smax.romanov@nginx.com fail:
2199507Smax.romanov@nginx.com 
2200507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2201507Smax.romanov@nginx.com }
2202507Smax.romanov@nginx.com 
2203507Smax.romanov@nginx.com 
2204507Smax.romanov@nginx.com static void
2205507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2206507Smax.romanov@nginx.com     void *data)
2207507Smax.romanov@nginx.com {
2208507Smax.romanov@nginx.com     nxt_app_t           *app;
2209507Smax.romanov@nginx.com     nxt_port_t          *port;
2210507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2211507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2212507Smax.romanov@nginx.com 
2213507Smax.romanov@nginx.com     rpc = data;
2214507Smax.romanov@nginx.com     app = rpc->app;
2215507Smax.romanov@nginx.com 
2216507Smax.romanov@nginx.com     port = msg->u.new_port;
2217507Smax.romanov@nginx.com     port->app = app;
2218507Smax.romanov@nginx.com 
2219507Smax.romanov@nginx.com     app->pending_processes--;
2220507Smax.romanov@nginx.com     app->processes++;
2221507Smax.romanov@nginx.com     app->idle_processes++;
2222507Smax.romanov@nginx.com 
2223507Smax.romanov@nginx.com     engine = task->thread->engine;
2224507Smax.romanov@nginx.com 
2225507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2226507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2227507Smax.romanov@nginx.com 
2228507Smax.romanov@nginx.com     port->idle_start = 0;
2229507Smax.romanov@nginx.com 
2230507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2231507Smax.romanov@nginx.com 
2232507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2233507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2234507Smax.romanov@nginx.com }
2235507Smax.romanov@nginx.com 
2236507Smax.romanov@nginx.com 
2237507Smax.romanov@nginx.com static void
2238507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2239507Smax.romanov@nginx.com     void *data)
2240507Smax.romanov@nginx.com {
2241507Smax.romanov@nginx.com     nxt_app_t               *app;
2242507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2243507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2244507Smax.romanov@nginx.com 
2245507Smax.romanov@nginx.com     rpc = data;
2246507Smax.romanov@nginx.com     app = rpc->app;
2247507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2248507Smax.romanov@nginx.com 
2249507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2250507Smax.romanov@nginx.com             &app->name);
2251507Smax.romanov@nginx.com 
2252507Smax.romanov@nginx.com     app->pending_processes--;
2253507Smax.romanov@nginx.com 
2254507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2255507Smax.romanov@nginx.com }
2256507Smax.romanov@nginx.com 
2257507Smax.romanov@nginx.com 
225853Sigor@sysoev.ru static nxt_int_t
225953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
226053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
226153Sigor@sysoev.ru {
226253Sigor@sysoev.ru     nxt_int_t                 ret;
226353Sigor@sysoev.ru     nxt_uint_t                n, threads;
226453Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
226553Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
226653Sigor@sysoev.ru 
2267591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
226853Sigor@sysoev.ru 
226953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
227053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
227153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
227253Sigor@sysoev.ru         return NXT_ERROR;
227353Sigor@sysoev.ru     }
227453Sigor@sysoev.ru 
227553Sigor@sysoev.ru     n = 0;
227653Sigor@sysoev.ru 
227753Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
227853Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
227953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
228053Sigor@sysoev.ru     {
228153Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
228253Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
228353Sigor@sysoev.ru             return NXT_ERROR;
228453Sigor@sysoev.ru         }
228553Sigor@sysoev.ru 
2286115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
228753Sigor@sysoev.ru 
228853Sigor@sysoev.ru         if (n < threads) {
2289315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2290115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
229153Sigor@sysoev.ru 
229253Sigor@sysoev.ru         } else {
2293315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2294115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
229553Sigor@sysoev.ru         }
229653Sigor@sysoev.ru 
229753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
229853Sigor@sysoev.ru             return ret;
229953Sigor@sysoev.ru         }
230053Sigor@sysoev.ru 
230153Sigor@sysoev.ru         n++;
230253Sigor@sysoev.ru     }
230353Sigor@sysoev.ru 
230453Sigor@sysoev.ru     tmcf->new_threads = n;
230553Sigor@sysoev.ru 
230653Sigor@sysoev.ru     while (n < threads) {
230753Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
230853Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
230953Sigor@sysoev.ru             return NXT_ERROR;
231053Sigor@sysoev.ru         }
231153Sigor@sysoev.ru 
2312315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2313315Sigor@sysoev.ru 
231453Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
231553Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
231653Sigor@sysoev.ru             return NXT_ERROR;
231753Sigor@sysoev.ru         }
231853Sigor@sysoev.ru 
2319115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
232053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
232153Sigor@sysoev.ru             return ret;
232253Sigor@sysoev.ru         }
232353Sigor@sysoev.ru 
232453Sigor@sysoev.ru         n++;
232553Sigor@sysoev.ru     }
232653Sigor@sysoev.ru 
232753Sigor@sysoev.ru     return NXT_OK;
232853Sigor@sysoev.ru }
232953Sigor@sysoev.ru 
233053Sigor@sysoev.ru 
233153Sigor@sysoev.ru static nxt_int_t
2332115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2333115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
233453Sigor@sysoev.ru {
2335359Sigor@sysoev.ru     nxt_int_t  ret;
233653Sigor@sysoev.ru 
2337154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2338154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2339115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2340115Sigor@sysoev.ru         return ret;
2341115Sigor@sysoev.ru     }
2342115Sigor@sysoev.ru 
2343154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2344154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
234553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
234653Sigor@sysoev.ru         return ret;
234753Sigor@sysoev.ru     }
234853Sigor@sysoev.ru 
2349115Sigor@sysoev.ru     return ret;
235053Sigor@sysoev.ru }
235153Sigor@sysoev.ru 
235253Sigor@sysoev.ru 
235353Sigor@sysoev.ru static nxt_int_t
2354115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2355115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
235653Sigor@sysoev.ru {
2357359Sigor@sysoev.ru     nxt_int_t  ret;
235853Sigor@sysoev.ru 
2359154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2360154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
236153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
236253Sigor@sysoev.ru         return ret;
236353Sigor@sysoev.ru     }
236453Sigor@sysoev.ru 
2365154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2366154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
236753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
236853Sigor@sysoev.ru         return ret;
236953Sigor@sysoev.ru     }
237053Sigor@sysoev.ru 
2371139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
2372115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2373115Sigor@sysoev.ru         return ret;
2374115Sigor@sysoev.ru     }
2375115Sigor@sysoev.ru 
2376115Sigor@sysoev.ru     return ret;
237753Sigor@sysoev.ru }
237853Sigor@sysoev.ru 
237953Sigor@sysoev.ru 
238053Sigor@sysoev.ru static nxt_int_t
2381115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2382115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
238353Sigor@sysoev.ru {
238453Sigor@sysoev.ru     nxt_int_t  ret;
238553Sigor@sysoev.ru 
2386313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2387313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2388313Sigor@sysoev.ru         return ret;
2389313Sigor@sysoev.ru     }
2390313Sigor@sysoev.ru 
2391139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
239253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
239353Sigor@sysoev.ru         return ret;
239453Sigor@sysoev.ru     }
239553Sigor@sysoev.ru 
2396139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
239753Sigor@sysoev.ru }
239853Sigor@sysoev.ru 
239953Sigor@sysoev.ru 
240053Sigor@sysoev.ru static nxt_int_t
2401154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2402154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
240353Sigor@sysoev.ru     nxt_work_handler_t handler)
240453Sigor@sysoev.ru {
2405153Sigor@sysoev.ru     nxt_joint_job_t          *job;
240653Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2407155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
240853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
240953Sigor@sysoev.ru 
241053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
241153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
241253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
241353Sigor@sysoev.ru     {
2414154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2415153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2416139Sigor@sysoev.ru             return NXT_ERROR;
2417139Sigor@sysoev.ru         }
2418139Sigor@sysoev.ru 
2419154Sigor@sysoev.ru         job->work.next = recf->jobs;
2420154Sigor@sysoev.ru         recf->jobs = &job->work;
2421154Sigor@sysoev.ru 
2422153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2423153Sigor@sysoev.ru         job->work.handler = handler;
2424153Sigor@sysoev.ru         job->work.task = &job->task;
2425153Sigor@sysoev.ru         job->work.obj = job;
2426153Sigor@sysoev.ru         job->tmcf = tmcf;
242753Sigor@sysoev.ru 
2428154Sigor@sysoev.ru         tmcf->count++;
2429154Sigor@sysoev.ru 
2430591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2431154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
243253Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
243353Sigor@sysoev.ru             return NXT_ERROR;
243453Sigor@sysoev.ru         }
243553Sigor@sysoev.ru 
2436153Sigor@sysoev.ru         job->work.data = joint;
243753Sigor@sysoev.ru 
243853Sigor@sysoev.ru         joint->count = 1;
2439155Sigor@sysoev.ru 
2440155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2441155Sigor@sysoev.ru         skcf->count++;
2442155Sigor@sysoev.ru         joint->socket_conf = skcf;
2443155Sigor@sysoev.ru 
244488Smax.romanov@nginx.com         joint->engine = recf->engine;
244553Sigor@sysoev.ru     }
244653Sigor@sysoev.ru 
244720Sigor@sysoev.ru     return NXT_OK;
244820Sigor@sysoev.ru }
244920Sigor@sysoev.ru 
245020Sigor@sysoev.ru 
245120Sigor@sysoev.ru static nxt_int_t
2452313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2453313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2454313Sigor@sysoev.ru {
2455313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2456313Sigor@sysoev.ru 
2457313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2458313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2459313Sigor@sysoev.ru         return NXT_ERROR;
2460313Sigor@sysoev.ru     }
2461313Sigor@sysoev.ru 
2462313Sigor@sysoev.ru     job->work.next = recf->jobs;
2463313Sigor@sysoev.ru     recf->jobs = &job->work;
2464313Sigor@sysoev.ru 
2465313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2466313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2467313Sigor@sysoev.ru     job->work.task = &job->task;
2468313Sigor@sysoev.ru     job->work.obj = NULL;
2469313Sigor@sysoev.ru     job->work.data = NULL;
2470313Sigor@sysoev.ru     job->tmcf = NULL;
2471313Sigor@sysoev.ru 
2472313Sigor@sysoev.ru     return NXT_OK;
2473313Sigor@sysoev.ru }
2474313Sigor@sysoev.ru 
2475313Sigor@sysoev.ru 
2476313Sigor@sysoev.ru static nxt_int_t
2477139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2478139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
247920Sigor@sysoev.ru {
2480153Sigor@sysoev.ru     nxt_joint_job_t   *job;
248153Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
248220Sigor@sysoev.ru 
248353Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
248453Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
248553Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
248653Sigor@sysoev.ru     {
2487154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2488153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2489139Sigor@sysoev.ru             return NXT_ERROR;
2490139Sigor@sysoev.ru         }
2491139Sigor@sysoev.ru 
2492154Sigor@sysoev.ru         job->work.next = recf->jobs;
2493154Sigor@sysoev.ru         recf->jobs = &job->work;
2494154Sigor@sysoev.ru 
2495153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2496153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2497153Sigor@sysoev.ru         job->work.task = &job->task;
2498153Sigor@sysoev.ru         job->work.obj = job;
2499153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2500153Sigor@sysoev.ru         job->tmcf = tmcf;
2501154Sigor@sysoev.ru 
2502154Sigor@sysoev.ru         tmcf->count++;
250320Sigor@sysoev.ru     }
250420Sigor@sysoev.ru 
250553Sigor@sysoev.ru     return NXT_OK;
250653Sigor@sysoev.ru }
250720Sigor@sysoev.ru 
250820Sigor@sysoev.ru 
250953Sigor@sysoev.ru static nxt_int_t
251053Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
251153Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
251253Sigor@sysoev.ru {
251353Sigor@sysoev.ru     nxt_int_t                 ret;
251453Sigor@sysoev.ru     nxt_uint_t                i, threads;
251553Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
251620Sigor@sysoev.ru 
251753Sigor@sysoev.ru     recf = tmcf->engines->elts;
2518591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
251920Sigor@sysoev.ru 
252053Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
252153Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
252253Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
252353Sigor@sysoev.ru             return ret;
252453Sigor@sysoev.ru         }
252520Sigor@sysoev.ru     }
252620Sigor@sysoev.ru 
252720Sigor@sysoev.ru     return NXT_OK;
252820Sigor@sysoev.ru }
252953Sigor@sysoev.ru 
253053Sigor@sysoev.ru 
253153Sigor@sysoev.ru static nxt_int_t
253253Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
253353Sigor@sysoev.ru     nxt_event_engine_t *engine)
253453Sigor@sysoev.ru {
253553Sigor@sysoev.ru     nxt_int_t            ret;
253653Sigor@sysoev.ru     nxt_thread_link_t    *link;
253753Sigor@sysoev.ru     nxt_thread_handle_t  handle;
253853Sigor@sysoev.ru 
253953Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
254053Sigor@sysoev.ru 
254153Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
254253Sigor@sysoev.ru         return NXT_ERROR;
254353Sigor@sysoev.ru     }
254453Sigor@sysoev.ru 
254553Sigor@sysoev.ru     link->start = nxt_router_thread_start;
254653Sigor@sysoev.ru     link->engine = engine;
254753Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
254853Sigor@sysoev.ru     link->work.task = task;
254953Sigor@sysoev.ru     link->work.data = link;
255053Sigor@sysoev.ru 
255153Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
255253Sigor@sysoev.ru 
255353Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
255453Sigor@sysoev.ru 
255553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
255653Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
255753Sigor@sysoev.ru     }
255853Sigor@sysoev.ru 
255953Sigor@sysoev.ru     return ret;
256053Sigor@sysoev.ru }
256153Sigor@sysoev.ru 
256253Sigor@sysoev.ru 
256353Sigor@sysoev.ru static void
2564343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2565343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2566133Sigor@sysoev.ru {
2567507Smax.romanov@nginx.com     nxt_app_t  *app;
2568141Smax.romanov@nginx.com 
2569141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2570133Sigor@sysoev.ru 
2571753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2572343Smax.romanov@nginx.com 
2573141Smax.romanov@nginx.com     } nxt_queue_loop;
2574133Sigor@sysoev.ru 
2575133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2576133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2577133Sigor@sysoev.ru }
2578133Sigor@sysoev.ru 
2579133Sigor@sysoev.ru 
2580133Sigor@sysoev.ru static void
2581315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
258253Sigor@sysoev.ru {
258353Sigor@sysoev.ru     nxt_uint_t                n;
2584315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
258553Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
258653Sigor@sysoev.ru 
258753Sigor@sysoev.ru     recf = tmcf->engines->elts;
258853Sigor@sysoev.ru 
258953Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2590315Sigor@sysoev.ru         engine = recf->engine;
2591315Sigor@sysoev.ru 
2592315Sigor@sysoev.ru         switch (recf->action) {
2593315Sigor@sysoev.ru 
2594315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2595315Sigor@sysoev.ru             break;
2596315Sigor@sysoev.ru 
2597315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2598315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2599315Sigor@sysoev.ru             break;
2600315Sigor@sysoev.ru 
2601315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2602315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2603315Sigor@sysoev.ru             break;
2604315Sigor@sysoev.ru         }
2605315Sigor@sysoev.ru 
2606316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2607316Sigor@sysoev.ru 
260853Sigor@sysoev.ru         recf++;
260953Sigor@sysoev.ru     }
261053Sigor@sysoev.ru }
261153Sigor@sysoev.ru 
261253Sigor@sysoev.ru 
261353Sigor@sysoev.ru static void
2614315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
261553Sigor@sysoev.ru {
2616154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2617154Sigor@sysoev.ru 
2618315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2619154Sigor@sysoev.ru         next = work->next;
2620154Sigor@sysoev.ru         work->next = NULL;
2621154Sigor@sysoev.ru 
2622315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
262353Sigor@sysoev.ru     }
262453Sigor@sysoev.ru }
262553Sigor@sysoev.ru 
262653Sigor@sysoev.ru 
2627320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2628616Smax.romanov@nginx.com     .rpc_error = nxt_port_rpc_handler,
2629616Smax.romanov@nginx.com     .mmap      = nxt_port_mmap_handler,
2630616Smax.romanov@nginx.com     .data      = nxt_port_rpc_handler,
263188Smax.romanov@nginx.com };
263288Smax.romanov@nginx.com 
263388Smax.romanov@nginx.com 
263488Smax.romanov@nginx.com static void
263553Sigor@sysoev.ru nxt_router_thread_start(void *data)
263653Sigor@sysoev.ru {
2637141Smax.romanov@nginx.com     nxt_int_t           ret;
2638141Smax.romanov@nginx.com     nxt_port_t          *port;
263988Smax.romanov@nginx.com     nxt_task_t          *task;
264053Sigor@sysoev.ru     nxt_thread_t        *thread;
264153Sigor@sysoev.ru     nxt_thread_link_t   *link;
264253Sigor@sysoev.ru     nxt_event_engine_t  *engine;
264353Sigor@sysoev.ru 
264453Sigor@sysoev.ru     link = data;
264553Sigor@sysoev.ru     engine = link->engine;
264688Smax.romanov@nginx.com     task = &engine->task;
264753Sigor@sysoev.ru 
264853Sigor@sysoev.ru     thread = nxt_thread();
264953Sigor@sysoev.ru 
2650165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2651165Smax.romanov@nginx.com 
265253Sigor@sysoev.ru     /* STUB */
265353Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
265453Sigor@sysoev.ru 
265553Sigor@sysoev.ru     engine->task.thread = thread;
265653Sigor@sysoev.ru     engine->task.log = thread->log;
265753Sigor@sysoev.ru     thread->engine = engine;
265863Sigor@sysoev.ru     thread->task = &engine->task;
2659326Svbart@nginx.com #if 0
266053Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2661326Svbart@nginx.com #endif
266253Sigor@sysoev.ru 
266363Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2664337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2665337Sigor@sysoev.ru         return;
2666337Sigor@sysoev.ru     }
266753Sigor@sysoev.ru 
2668197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2669197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2670141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2671141Smax.romanov@nginx.com         return;
2672141Smax.romanov@nginx.com     }
2673141Smax.romanov@nginx.com 
2674141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2675141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2676343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2677141Smax.romanov@nginx.com         return;
2678141Smax.romanov@nginx.com     }
2679141Smax.romanov@nginx.com 
2680141Smax.romanov@nginx.com     engine->port = port;
2681141Smax.romanov@nginx.com 
2682320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2683141Smax.romanov@nginx.com 
268453Sigor@sysoev.ru     nxt_event_engine_start(engine);
268553Sigor@sysoev.ru }
268653Sigor@sysoev.ru 
268753Sigor@sysoev.ru 
268853Sigor@sysoev.ru static void
268953Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
269053Sigor@sysoev.ru {
2691153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2692359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2693359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
269453Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2695359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
269653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
269753Sigor@sysoev.ru 
2698153Sigor@sysoev.ru     job = obj;
269953Sigor@sysoev.ru     joint = data;
270053Sigor@sysoev.ru 
2701159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2702159Sigor@sysoev.ru 
2703359Sigor@sysoev.ru     skcf = joint->socket_conf;
2704359Sigor@sysoev.ru     ls = skcf->listen;
2705359Sigor@sysoev.ru 
2706359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2707359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2708359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
270953Sigor@sysoev.ru         return;
271053Sigor@sysoev.ru     }
271153Sigor@sysoev.ru 
2712359Sigor@sysoev.ru     lev->socket.data = joint;
2713359Sigor@sysoev.ru 
2714359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2715359Sigor@sysoev.ru 
2716359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2717359Sigor@sysoev.ru     ls->count++;
2718359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2719139Sigor@sysoev.ru 
2720153Sigor@sysoev.ru     job->work.next = NULL;
2721153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2722153Sigor@sysoev.ru 
2723153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
272453Sigor@sysoev.ru }
272553Sigor@sysoev.ru 
272653Sigor@sysoev.ru 
272753Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
272853Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
272953Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
273053Sigor@sysoev.ru {
2731115Sigor@sysoev.ru     nxt_socket_t        fd;
2732115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2733359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2734359Sigor@sysoev.ru 
2735359Sigor@sysoev.ru     fd = skcf->listen->socket;
273653Sigor@sysoev.ru 
2737115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2738115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2739115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
274053Sigor@sysoev.ru     {
2741359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2742359Sigor@sysoev.ru 
2743359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2744359Sigor@sysoev.ru             return lev;
274553Sigor@sysoev.ru         }
274653Sigor@sysoev.ru     }
274753Sigor@sysoev.ru 
274853Sigor@sysoev.ru     return NULL;
274953Sigor@sysoev.ru }
275053Sigor@sysoev.ru 
275153Sigor@sysoev.ru 
275253Sigor@sysoev.ru static void
275353Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
275453Sigor@sysoev.ru {
2755153Sigor@sysoev.ru     nxt_joint_job_t          *job;
275653Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2757359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
275853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
275953Sigor@sysoev.ru 
2760153Sigor@sysoev.ru     job = obj;
276153Sigor@sysoev.ru     joint = data;
276253Sigor@sysoev.ru 
2763139Sigor@sysoev.ru     engine = task->thread->engine;
2764139Sigor@sysoev.ru 
2765159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2766159Sigor@sysoev.ru 
2767359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2768359Sigor@sysoev.ru                                   joint->socket_conf);
2769359Sigor@sysoev.ru 
2770359Sigor@sysoev.ru     old = lev->socket.data;
2771359Sigor@sysoev.ru     lev->socket.data = joint;
2772359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
277353Sigor@sysoev.ru 
2774153Sigor@sysoev.ru     job->work.next = NULL;
2775153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2776153Sigor@sysoev.ru 
2777153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2778139Sigor@sysoev.ru 
2779181Smax.romanov@nginx.com     /*
2780181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2781181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2782181Smax.romanov@nginx.com      */
2783181Smax.romanov@nginx.com 
2784181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
278553Sigor@sysoev.ru }
278653Sigor@sysoev.ru 
278753Sigor@sysoev.ru 
278853Sigor@sysoev.ru static void
278953Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
279053Sigor@sysoev.ru {
2791153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2792153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2793359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2794153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2795153Sigor@sysoev.ru 
2796153Sigor@sysoev.ru     job = obj;
279753Sigor@sysoev.ru     skcf = data;
279853Sigor@sysoev.ru 
2799139Sigor@sysoev.ru     engine = task->thread->engine;
2800139Sigor@sysoev.ru 
2801359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2802359Sigor@sysoev.ru 
2803359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
280453Sigor@sysoev.ru 
2805163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2806359Sigor@sysoev.ru               lev->socket.fd);
2807359Sigor@sysoev.ru 
2808359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2809359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2810359Sigor@sysoev.ru 
2811359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2812139Sigor@sysoev.ru 
2813153Sigor@sysoev.ru     job->work.next = NULL;
2814153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2815153Sigor@sysoev.ru 
2816153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
281753Sigor@sysoev.ru }
281853Sigor@sysoev.ru 
281953Sigor@sysoev.ru 
282053Sigor@sysoev.ru static void
2821313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2822313Sigor@sysoev.ru {
2823313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2824313Sigor@sysoev.ru 
2825313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2826313Sigor@sysoev.ru 
2827313Sigor@sysoev.ru     engine = task->thread->engine;
2828313Sigor@sysoev.ru 
2829313Sigor@sysoev.ru     engine->shutdown = 1;
2830313Sigor@sysoev.ru 
2831313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2832313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2833313Sigor@sysoev.ru     }
2834313Sigor@sysoev.ru }
2835313Sigor@sysoev.ru 
2836313Sigor@sysoev.ru 
2837313Sigor@sysoev.ru static void
283853Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
283953Sigor@sysoev.ru {
284053Sigor@sysoev.ru     nxt_timer_t              *timer;
2841359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
284253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
284353Sigor@sysoev.ru 
284453Sigor@sysoev.ru     timer = obj;
2845359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
284653Sigor@sysoev.ru 
2847163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2848359Sigor@sysoev.ru               lev->socket.fd);
2849359Sigor@sysoev.ru 
2850359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2851359Sigor@sysoev.ru 
2852683Sigor@sysoev.ru     joint = lev->socket.data;
2853683Sigor@sysoev.ru     lev->socket.data = NULL;
2854683Sigor@sysoev.ru 
2855359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2856123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2857123Smax.romanov@nginx.com 
2858359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2859359Sigor@sysoev.ru 
2860683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
286153Sigor@sysoev.ru }
286253Sigor@sysoev.ru 
286353Sigor@sysoev.ru 
286453Sigor@sysoev.ru static void
2865359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
286653Sigor@sysoev.ru {
2867359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
286853Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
286953Sigor@sysoev.ru 
2870359Sigor@sysoev.ru     ls = skcf->listen;
2871118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
287253Sigor@sysoev.ru 
287353Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
287453Sigor@sysoev.ru 
2875359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2876359Sigor@sysoev.ru               task->thread->engine, ls->count);
2877359Sigor@sysoev.ru 
2878359Sigor@sysoev.ru     if (--ls->count != 0) {
2879359Sigor@sysoev.ru         ls = NULL;
288053Sigor@sysoev.ru     }
288153Sigor@sysoev.ru 
288253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
288353Sigor@sysoev.ru 
2884359Sigor@sysoev.ru     if (ls != NULL) {
2885359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
2886359Sigor@sysoev.ru         nxt_free(ls);
288753Sigor@sysoev.ru     }
288853Sigor@sysoev.ru }
288953Sigor@sysoev.ru 
289053Sigor@sysoev.ru 
2891683Sigor@sysoev.ru void
2892683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
2893683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
2894683Sigor@sysoev.ru {
2895683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2896683Sigor@sysoev.ru 
2897683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
2898683Sigor@sysoev.ru 
2899683Sigor@sysoev.ru     if (--lev->count == 0) {
2900683Sigor@sysoev.ru         nxt_free(lev);
2901683Sigor@sysoev.ru     }
2902683Sigor@sysoev.ru 
2903683Sigor@sysoev.ru     if (joint != NULL) {
2904683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
2905683Sigor@sysoev.ru     }
2906683Sigor@sysoev.ru 
2907683Sigor@sysoev.ru     engine = task->thread->engine;
2908683Sigor@sysoev.ru 
2909683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
2910683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2911683Sigor@sysoev.ru     }
2912683Sigor@sysoev.ru }
2913683Sigor@sysoev.ru 
2914683Sigor@sysoev.ru 
2915683Sigor@sysoev.ru void
291653Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
291753Sigor@sysoev.ru {
291853Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
291953Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
292053Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
292153Sigor@sysoev.ru 
2922163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
292353Sigor@sysoev.ru 
292453Sigor@sysoev.ru     if (--joint->count != 0) {
292553Sigor@sysoev.ru         return;
292653Sigor@sysoev.ru     }
292753Sigor@sysoev.ru 
292853Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
292953Sigor@sysoev.ru 
2930530Sigor@sysoev.ru     /*
2931530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
2932530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
2933530Sigor@sysoev.ru      * be already destroyed by another thread.
2934530Sigor@sysoev.ru      */
293553Sigor@sysoev.ru     skcf = joint->socket_conf;
293653Sigor@sysoev.ru     rtcf = skcf->router_conf;
293753Sigor@sysoev.ru     lock = &rtcf->router->lock;
293853Sigor@sysoev.ru 
293953Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
294053Sigor@sysoev.ru 
2941163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2942163Smax.romanov@nginx.com               rtcf, rtcf->count);
2943163Smax.romanov@nginx.com 
294453Sigor@sysoev.ru     if (--skcf->count != 0) {
2945952Sigor@sysoev.ru         skcf = NULL;
294653Sigor@sysoev.ru         rtcf = NULL;
294753Sigor@sysoev.ru 
294853Sigor@sysoev.ru     } else {
294953Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
295053Sigor@sysoev.ru 
295153Sigor@sysoev.ru         if (--rtcf->count != 0) {
295253Sigor@sysoev.ru             rtcf = NULL;
295353Sigor@sysoev.ru         }
295453Sigor@sysoev.ru     }
295553Sigor@sysoev.ru 
295653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
295753Sigor@sysoev.ru 
2958952Sigor@sysoev.ru     if (skcf != NULL) {
2959964Sigor@sysoev.ru         if (skcf->pass != NULL) {
2960964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
2961964Sigor@sysoev.ru         }
2962964Sigor@sysoev.ru 
2963952Sigor@sysoev.ru #if (NXT_TLS)
2964952Sigor@sysoev.ru         if (skcf->tls != NULL) {
2965952Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
2966952Sigor@sysoev.ru         }
2967952Sigor@sysoev.ru #endif
2968952Sigor@sysoev.ru     }
2969952Sigor@sysoev.ru 
2970141Smax.romanov@nginx.com     /* TODO remove engine->port */
2971141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2972141Smax.romanov@nginx.com 
297353Sigor@sysoev.ru     if (rtcf != NULL) {
2974115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2975131Smax.romanov@nginx.com 
2976964Sigor@sysoev.ru         nxt_http_routes_cleanup(task, rtcf->routes);
2977964Sigor@sysoev.ru 
2978630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
2979630Svbart@nginx.com 
2980131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2981131Smax.romanov@nginx.com 
298265Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
298353Sigor@sysoev.ru     }
298453Sigor@sysoev.ru }
298553Sigor@sysoev.ru 
298653Sigor@sysoev.ru 
298753Sigor@sysoev.ru static void
2988630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
2989630Svbart@nginx.com     nxt_router_access_log_t *access_log)
2990630Svbart@nginx.com {
2991630Svbart@nginx.com     size_t     size;
2992630Svbart@nginx.com     u_char     *buf, *p;
2993630Svbart@nginx.com     nxt_off_t  bytes;
2994630Svbart@nginx.com 
2995630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
2996630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
2997630Svbart@nginx.com         nxt_router_access_log_date,
2998630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
2999703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
3000630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
3001630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
3002630Svbart@nginx.com     };
3003630Svbart@nginx.com 
3004630Svbart@nginx.com     size = r->remote->address_length
3005630Svbart@nginx.com            + 6                  /* ' - - [' */
3006630Svbart@nginx.com            + date_cache.size
3007630Svbart@nginx.com            + 3                  /* '] "' */
3008630Svbart@nginx.com            + r->method->length
3009630Svbart@nginx.com            + 1                  /* space */
3010630Svbart@nginx.com            + r->target.length
3011630Svbart@nginx.com            + 1                  /* space */
3012630Svbart@nginx.com            + r->version.length
3013630Svbart@nginx.com            + 2                  /* '" ' */
3014630Svbart@nginx.com            + 3                  /* status */
3015630Svbart@nginx.com            + 1                  /* space */
3016630Svbart@nginx.com            + NXT_OFF_T_LEN
3017630Svbart@nginx.com            + 2                  /* ' "' */
3018630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3019630Svbart@nginx.com            + 3                  /* '" "' */
3020630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3021630Svbart@nginx.com            + 2                  /* '"\n' */
3022630Svbart@nginx.com     ;
3023630Svbart@nginx.com 
3024630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3025630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3026630Svbart@nginx.com         return;
3027630Svbart@nginx.com     }
3028630Svbart@nginx.com 
3029630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3030630Svbart@nginx.com                    r->remote->address_length);
3031630Svbart@nginx.com 
3032630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3033630Svbart@nginx.com 
3034630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3035630Svbart@nginx.com 
3036630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3037630Svbart@nginx.com 
3038630Svbart@nginx.com     if (r->method->length != 0) {
3039630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3040630Svbart@nginx.com 
3041630Svbart@nginx.com         if (r->target.length != 0) {
3042630Svbart@nginx.com             *p++ = ' ';
3043630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3044630Svbart@nginx.com 
3045630Svbart@nginx.com             if (r->version.length != 0) {
3046630Svbart@nginx.com                 *p++ = ' ';
3047630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3048630Svbart@nginx.com             }
3049630Svbart@nginx.com         }
3050630Svbart@nginx.com 
3051630Svbart@nginx.com     } else {
3052630Svbart@nginx.com         *p++ = '-';
3053630Svbart@nginx.com     }
3054630Svbart@nginx.com 
3055630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3056630Svbart@nginx.com 
3057630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3058630Svbart@nginx.com 
3059630Svbart@nginx.com     *p++ = ' ';
3060630Svbart@nginx.com 
3061630Svbart@nginx.com     bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto);
3062630Svbart@nginx.com 
3063630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3064630Svbart@nginx.com 
3065630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3066630Svbart@nginx.com 
3067630Svbart@nginx.com     if (r->referer != NULL) {
3068630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3069630Svbart@nginx.com 
3070630Svbart@nginx.com     } else {
3071630Svbart@nginx.com         *p++ = '-';
3072630Svbart@nginx.com     }
3073630Svbart@nginx.com 
3074630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3075630Svbart@nginx.com 
3076630Svbart@nginx.com     if (r->user_agent != NULL) {
3077630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3078630Svbart@nginx.com 
3079630Svbart@nginx.com     } else {
3080630Svbart@nginx.com         *p++ = '-';
3081630Svbart@nginx.com     }
3082630Svbart@nginx.com 
3083630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3084630Svbart@nginx.com 
3085630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3086630Svbart@nginx.com }
3087630Svbart@nginx.com 
3088630Svbart@nginx.com 
3089630Svbart@nginx.com static u_char *
3090630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3091630Svbart@nginx.com     size_t size, const char *format)
3092630Svbart@nginx.com {
3093630Svbart@nginx.com     u_char  sign;
3094630Svbart@nginx.com     time_t  gmtoff;
3095630Svbart@nginx.com 
3096630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3097630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3098630Svbart@nginx.com 
3099630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3100630Svbart@nginx.com 
3101630Svbart@nginx.com     if (gmtoff < 0) {
3102630Svbart@nginx.com         gmtoff = -gmtoff;
3103630Svbart@nginx.com         sign = '-';
3104630Svbart@nginx.com 
3105630Svbart@nginx.com     } else {
3106630Svbart@nginx.com         sign = '+';
3107630Svbart@nginx.com     }
3108630Svbart@nginx.com 
3109630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3110630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3111630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3112630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3113630Svbart@nginx.com }
3114630Svbart@nginx.com 
3115630Svbart@nginx.com 
3116630Svbart@nginx.com static void
3117630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3118630Svbart@nginx.com {
3119630Svbart@nginx.com     uint32_t                 stream;
3120648Svbart@nginx.com     nxt_int_t                ret;
3121630Svbart@nginx.com     nxt_buf_t                *b;
3122630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3123630Svbart@nginx.com     nxt_runtime_t            *rt;
3124630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3125630Svbart@nginx.com 
3126630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3127630Svbart@nginx.com 
3128630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3129630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3130630Svbart@nginx.com         goto fail;
3131630Svbart@nginx.com     }
3132630Svbart@nginx.com 
3133630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3134630Svbart@nginx.com     *b->mem.free++ = '\0';
3135630Svbart@nginx.com 
3136630Svbart@nginx.com     rt = task->thread->runtime;
3137630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3138630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3139630Svbart@nginx.com 
3140630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3141630Svbart@nginx.com                                            nxt_router_access_log_ready,
3142630Svbart@nginx.com                                            nxt_router_access_log_error,
3143630Svbart@nginx.com                                            -1, tmcf);
3144630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3145630Svbart@nginx.com         goto fail;
3146630Svbart@nginx.com     }
3147630Svbart@nginx.com 
3148648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3149648Svbart@nginx.com                                 stream, router_port->id, b);
3150648Svbart@nginx.com 
3151648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3152648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3153648Svbart@nginx.com         goto fail;
3154648Svbart@nginx.com     }
3155630Svbart@nginx.com 
3156630Svbart@nginx.com     return;
3157630Svbart@nginx.com 
3158630Svbart@nginx.com fail:
3159630Svbart@nginx.com 
3160630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3161630Svbart@nginx.com }
3162630Svbart@nginx.com 
3163630Svbart@nginx.com 
3164630Svbart@nginx.com static void
3165630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3166630Svbart@nginx.com     void *data)
3167630Svbart@nginx.com {
3168630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3169630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3170630Svbart@nginx.com 
3171630Svbart@nginx.com     tmcf = data;
3172630Svbart@nginx.com 
3173630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3174630Svbart@nginx.com 
3175630Svbart@nginx.com     access_log->fd = msg->fd;
3176630Svbart@nginx.com 
3177630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3178630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3179630Svbart@nginx.com }
3180630Svbart@nginx.com 
3181630Svbart@nginx.com 
3182630Svbart@nginx.com static void
3183630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3184630Svbart@nginx.com     void *data)
3185630Svbart@nginx.com {
3186630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3187630Svbart@nginx.com 
3188630Svbart@nginx.com     tmcf = data;
3189630Svbart@nginx.com 
3190630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3191630Svbart@nginx.com }
3192630Svbart@nginx.com 
3193630Svbart@nginx.com 
3194630Svbart@nginx.com static void
3195630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3196630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3197630Svbart@nginx.com {
3198630Svbart@nginx.com     if (access_log == NULL) {
3199630Svbart@nginx.com         return;
3200630Svbart@nginx.com     }
3201630Svbart@nginx.com 
3202630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3203630Svbart@nginx.com 
3204630Svbart@nginx.com     if (--access_log->count != 0) {
3205630Svbart@nginx.com         access_log = NULL;
3206630Svbart@nginx.com     }
3207630Svbart@nginx.com 
3208630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3209630Svbart@nginx.com 
3210630Svbart@nginx.com     if (access_log != NULL) {
3211630Svbart@nginx.com 
3212630Svbart@nginx.com         if (access_log->fd != -1) {
3213630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3214630Svbart@nginx.com         }
3215630Svbart@nginx.com 
3216630Svbart@nginx.com         nxt_free(access_log);
3217630Svbart@nginx.com     }
3218630Svbart@nginx.com }
3219630Svbart@nginx.com 
3220630Svbart@nginx.com 
3221631Svbart@nginx.com typedef struct {
3222631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3223631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3224631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3225631Svbart@nginx.com 
3226631Svbart@nginx.com 
3227631Svbart@nginx.com void
3228631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3229631Svbart@nginx.com {
3230631Svbart@nginx.com     nxt_mp_t                        *mp;
3231631Svbart@nginx.com     uint32_t                        stream;
3232631Svbart@nginx.com     nxt_int_t                       ret;
3233631Svbart@nginx.com     nxt_buf_t                       *b;
3234631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3235631Svbart@nginx.com     nxt_runtime_t                   *rt;
3236631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3237631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3238631Svbart@nginx.com 
3239631Svbart@nginx.com     access_log = nxt_router->access_log;
3240631Svbart@nginx.com 
3241631Svbart@nginx.com     if (access_log == NULL) {
3242631Svbart@nginx.com         return;
3243631Svbart@nginx.com     }
3244631Svbart@nginx.com 
3245631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3246631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3247631Svbart@nginx.com         return;
3248631Svbart@nginx.com     }
3249631Svbart@nginx.com 
3250631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3251631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3252631Svbart@nginx.com         goto fail;
3253631Svbart@nginx.com     }
3254631Svbart@nginx.com 
3255631Svbart@nginx.com     reopen->mem_pool = mp;
3256631Svbart@nginx.com     reopen->access_log = access_log;
3257631Svbart@nginx.com 
3258631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3259631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3260631Svbart@nginx.com         goto fail;
3261631Svbart@nginx.com     }
3262631Svbart@nginx.com 
3263651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3264651Svbart@nginx.com 
3265631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3266631Svbart@nginx.com     *b->mem.free++ = '\0';
3267631Svbart@nginx.com 
3268631Svbart@nginx.com     rt = task->thread->runtime;
3269631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3270631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3271631Svbart@nginx.com 
3272631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3273631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3274631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3275631Svbart@nginx.com                                            -1, reopen);
3276631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3277631Svbart@nginx.com         goto fail;
3278631Svbart@nginx.com     }
3279631Svbart@nginx.com 
3280631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3281631Svbart@nginx.com                                 stream, router_port->id, b);
3282631Svbart@nginx.com 
3283631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3284631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3285631Svbart@nginx.com         goto fail;
3286631Svbart@nginx.com     }
3287631Svbart@nginx.com 
3288651Svbart@nginx.com     nxt_mp_retain(mp);
3289651Svbart@nginx.com 
3290631Svbart@nginx.com     return;
3291631Svbart@nginx.com 
3292631Svbart@nginx.com fail:
3293631Svbart@nginx.com 
3294631Svbart@nginx.com     nxt_mp_destroy(mp);
3295631Svbart@nginx.com }
3296631Svbart@nginx.com 
3297631Svbart@nginx.com 
3298631Svbart@nginx.com static void
3299651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3300651Svbart@nginx.com {
3301651Svbart@nginx.com     nxt_mp_t   *mp;
3302651Svbart@nginx.com     nxt_buf_t  *b;
3303651Svbart@nginx.com 
3304651Svbart@nginx.com     b = obj;
3305651Svbart@nginx.com     mp = b->data;
3306651Svbart@nginx.com 
3307651Svbart@nginx.com     nxt_mp_release(mp);
3308651Svbart@nginx.com }
3309651Svbart@nginx.com 
3310651Svbart@nginx.com 
3311651Svbart@nginx.com static void
3312631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3313631Svbart@nginx.com     void *data)
3314631Svbart@nginx.com {
3315631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3316631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3317631Svbart@nginx.com 
3318631Svbart@nginx.com     reopen = data;
3319631Svbart@nginx.com 
3320631Svbart@nginx.com     access_log = reopen->access_log;
3321631Svbart@nginx.com 
3322631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3323631Svbart@nginx.com 
3324631Svbart@nginx.com         if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) {
3325631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3326631Svbart@nginx.com                       msg->fd, access_log->fd, nxt_errno);
3327631Svbart@nginx.com         }
3328631Svbart@nginx.com     }
3329631Svbart@nginx.com 
3330631Svbart@nginx.com     nxt_fd_close(msg->fd);
3331651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3332631Svbart@nginx.com }
3333631Svbart@nginx.com 
3334631Svbart@nginx.com 
3335631Svbart@nginx.com static void
3336631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3337631Svbart@nginx.com     void *data)
3338631Svbart@nginx.com {
3339631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3340631Svbart@nginx.com 
3341631Svbart@nginx.com     reopen = data;
3342631Svbart@nginx.com 
3343651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3344631Svbart@nginx.com }
3345631Svbart@nginx.com 
3346631Svbart@nginx.com 
3347630Svbart@nginx.com static void
334853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
334953Sigor@sysoev.ru {
3350141Smax.romanov@nginx.com     nxt_port_t           *port;
335153Sigor@sysoev.ru     nxt_thread_link_t    *link;
335253Sigor@sysoev.ru     nxt_event_engine_t   *engine;
335353Sigor@sysoev.ru     nxt_thread_handle_t  handle;
335453Sigor@sysoev.ru 
335558Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
335653Sigor@sysoev.ru     link = data;
335753Sigor@sysoev.ru 
335853Sigor@sysoev.ru     nxt_thread_wait(handle);
335953Sigor@sysoev.ru 
336053Sigor@sysoev.ru     engine = link->engine;
336153Sigor@sysoev.ru 
336253Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
336353Sigor@sysoev.ru 
3364141Smax.romanov@nginx.com     port = engine->port;
3365141Smax.romanov@nginx.com 
3366141Smax.romanov@nginx.com     // TODO notify all apps
3367141Smax.romanov@nginx.com 
3368343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3369163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3370343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3371163Smax.romanov@nginx.com 
3372163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
337363Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
337453Sigor@sysoev.ru 
337553Sigor@sysoev.ru     nxt_event_engine_free(engine);
337653Sigor@sysoev.ru 
337753Sigor@sysoev.ru     nxt_free(link);
337853Sigor@sysoev.ru }
337953Sigor@sysoev.ru 
338053Sigor@sysoev.ru 
338153Sigor@sysoev.ru static void
3382318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3383318Smax.romanov@nginx.com     void *data)
338488Smax.romanov@nginx.com {
338588Smax.romanov@nginx.com     size_t               dump_size;
3386431Sigor@sysoev.ru     nxt_int_t            ret;
3387608Sigor@sysoev.ru     nxt_buf_t            *b;
3388*1007Salexander.borisov@nginx.com     nxt_unit_field_t     *f;
3389*1007Salexander.borisov@nginx.com     nxt_http_field_t     *field;
3390431Sigor@sysoev.ru     nxt_http_request_t   *r;
339188Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3392743Smax.romanov@nginx.com     nxt_unit_response_t  *resp;
339388Smax.romanov@nginx.com 
339488Smax.romanov@nginx.com     b = msg->buf;
3395318Smax.romanov@nginx.com     rc = data;
339688Smax.romanov@nginx.com 
339788Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
339888Smax.romanov@nginx.com 
339988Smax.romanov@nginx.com     if (dump_size > 300) {
340088Smax.romanov@nginx.com         dump_size = 300;
340188Smax.romanov@nginx.com     }
340288Smax.romanov@nginx.com 
340388Smax.romanov@nginx.com     if (msg->size == 0) {
340488Smax.romanov@nginx.com         b = NULL;
340588Smax.romanov@nginx.com     }
340688Smax.romanov@nginx.com 
3407*1007Salexander.borisov@nginx.com     r = rc->request;
3408*1007Salexander.borisov@nginx.com     if (nxt_slow_path(r == NULL)) {
3409570Smax.romanov@nginx.com         return;
3410570Smax.romanov@nginx.com     }
3411425Smax.romanov@nginx.com 
3412*1007Salexander.borisov@nginx.com     if (r->error) {
3413608Sigor@sysoev.ru         nxt_router_rc_unlink(task, rc);
3414608Sigor@sysoev.ru         return;
3415608Sigor@sysoev.ru     }
3416608Sigor@sysoev.ru 
341788Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
341888Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
341988Smax.romanov@nginx.com 
3420*1007Salexander.borisov@nginx.com         nxt_buf_chain_add(&b, nxt_http_buf_last(r));
3421167Smax.romanov@nginx.com 
3422343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3423425Smax.romanov@nginx.com 
3424425Smax.romanov@nginx.com     } else {
3425615Smax.romanov@nginx.com         if (rc->app != NULL && rc->app->timeout != 0) {
3426*1007Salexander.borisov@nginx.com             r->timer.handler = nxt_router_app_timeout;
3427*1007Salexander.borisov@nginx.com             r->timer_data = rc;
3428*1007Salexander.borisov@nginx.com             nxt_timer_add(task->thread->engine, &r->timer, rc->app->timeout);
3429425Smax.romanov@nginx.com         }
343088Smax.romanov@nginx.com     }
343188Smax.romanov@nginx.com 
343288Smax.romanov@nginx.com     if (b == NULL) {
343388Smax.romanov@nginx.com         return;
343488Smax.romanov@nginx.com     }
343588Smax.romanov@nginx.com 
3436206Smax.romanov@nginx.com     if (msg->buf == b) {
3437206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3438206Smax.romanov@nginx.com         msg->buf = NULL;
3439206Smax.romanov@nginx.com     }
3440194Smax.romanov@nginx.com 
3441431Sigor@sysoev.ru     if (r->header_sent) {
3442431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3443431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3444277Sigor@sysoev.ru 
344588Smax.romanov@nginx.com     } else {
3446743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3447743Smax.romanov@nginx.com 
3448743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3449743Smax.romanov@nginx.com             goto fail;
3450743Smax.romanov@nginx.com         }
3451743Smax.romanov@nginx.com 
3452743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3453743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3454743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3455743Smax.romanov@nginx.com             goto fail;
3456743Smax.romanov@nginx.com         }
3457743Smax.romanov@nginx.com 
3458743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
3459*1007Salexander.borisov@nginx.com             field = nxt_list_add(r->resp.fields);
3460743Smax.romanov@nginx.com 
3461743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3462743Smax.romanov@nginx.com                 goto fail;
3463743Smax.romanov@nginx.com             }
3464743Smax.romanov@nginx.com 
3465743Smax.romanov@nginx.com             field->hash = f->hash;
3466743Smax.romanov@nginx.com             field->skip = f->skip;
3467743Smax.romanov@nginx.com 
3468743Smax.romanov@nginx.com             field->name_length = f->name_length;
3469743Smax.romanov@nginx.com             field->value_length = f->value_length;
3470743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3471743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3472743Smax.romanov@nginx.com 
3473743Smax.romanov@nginx.com             nxt_debug(task, "header: %*s: %*s",
3474743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3475743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
3476743Smax.romanov@nginx.com         }
3477*1007Salexander.borisov@nginx.com 
3478743Smax.romanov@nginx.com         r->status = resp->status;
3479743Smax.romanov@nginx.com 
3480431Sigor@sysoev.ru         ret = nxt_http_fields_process(r->resp.fields,
3481431Sigor@sysoev.ru                                       &nxt_response_fields_hash, r);
3482431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
3483431Sigor@sysoev.ru             goto fail;
3484431Sigor@sysoev.ru         }
3485431Sigor@sysoev.ru 
3486743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3487743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3488743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3489743Smax.romanov@nginx.com 
3490743Smax.romanov@nginx.com         } else {
3491743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3492743Smax.romanov@nginx.com         }
3493743Smax.romanov@nginx.com 
3494435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
3495435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3496435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3497507Smax.romanov@nginx.com 
3498520Smax.romanov@nginx.com             b = b->next;
3499520Smax.romanov@nginx.com         }
3500520Smax.romanov@nginx.com 
3501520Smax.romanov@nginx.com         if (b != NULL) {
3502431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3503431Sigor@sysoev.ru         }
3504431Sigor@sysoev.ru 
3505431Sigor@sysoev.ru         r->state = &nxt_http_request_send_state;
3506431Sigor@sysoev.ru 
3507431Sigor@sysoev.ru         nxt_http_request_header_send(task, r);
3508431Sigor@sysoev.ru     }
3509431Sigor@sysoev.ru 
3510431Sigor@sysoev.ru     return;
3511431Sigor@sysoev.ru 
3512431Sigor@sysoev.ru fail:
3513431Sigor@sysoev.ru 
3514615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3515615Smax.romanov@nginx.com 
3516431Sigor@sysoev.ru     nxt_router_rc_unlink(task, rc);
3517431Sigor@sysoev.ru }
3518431Sigor@sysoev.ru 
3519431Sigor@sysoev.ru 
3520431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3521431Sigor@sysoev.ru     nxt_aligned(64) =
3522431Sigor@sysoev.ru {
3523431Sigor@sysoev.ru     .ready_handler = nxt_http_request_send_body,
3524943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
3525431Sigor@sysoev.ru };
3526431Sigor@sysoev.ru 
3527431Sigor@sysoev.ru 
3528431Sigor@sysoev.ru static void
3529431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3530431Sigor@sysoev.ru {
3531431Sigor@sysoev.ru     nxt_buf_t           *out;
3532431Sigor@sysoev.ru     nxt_http_request_t  *r;
3533431Sigor@sysoev.ru 
3534431Sigor@sysoev.ru     r = obj;
3535431Sigor@sysoev.ru 
3536431Sigor@sysoev.ru     out = r->out;
3537431Sigor@sysoev.ru 
3538431Sigor@sysoev.ru     if (out != NULL) {
3539431Sigor@sysoev.ru         r->out = NULL;
3540431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
354188Smax.romanov@nginx.com     }
354288Smax.romanov@nginx.com }
354388Smax.romanov@nginx.com 
3544277Sigor@sysoev.ru 
3545318Smax.romanov@nginx.com static void
3546318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3547318Smax.romanov@nginx.com     void *data)
3548318Smax.romanov@nginx.com {
3549425Smax.romanov@nginx.com     nxt_int_t            res;
3550425Smax.romanov@nginx.com     nxt_port_t           *port;
3551425Smax.romanov@nginx.com     nxt_bool_t           cancelled;
3552425Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
3553318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3554318Smax.romanov@nginx.com 
3555318Smax.romanov@nginx.com     rc = data;
3556318Smax.romanov@nginx.com 
3557425Smax.romanov@nginx.com     ra = rc->ra;
3558425Smax.romanov@nginx.com 
3559425Smax.romanov@nginx.com     if (ra != NULL) {
3560425Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
3561425Smax.romanov@nginx.com 
3562425Smax.romanov@nginx.com         if (cancelled) {
3563425Smax.romanov@nginx.com             nxt_router_ra_inc_use(ra);
3564425Smax.romanov@nginx.com 
3565427Smax.romanov@nginx.com             res = nxt_router_app_port(task, rc->app, ra);
3566425Smax.romanov@nginx.com 
3567425Smax.romanov@nginx.com             if (res == NXT_OK) {
3568425Smax.romanov@nginx.com                 port = ra->app_port;
3569425Smax.romanov@nginx.com 
3570551Smax.romanov@nginx.com                 if (nxt_slow_path(port == NULL)) {
3571551Smax.romanov@nginx.com                     nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra");
3572551Smax.romanov@nginx.com                     return;
3573551Smax.romanov@nginx.com                 }
3574425Smax.romanov@nginx.com 
3575425Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc,
3576425Smax.romanov@nginx.com                                          port->pid);
3577425Smax.romanov@nginx.com 
3578425Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, ra);
3579425Smax.romanov@nginx.com             }
3580425Smax.romanov@nginx.com 
3581425Smax.romanov@nginx.com             msg->port_msg.last = 0;
3582425Smax.romanov@nginx.com 
3583425Smax.romanov@nginx.com             return;
3584425Smax.romanov@nginx.com         }
3585425Smax.romanov@nginx.com     }
3586425Smax.romanov@nginx.com 
3587*1007Salexander.borisov@nginx.com     if (rc->request != NULL) {
3588*1007Salexander.borisov@nginx.com         nxt_http_request_error(task, rc->request,
3589616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3590616Smax.romanov@nginx.com     }
3591318Smax.romanov@nginx.com 
3592343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
3593318Smax.romanov@nginx.com }
3594318Smax.romanov@nginx.com 
3595318Smax.romanov@nginx.com 
3596141Smax.romanov@nginx.com static void
3597343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3598343Smax.romanov@nginx.com     void *data)
3599192Smax.romanov@nginx.com {
3600753Smax.romanov@nginx.com     nxt_app_t        *app;
3601753Smax.romanov@nginx.com     nxt_port_t       *port;
3602753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3603753Smax.romanov@nginx.com 
3604753Smax.romanov@nginx.com     app_joint = data;
3605347Smax.romanov@nginx.com     port = msg->u.new_port;
3606343Smax.romanov@nginx.com 
3607753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3608343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3609343Smax.romanov@nginx.com 
3610753Smax.romanov@nginx.com     app = app_joint->app;
3611753Smax.romanov@nginx.com 
3612753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3613753Smax.romanov@nginx.com 
3614753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3615753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3616753Smax.romanov@nginx.com 
3617753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3618753Smax.romanov@nginx.com 
3619753Smax.romanov@nginx.com         return;
3620753Smax.romanov@nginx.com     }
3621753Smax.romanov@nginx.com 
3622343Smax.romanov@nginx.com     port->app = app;
3623343Smax.romanov@nginx.com 
3624343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3625343Smax.romanov@nginx.com 
3626507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3627507Smax.romanov@nginx.com 
3628507Smax.romanov@nginx.com     app->pending_processes--;
3629507Smax.romanov@nginx.com     app->processes++;
3630343Smax.romanov@nginx.com 
3631343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3632343Smax.romanov@nginx.com 
3633507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3634507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3635343Smax.romanov@nginx.com 
3636343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
3637192Smax.romanov@nginx.com }
3638192Smax.romanov@nginx.com 
3639192Smax.romanov@nginx.com 
3640192Smax.romanov@nginx.com static void
3641343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3642343Smax.romanov@nginx.com     void *data)
3643192Smax.romanov@nginx.com {
3644318Smax.romanov@nginx.com     nxt_app_t           *app;
3645753Smax.romanov@nginx.com     nxt_app_joint_t     *app_joint;
3646318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
3647318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3648343Smax.romanov@nginx.com 
3649753Smax.romanov@nginx.com     app_joint = data;
3650753Smax.romanov@nginx.com 
3651753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3652753Smax.romanov@nginx.com 
3653753Smax.romanov@nginx.com     app = app_joint->app;
3654753Smax.romanov@nginx.com 
3655753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3656753Smax.romanov@nginx.com 
3657753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3658753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
3659753Smax.romanov@nginx.com 
3660753Smax.romanov@nginx.com         return;
3661753Smax.romanov@nginx.com     }
3662343Smax.romanov@nginx.com 
3663343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
3664343Smax.romanov@nginx.com 
3665343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3666343Smax.romanov@nginx.com 
3667507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3668507Smax.romanov@nginx.com 
3669507Smax.romanov@nginx.com     app->pending_processes--;
3670318Smax.romanov@nginx.com 
3671318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
3672318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
3673318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3674343Smax.romanov@nginx.com         lnk->next = NULL;
3675318Smax.romanov@nginx.com 
3676425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3677318Smax.romanov@nginx.com 
3678343Smax.romanov@nginx.com     } else {
3679343Smax.romanov@nginx.com         ra = NULL;
3680343Smax.romanov@nginx.com     }
3681343Smax.romanov@nginx.com 
3682343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3683343Smax.romanov@nginx.com 
3684343Smax.romanov@nginx.com     if (ra != NULL) {
3685318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
3686318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
3687318Smax.romanov@nginx.com 
3688507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start application process");
3689425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3690318Smax.romanov@nginx.com     }
3691192Smax.romanov@nginx.com }
3692192Smax.romanov@nginx.com 
3693753Smax.romanov@nginx.com nxt_inline nxt_port_t *
3694753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app);
3695192Smax.romanov@nginx.com 
3696343Smax.romanov@nginx.com void
3697343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
3698141Smax.romanov@nginx.com {
3699343Smax.romanov@nginx.com     int  c;
3700343Smax.romanov@nginx.com 
3701343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
3702343Smax.romanov@nginx.com 
3703343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
3704343Smax.romanov@nginx.com 
3705753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
3706753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
3707753Smax.romanov@nginx.com 
3708753Smax.romanov@nginx.com         } else {
3709753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
3710753Smax.romanov@nginx.com         }
3711163Smax.romanov@nginx.com     }
3712343Smax.romanov@nginx.com }
3713343Smax.romanov@nginx.com 
3714343Smax.romanov@nginx.com 
3715424Smax.romanov@nginx.com nxt_inline nxt_bool_t
3716424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
3717424Smax.romanov@nginx.com {
3718424Smax.romanov@nginx.com     nxt_port_t        *port;
3719424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3720424Smax.romanov@nginx.com 
3721424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3722424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3723424Smax.romanov@nginx.com 
3724424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
3725424Smax.romanov@nginx.com }
3726424Smax.romanov@nginx.com 
3727424Smax.romanov@nginx.com 
3728343Smax.romanov@nginx.com nxt_inline nxt_port_t *
3729427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
3730343Smax.romanov@nginx.com {
3731343Smax.romanov@nginx.com     nxt_port_t        *port;
3732343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3733343Smax.romanov@nginx.com 
3734343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3735343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
3736343Smax.romanov@nginx.com 
3737343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3738343Smax.romanov@nginx.com 
3739424Smax.romanov@nginx.com     port->app_pending_responses++;
3740424Smax.romanov@nginx.com 
3741507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3742507Smax.romanov@nginx.com         app->idle_processes--;
3743507Smax.romanov@nginx.com 
3744507Smax.romanov@nginx.com         if (port->idle_start == 0) {
3745507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
3746507Smax.romanov@nginx.com 
3747507Smax.romanov@nginx.com         } else {
3748507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
3749507Smax.romanov@nginx.com 
3750507Smax.romanov@nginx.com             port->idle_start = 0;
3751507Smax.romanov@nginx.com         }
3752507Smax.romanov@nginx.com     }
3753507Smax.romanov@nginx.com 
3754428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
3755428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3756428Smax.romanov@nginx.com         && (app->max_requests == 0
3757428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3758428Smax.romanov@nginx.com                 < app->max_requests))
3759277Sigor@sysoev.ru     {
3760343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
3761343Smax.romanov@nginx.com 
3762425Smax.romanov@nginx.com         nxt_port_inc_use(port);
3763425Smax.romanov@nginx.com 
3764343Smax.romanov@nginx.com     } else {
3765343Smax.romanov@nginx.com         lnk->next = NULL;
3766167Smax.romanov@nginx.com     }
3767167Smax.romanov@nginx.com 
3768343Smax.romanov@nginx.com     return port;
3769163Smax.romanov@nginx.com }
3770163Smax.romanov@nginx.com 
3771163Smax.romanov@nginx.com 
3772507Smax.romanov@nginx.com nxt_inline nxt_port_t *
3773507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
3774141Smax.romanov@nginx.com {
3775343Smax.romanov@nginx.com     nxt_port_t  *port;
3776141Smax.romanov@nginx.com 
3777141Smax.romanov@nginx.com     port = NULL;
3778141Smax.romanov@nginx.com 
3779141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3780141Smax.romanov@nginx.com 
3781343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
3782343Smax.romanov@nginx.com 
3783424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
3784343Smax.romanov@nginx.com             port = NULL;
3785343Smax.romanov@nginx.com 
3786343Smax.romanov@nginx.com             continue;
3787343Smax.romanov@nginx.com         }
3788343Smax.romanov@nginx.com 
3789507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
3790507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
3791507Smax.romanov@nginx.com 
3792507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
3793507Smax.romanov@nginx.com             app->idle_processes--;
3794507Smax.romanov@nginx.com         }
3795507Smax.romanov@nginx.com 
3796507Smax.romanov@nginx.com         port->app = NULL;
3797507Smax.romanov@nginx.com         app->processes--;
3798343Smax.romanov@nginx.com 
3799343Smax.romanov@nginx.com         break;
3800343Smax.romanov@nginx.com 
3801343Smax.romanov@nginx.com     } nxt_queue_loop;
3802141Smax.romanov@nginx.com 
3803141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3804141Smax.romanov@nginx.com 
3805141Smax.romanov@nginx.com     return port;
3806141Smax.romanov@nginx.com }
3807141Smax.romanov@nginx.com 
3808141Smax.romanov@nginx.com 
3809141Smax.romanov@nginx.com static void
3810753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
3811507Smax.romanov@nginx.com {
3812753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
3813507Smax.romanov@nginx.com 
3814507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
3815507Smax.romanov@nginx.com 
3816753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
3817507Smax.romanov@nginx.com }
3818507Smax.romanov@nginx.com 
3819507Smax.romanov@nginx.com 
3820507Smax.romanov@nginx.com static void
3821343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
3822141Smax.romanov@nginx.com {
3823343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3824343Smax.romanov@nginx.com 
3825538Svbart@nginx.com     ra = data;
3826538Svbart@nginx.com 
3827538Svbart@nginx.com #if (NXT_DEBUG)
3828538Svbart@nginx.com     {
3829538Svbart@nginx.com     nxt_app_t  *app;
3830538Svbart@nginx.com 
3831343Smax.romanov@nginx.com     app = obj;
3832141Smax.romanov@nginx.com 
3833141Smax.romanov@nginx.com     nxt_assert(app != NULL);
3834343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
3835343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3836343Smax.romanov@nginx.com 
3837343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
3838343Smax.romanov@nginx.com               &app->name, app, ra->stream);
3839538Svbart@nginx.com     }
3840538Svbart@nginx.com #endif
3841343Smax.romanov@nginx.com 
3842425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
3843343Smax.romanov@nginx.com }
3844343Smax.romanov@nginx.com 
3845343Smax.romanov@nginx.com 
3846343Smax.romanov@nginx.com static void
3847343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
3848343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
3849343Smax.romanov@nginx.com {
3850427Smax.romanov@nginx.com     nxt_app_t                *app;
3851507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
3852507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
3853427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
3854427Smax.romanov@nginx.com     nxt_req_app_link_t       *ra, *pending_ra, *re_ra;
3855427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
3856343Smax.romanov@nginx.com 
3857343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3858343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
3859343Smax.romanov@nginx.com 
3860427Smax.romanov@nginx.com     ra = NULL;
3861427Smax.romanov@nginx.com 
3862343Smax.romanov@nginx.com     app = port->app;
3863343Smax.romanov@nginx.com 
3864343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3865343Smax.romanov@nginx.com 
3866424Smax.romanov@nginx.com     port->app_pending_responses -= request_failed + got_response;
3867343Smax.romanov@nginx.com     port->app_responses += got_response;
3868343Smax.romanov@nginx.com 
3869427Smax.romanov@nginx.com     if (port->pair[1] != -1
3870426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
3871428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3872428Smax.romanov@nginx.com         && (app->max_requests == 0
3873428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3874428Smax.romanov@nginx.com                 < app->max_requests))
3875343Smax.romanov@nginx.com     {
3876424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
3877424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
3878424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
3879424Smax.romanov@nginx.com 
3880424Smax.romanov@nginx.com             } else {
3881424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3882424Smax.romanov@nginx.com             }
3883424Smax.romanov@nginx.com 
3884425Smax.romanov@nginx.com             nxt_port_inc_use(port);
3885424Smax.romanov@nginx.com 
3886424Smax.romanov@nginx.com         } else {
3887424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
3888424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
3889424Smax.romanov@nginx.com             {
3890424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
3891424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3892424Smax.romanov@nginx.com             }
3893424Smax.romanov@nginx.com         }
3894141Smax.romanov@nginx.com     }
3895141Smax.romanov@nginx.com 
3896427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
3897426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
3898343Smax.romanov@nginx.com     {
3899141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
3900141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3901343Smax.romanov@nginx.com         lnk->next = NULL;
3902141Smax.romanov@nginx.com 
3903425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3904425Smax.romanov@nginx.com 
3905427Smax.romanov@nginx.com         ra->app_port = nxt_router_pop_first_port(app);
3906425Smax.romanov@nginx.com 
3907425Smax.romanov@nginx.com         if (ra->app_port->app_pending_responses > 1) {
3908427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
3909425Smax.romanov@nginx.com         }
3910425Smax.romanov@nginx.com     }
3911425Smax.romanov@nginx.com 
3912427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
3913425Smax.romanov@nginx.com     if ((request_failed > 0 || got_response > 0)
3914425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
3915425Smax.romanov@nginx.com     {
3916425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
3917425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3918425Smax.romanov@nginx.com         lnk->next = NULL;
3919425Smax.romanov@nginx.com 
3920427Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
3921427Smax.romanov@nginx.com                                          link_port_pending);
3922427Smax.romanov@nginx.com 
3923427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
3924427Smax.romanov@nginx.com 
3925427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
3926427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
3927425Smax.romanov@nginx.com 
3928425Smax.romanov@nginx.com     } else {
3929427Smax.romanov@nginx.com         pending_ra = NULL;
3930141Smax.romanov@nginx.com     }
3931141Smax.romanov@nginx.com 
3932427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
3933427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
3934427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
3935427Smax.romanov@nginx.com 
3936427Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending);
3937427Smax.romanov@nginx.com 
3938427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
3939427Smax.romanov@nginx.com 
3940427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
3941427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
3942427Smax.romanov@nginx.com 
3943427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
3944427Smax.romanov@nginx.com                                               re_ra->stream);
3945427Smax.romanov@nginx.com 
3946427Smax.romanov@nginx.com             if (cancelled) {
3947427Smax.romanov@nginx.com                 nxt_router_ra_inc_use(re_ra);
3948427Smax.romanov@nginx.com 
3949427Smax.romanov@nginx.com                 state.ra = re_ra;
3950427Smax.romanov@nginx.com                 state.app = app;
3951427Smax.romanov@nginx.com 
3952427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
3953427Smax.romanov@nginx.com 
3954427Smax.romanov@nginx.com                 goto re_ra_cancelled;
3955427Smax.romanov@nginx.com             }
3956427Smax.romanov@nginx.com         }
3957427Smax.romanov@nginx.com     }
3958427Smax.romanov@nginx.com 
3959427Smax.romanov@nginx.com     re_ra = NULL;
3960427Smax.romanov@nginx.com 
3961427Smax.romanov@nginx.com re_ra_cancelled:
3962427Smax.romanov@nginx.com 
3963753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
3964753Smax.romanov@nginx.com                  && port->app_pending_responses == 0
3965753Smax.romanov@nginx.com                  && port->app_responses >= app->max_requests);
3966367Smax.romanov@nginx.com 
3967507Smax.romanov@nginx.com     if (send_quit) {
3968507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
3969507Smax.romanov@nginx.com 
3970507Smax.romanov@nginx.com         port->app = NULL;
3971507Smax.romanov@nginx.com         app->processes--;
3972507Smax.romanov@nginx.com 
3973507Smax.romanov@nginx.com     } else {
3974507Smax.romanov@nginx.com         port_unchained = 0;
3975507Smax.romanov@nginx.com     }
3976507Smax.romanov@nginx.com 
3977507Smax.romanov@nginx.com     adjust_idle_timer = 0;
3978507Smax.romanov@nginx.com 
3979571Smax.romanov@nginx.com     if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) {
3980507Smax.romanov@nginx.com         nxt_assert(port->idle_link.next == NULL);
3981507Smax.romanov@nginx.com 
3982507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
3983507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
3984507Smax.romanov@nginx.com         {
3985507Smax.romanov@nginx.com             adjust_idle_timer = 1;
3986507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
3987507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
3988507Smax.romanov@nginx.com         }
3989507Smax.romanov@nginx.com 
3990507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
3991507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
3992507Smax.romanov@nginx.com 
3993507Smax.romanov@nginx.com         } else {
3994507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
3995507Smax.romanov@nginx.com 
3996507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
3997507Smax.romanov@nginx.com         }
3998507Smax.romanov@nginx.com 
3999507Smax.romanov@nginx.com         app->idle_processes++;
4000507Smax.romanov@nginx.com     }
4001507Smax.romanov@nginx.com 
4002343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4003343Smax.romanov@nginx.com 
4004507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4005507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4006507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4007507Smax.romanov@nginx.com     }
4008507Smax.romanov@nginx.com 
4009427Smax.romanov@nginx.com     if (pending_ra != NULL) {
4010427Smax.romanov@nginx.com         nxt_router_ra_use(task, pending_ra, -1);
4011427Smax.romanov@nginx.com     }
4012427Smax.romanov@nginx.com 
4013427Smax.romanov@nginx.com     if (re_ra != NULL) {
4014427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
4015427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4016427Smax.romanov@nginx.com                                nxt_router_app_process_request,
4017427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
4018427Smax.romanov@nginx.com         }
4019425Smax.romanov@nginx.com     }
4020425Smax.romanov@nginx.com 
4021343Smax.romanov@nginx.com     if (ra != NULL) {
4022425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
4023425Smax.romanov@nginx.com 
4024343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4025343Smax.romanov@nginx.com                            nxt_router_app_process_request,
4026343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
4027343Smax.romanov@nginx.com 
4028343Smax.romanov@nginx.com         goto adjust_use;
4029343Smax.romanov@nginx.com     }
4030343Smax.romanov@nginx.com 
4031343Smax.romanov@nginx.com     /* ? */
4032163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
4033343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4034343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
4035343Smax.romanov@nginx.com 
4036343Smax.romanov@nginx.com         goto adjust_use;
4037163Smax.romanov@nginx.com     }
4038163Smax.romanov@nginx.com 
4039367Smax.romanov@nginx.com     if (send_quit) {
4040507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
4041167Smax.romanov@nginx.com                   &app->name, app);
4042163Smax.romanov@nginx.com 
4043163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
4044163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
4045163Smax.romanov@nginx.com 
4046507Smax.romanov@nginx.com         if (port_unchained) {
4047507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
4048507Smax.romanov@nginx.com         }
4049507Smax.romanov@nginx.com 
4050343Smax.romanov@nginx.com         goto adjust_use;
4051163Smax.romanov@nginx.com     }
4052163Smax.romanov@nginx.com 
4053167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4054167Smax.romanov@nginx.com               &app->name, app);
4055141Smax.romanov@nginx.com 
4056343Smax.romanov@nginx.com adjust_use:
4057343Smax.romanov@nginx.com 
4058425Smax.romanov@nginx.com     if (request_failed > 0 || got_response > 0) {
4059425Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4060343Smax.romanov@nginx.com     }
4061141Smax.romanov@nginx.com }
4062141Smax.romanov@nginx.com 
4063141Smax.romanov@nginx.com 
4064343Smax.romanov@nginx.com void
4065343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4066141Smax.romanov@nginx.com {
4067507Smax.romanov@nginx.com     nxt_app_t         *app;
4068507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4069507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4070507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4071141Smax.romanov@nginx.com 
4072141Smax.romanov@nginx.com     app = port->app;
4073343Smax.romanov@nginx.com 
4074343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4075141Smax.romanov@nginx.com 
4076141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4077141Smax.romanov@nginx.com 
4078507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4079507Smax.romanov@nginx.com 
4080507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4081507Smax.romanov@nginx.com         app->idle_processes--;
4082507Smax.romanov@nginx.com 
4083507Smax.romanov@nginx.com         if (port->idle_start == 0
4084507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4085507Smax.romanov@nginx.com         {
4086507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4087507Smax.romanov@nginx.com 
4088507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4089507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4090507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4091507Smax.romanov@nginx.com 
4092507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4093507Smax.romanov@nginx.com 
4094507Smax.romanov@nginx.com             idle_port->idle_start = 0;
4095507Smax.romanov@nginx.com         }
4096343Smax.romanov@nginx.com     }
4097343Smax.romanov@nginx.com 
4098507Smax.romanov@nginx.com     app->processes--;
4099507Smax.romanov@nginx.com 
4100753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4101507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
4102507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
4103507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
4104507Smax.romanov@nginx.com 
4105507Smax.romanov@nginx.com     if (start_process) {
4106507Smax.romanov@nginx.com         app->pending_processes++;
4107163Smax.romanov@nginx.com     }
4108141Smax.romanov@nginx.com 
4109141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4110163Smax.romanov@nginx.com 
4111507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4112343Smax.romanov@nginx.com 
4113343Smax.romanov@nginx.com     if (unchain) {
4114343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4115163Smax.romanov@nginx.com     }
4116163Smax.romanov@nginx.com 
4117507Smax.romanov@nginx.com     if (start_process) {
4118507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4119507Smax.romanov@nginx.com     }
4120507Smax.romanov@nginx.com }
4121507Smax.romanov@nginx.com 
4122507Smax.romanov@nginx.com 
4123507Smax.romanov@nginx.com static void
4124507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4125507Smax.romanov@nginx.com {
4126507Smax.romanov@nginx.com     nxt_app_t           *app;
4127507Smax.romanov@nginx.com     nxt_bool_t          queued;
4128507Smax.romanov@nginx.com     nxt_port_t          *port;
4129507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4130507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4131507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4132507Smax.romanov@nginx.com 
4133507Smax.romanov@nginx.com     app = obj;
4134507Smax.romanov@nginx.com     queued = (data == app);
4135507Smax.romanov@nginx.com 
4136507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4137507Smax.romanov@nginx.com               &app->name, queued);
4138507Smax.romanov@nginx.com 
4139507Smax.romanov@nginx.com     engine = task->thread->engine;
4140507Smax.romanov@nginx.com 
4141507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
4142507Smax.romanov@nginx.com 
4143811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
4144507Smax.romanov@nginx.com     timeout = 0;
4145507Smax.romanov@nginx.com 
4146507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4147507Smax.romanov@nginx.com 
4148507Smax.romanov@nginx.com     if (queued) {
4149507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
4150343Smax.romanov@nginx.com     }
4151507Smax.romanov@nginx.com 
4152507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
4153507Smax.romanov@nginx.com 
4154551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4155507Smax.romanov@nginx.com 
4156507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
4157507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4158507Smax.romanov@nginx.com 
4159507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
4160507Smax.romanov@nginx.com 
4161507Smax.romanov@nginx.com         if (timeout > threshold) {
4162507Smax.romanov@nginx.com             break;
4163507Smax.romanov@nginx.com         }
4164507Smax.romanov@nginx.com 
4165507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4166507Smax.romanov@nginx.com         lnk->next = NULL;
4167507Smax.romanov@nginx.com 
4168507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4169507Smax.romanov@nginx.com 
4170507Smax.romanov@nginx.com         app->idle_processes--;
4171507Smax.romanov@nginx.com         app->processes--;
4172507Smax.romanov@nginx.com         port->app = NULL;
4173507Smax.romanov@nginx.com 
4174507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4175507Smax.romanov@nginx.com 
4176507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4177507Smax.romanov@nginx.com                   &app->name, port->pid);
4178507Smax.romanov@nginx.com 
4179507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4180507Smax.romanov@nginx.com 
4181507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4182507Smax.romanov@nginx.com 
4183507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4184507Smax.romanov@nginx.com     }
4185507Smax.romanov@nginx.com 
4186507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4187507Smax.romanov@nginx.com 
4188507Smax.romanov@nginx.com     if (timeout > threshold) {
4189753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4190507Smax.romanov@nginx.com 
4191507Smax.romanov@nginx.com     } else {
4192753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4193507Smax.romanov@nginx.com     }
4194507Smax.romanov@nginx.com 
4195507Smax.romanov@nginx.com     if (queued) {
4196507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4197507Smax.romanov@nginx.com     }
4198507Smax.romanov@nginx.com }
4199507Smax.romanov@nginx.com 
4200507Smax.romanov@nginx.com 
4201507Smax.romanov@nginx.com static void
4202507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4203507Smax.romanov@nginx.com {
4204753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4205753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4206507Smax.romanov@nginx.com 
4207507Smax.romanov@nginx.com     timer = obj;
4208753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4209753Smax.romanov@nginx.com 
4210753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4211753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4212753Smax.romanov@nginx.com     }
4213753Smax.romanov@nginx.com }
4214753Smax.romanov@nginx.com 
4215753Smax.romanov@nginx.com 
4216753Smax.romanov@nginx.com static void
4217753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4218753Smax.romanov@nginx.com {
4219753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4220753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4221753Smax.romanov@nginx.com 
4222753Smax.romanov@nginx.com     timer = obj;
4223753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4224753Smax.romanov@nginx.com 
4225753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4226507Smax.romanov@nginx.com }
4227507Smax.romanov@nginx.com 
4228507Smax.romanov@nginx.com 
4229507Smax.romanov@nginx.com static void
4230753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4231507Smax.romanov@nginx.com {
4232753Smax.romanov@nginx.com     nxt_app_t        *app;
4233753Smax.romanov@nginx.com     nxt_port_t       *port;
4234753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4235753Smax.romanov@nginx.com 
4236753Smax.romanov@nginx.com     app_joint = obj;
4237753Smax.romanov@nginx.com     app = app_joint->app;
4238753Smax.romanov@nginx.com 
4239753Smax.romanov@nginx.com     for ( ;; ) {
4240753Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
4241753Smax.romanov@nginx.com         if (port == NULL) {
4242753Smax.romanov@nginx.com             break;
4243753Smax.romanov@nginx.com         }
4244753Smax.romanov@nginx.com 
4245753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4246753Smax.romanov@nginx.com 
4247753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4248753Smax.romanov@nginx.com 
4249753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4250753Smax.romanov@nginx.com     }
4251753Smax.romanov@nginx.com 
4252753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
4253753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4254753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->requests));
4255753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4256753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4257753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4258753Smax.romanov@nginx.com 
4259753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
4260753Smax.romanov@nginx.com     nxt_free(app);
4261753Smax.romanov@nginx.com 
4262753Smax.romanov@nginx.com     app_joint->app = NULL;
4263753Smax.romanov@nginx.com 
4264753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4265753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4266753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4267753Smax.romanov@nginx.com 
4268753Smax.romanov@nginx.com     } else {
4269753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4270753Smax.romanov@nginx.com     }
4271141Smax.romanov@nginx.com }
4272141Smax.romanov@nginx.com 
4273141Smax.romanov@nginx.com 
4274427Smax.romanov@nginx.com static void
4275427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
4276141Smax.romanov@nginx.com {
4277427Smax.romanov@nginx.com     nxt_app_t           *app;
4278507Smax.romanov@nginx.com     nxt_bool_t          can_start_process;
4279427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4280427Smax.romanov@nginx.com 
4281427Smax.romanov@nginx.com     ra = state->ra;
4282427Smax.romanov@nginx.com     app = state->app;
4283427Smax.romanov@nginx.com 
4284427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
4285343Smax.romanov@nginx.com 
4286425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_app_requests))
4287425Smax.romanov@nginx.com     {
4288425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4289425Smax.romanov@nginx.com     }
4290425Smax.romanov@nginx.com 
4291425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_port_pending))
4292425Smax.romanov@nginx.com     {
4293427Smax.romanov@nginx.com         nxt_assert(ra->link_app_pending.next != NULL);
4294427Smax.romanov@nginx.com 
4295427Smax.romanov@nginx.com         nxt_queue_remove(&ra->link_app_pending);
4296427Smax.romanov@nginx.com         ra->link_app_pending.next = NULL;
4297427Smax.romanov@nginx.com 
4298425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4299425Smax.romanov@nginx.com     }
4300425Smax.romanov@nginx.com 
4301427Smax.romanov@nginx.com     state->failed_port = ra->app_port;
4302427Smax.romanov@nginx.com 
4303425Smax.romanov@nginx.com     if (ra->app_port != NULL) {
4304427Smax.romanov@nginx.com         state->failed_port_use_delta--;
4305427Smax.romanov@nginx.com 
4306427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
4307427Smax.romanov@nginx.com 
4308427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
4309427Smax.romanov@nginx.com             state->failed_port_use_delta--;
4310427Smax.romanov@nginx.com         }
4311427Smax.romanov@nginx.com 
4312427Smax.romanov@nginx.com         ra->app_port = NULL;
4313427Smax.romanov@nginx.com     }
4314427Smax.romanov@nginx.com 
4315507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
4316507Smax.romanov@nginx.com 
4317427Smax.romanov@nginx.com     state->port = NULL;
4318507Smax.romanov@nginx.com     state->start_process = 0;
4319427Smax.romanov@nginx.com 
4320427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
4321507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
4322427Smax.romanov@nginx.com     {
4323427Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
4324427Smax.romanov@nginx.com 
4325427Smax.romanov@nginx.com         if (nxt_slow_path(ra == NULL)) {
4326427Smax.romanov@nginx.com             goto fail;
4327427Smax.romanov@nginx.com         }
4328427Smax.romanov@nginx.com 
4329427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
4330427Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests, &ra->link_app_requests);
4331427Smax.romanov@nginx.com 
4332427Smax.romanov@nginx.com         } else {
4333427Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link_app_requests);
4334427Smax.romanov@nginx.com         }
4335427Smax.romanov@nginx.com 
4336427Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
4337427Smax.romanov@nginx.com 
4338427Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream);
4339427Smax.romanov@nginx.com 
4340507Smax.romanov@nginx.com         if (can_start_process) {
4341507Smax.romanov@nginx.com             app->pending_processes++;
4342507Smax.romanov@nginx.com             state->start_process = 1;
4343425Smax.romanov@nginx.com         }
4344425Smax.romanov@nginx.com 
4345425Smax.romanov@nginx.com     } else {
4346427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
4347427Smax.romanov@nginx.com 
4348427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
4349427Smax.romanov@nginx.com             ra = nxt_router_ra_create(task, ra);
4350427Smax.romanov@nginx.com 
4351427Smax.romanov@nginx.com             if (nxt_slow_path(ra == NULL)) {
4352427Smax.romanov@nginx.com                 goto fail;
4353351Smax.romanov@nginx.com             }
4354427Smax.romanov@nginx.com 
4355427Smax.romanov@nginx.com             ra->app_port = state->port;
4356427Smax.romanov@nginx.com 
4357427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
4358425Smax.romanov@nginx.com         }
4359507Smax.romanov@nginx.com 
4360507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
4361507Smax.romanov@nginx.com             app->pending_processes++;
4362507Smax.romanov@nginx.com             state->start_process = 1;
4363507Smax.romanov@nginx.com         }
4364343Smax.romanov@nginx.com     }
4365343Smax.romanov@nginx.com 
4366427Smax.romanov@nginx.com fail:
4367427Smax.romanov@nginx.com 
4368427Smax.romanov@nginx.com     state->shared_ra = ra;
4369427Smax.romanov@nginx.com }
4370427Smax.romanov@nginx.com 
4371427Smax.romanov@nginx.com 
4372427Smax.romanov@nginx.com static nxt_int_t
4373427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
4374427Smax.romanov@nginx.com {
4375427Smax.romanov@nginx.com     nxt_int_t           res;
4376427Smax.romanov@nginx.com     nxt_app_t           *app;
4377427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4378427Smax.romanov@nginx.com 
4379427Smax.romanov@nginx.com     ra = state->shared_ra;
4380427Smax.romanov@nginx.com     app = state->app;
4381427Smax.romanov@nginx.com 
4382427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
4383427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
4384425Smax.romanov@nginx.com     }
4385425Smax.romanov@nginx.com 
4386351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
4387427Smax.romanov@nginx.com         if (state->port != NULL) {
4388427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
4389425Smax.romanov@nginx.com         }
4390425Smax.romanov@nginx.com 
4391427Smax.romanov@nginx.com         nxt_router_ra_error(state->ra, 500,
4392427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
4393427Smax.romanov@nginx.com         nxt_router_ra_use(task, state->ra, -1);
4394427Smax.romanov@nginx.com 
4395351Smax.romanov@nginx.com         return NXT_ERROR;
4396351Smax.romanov@nginx.com     }
4397351Smax.romanov@nginx.com 
4398427Smax.romanov@nginx.com     if (state->port != NULL) {
4399343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
4400163Smax.romanov@nginx.com 
4401427Smax.romanov@nginx.com         ra->app_port = state->port;
4402343Smax.romanov@nginx.com 
4403507Smax.romanov@nginx.com         if (state->start_process) {
4404507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
4405507Smax.romanov@nginx.com         }
4406507Smax.romanov@nginx.com 
4407141Smax.romanov@nginx.com         return NXT_OK;
4408141Smax.romanov@nginx.com     }
4409141Smax.romanov@nginx.com 
4410507Smax.romanov@nginx.com     if (!state->start_process) {
4411507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
4412343Smax.romanov@nginx.com                   &app->name, app);
4413343Smax.romanov@nginx.com 
4414343Smax.romanov@nginx.com         return NXT_AGAIN;
4415343Smax.romanov@nginx.com     }
4416343Smax.romanov@nginx.com 
4417507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
4418343Smax.romanov@nginx.com 
4419343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4420507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start app process");
4421427Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
4422343Smax.romanov@nginx.com 
4423141Smax.romanov@nginx.com         return NXT_ERROR;
4424141Smax.romanov@nginx.com     }
4425141Smax.romanov@nginx.com 
4426141Smax.romanov@nginx.com     return NXT_AGAIN;
442788Smax.romanov@nginx.com }
442888Smax.romanov@nginx.com 
442988Smax.romanov@nginx.com 
4430427Smax.romanov@nginx.com static nxt_int_t
4431427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
4432427Smax.romanov@nginx.com {
4433427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4434427Smax.romanov@nginx.com 
4435427Smax.romanov@nginx.com     state.ra = ra;
4436427Smax.romanov@nginx.com     state.app = app;
4437427Smax.romanov@nginx.com 
4438427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4439427Smax.romanov@nginx.com 
4440427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
4441427Smax.romanov@nginx.com 
4442427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4443427Smax.romanov@nginx.com 
4444427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
4445427Smax.romanov@nginx.com }
4446427Smax.romanov@nginx.com 
4447427Smax.romanov@nginx.com 
4448431Sigor@sysoev.ru void
4449*1007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
4450964Sigor@sysoev.ru     nxt_app_t *app)
445153Sigor@sysoev.ru {
4452431Sigor@sysoev.ru     nxt_int_t            res;
4453431Sigor@sysoev.ru     nxt_port_t           *port;
4454431Sigor@sysoev.ru     nxt_event_engine_t   *engine;
4455431Sigor@sysoev.ru     nxt_req_app_link_t   ra_local, *ra;
4456431Sigor@sysoev.ru     nxt_req_conn_link_t  *rc;
4457431Sigor@sysoev.ru 
445888Smax.romanov@nginx.com     engine = task->thread->engine;
445988Smax.romanov@nginx.com 
4460318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
4461318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4462318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
4463318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
4464122Smax.romanov@nginx.com 
446588Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
4466431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4467141Smax.romanov@nginx.com         return;
446888Smax.romanov@nginx.com     }
446988Smax.romanov@nginx.com 
4470318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
4471425Smax.romanov@nginx.com     rc->app = app;
4472425Smax.romanov@nginx.com 
4473425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4474425Smax.romanov@nginx.com 
4475*1007Salexander.borisov@nginx.com     rc->request = r;
4476346Smax.romanov@nginx.com 
4477351Smax.romanov@nginx.com     ra = &ra_local;
4478351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
4479167Smax.romanov@nginx.com 
4480427Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, ra);
4481141Smax.romanov@nginx.com 
4482141Smax.romanov@nginx.com     if (res != NXT_OK) {
4483141Smax.romanov@nginx.com         return;
4484141Smax.romanov@nginx.com     }
4485141Smax.romanov@nginx.com 
4486425Smax.romanov@nginx.com     ra = rc->ra;
4487167Smax.romanov@nginx.com     port = ra->app_port;
4488141Smax.romanov@nginx.com 
4489425Smax.romanov@nginx.com     nxt_assert(port != NULL);
4490141Smax.romanov@nginx.com 
4491318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
4492318Smax.romanov@nginx.com 
4493425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
4494167Smax.romanov@nginx.com }
4495167Smax.romanov@nginx.com 
4496167Smax.romanov@nginx.com 
4497167Smax.romanov@nginx.com static void
4498423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4499423Smax.romanov@nginx.com {
4500423Smax.romanov@nginx.com }
4501423Smax.romanov@nginx.com 
4502423Smax.romanov@nginx.com 
4503423Smax.romanov@nginx.com static void
4504425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
4505167Smax.romanov@nginx.com {
4506*1007Salexander.borisov@nginx.com     uint32_t    request_failed;
4507*1007Salexander.borisov@nginx.com     nxt_buf_t   *buf;
4508*1007Salexander.borisov@nginx.com     nxt_int_t   res;
4509*1007Salexander.borisov@nginx.com     nxt_port_t  *port, *c_port, *reply_port;
4510167Smax.romanov@nginx.com 
4511343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
4512343Smax.romanov@nginx.com 
4513343Smax.romanov@nginx.com     port = ra->app_port;
4514167Smax.romanov@nginx.com     reply_port = ra->reply_port;
4515141Smax.romanov@nginx.com 
4516343Smax.romanov@nginx.com     request_failed = 1;
4517343Smax.romanov@nginx.com 
4518141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
4519141Smax.romanov@nginx.com                                              reply_port->id);
4520141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
4521141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
4522122Smax.romanov@nginx.com 
4523122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
4524423Smax.romanov@nginx.com             nxt_router_ra_error(ra, 500,
4525345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
4526343Smax.romanov@nginx.com             goto release_port;
4527122Smax.romanov@nginx.com         }
4528122Smax.romanov@nginx.com 
4529141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
453088Smax.romanov@nginx.com     }
453188Smax.romanov@nginx.com 
4532*1007Salexander.borisov@nginx.com     buf = nxt_router_prepare_msg(task, ra->request, port,
4533743Smax.romanov@nginx.com                                  nxt_app_msg_prefix[port->app->type]);
4534743Smax.romanov@nginx.com 
4535743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
4536423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4537345Smax.romanov@nginx.com                             "Failed to prepare message for application");
4538343Smax.romanov@nginx.com         goto release_port;
4539122Smax.romanov@nginx.com     }
454088Smax.romanov@nginx.com 
4541507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4542743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4543743Smax.romanov@nginx.com                     port->socket.fd);
454488Smax.romanov@nginx.com 
4545343Smax.romanov@nginx.com     request_failed = 0;
4546343Smax.romanov@nginx.com 
4547743Smax.romanov@nginx.com     ra->msg_info.buf = buf;
4548743Smax.romanov@nginx.com     ra->msg_info.completion_handler = buf->completion_handler;
4549743Smax.romanov@nginx.com 
4550743Smax.romanov@nginx.com     for (; buf; buf = buf->next) {
4551743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
4552423Smax.romanov@nginx.com     }
4553423Smax.romanov@nginx.com 
4554743Smax.romanov@nginx.com     buf = ra->msg_info.buf;
4555743Smax.romanov@nginx.com 
4556423Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking,
4557423Smax.romanov@nginx.com                                      ra->stream);
4558423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4559423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4560423Smax.romanov@nginx.com                             "Failed to get tracking area");
4561423Smax.romanov@nginx.com         goto release_port;
4562423Smax.romanov@nginx.com     }
4563423Smax.romanov@nginx.com 
4564743Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA,
4565743Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, buf,
4566423Smax.romanov@nginx.com                                  &ra->msg_info.tracking);
4567122Smax.romanov@nginx.com 
4568122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4569423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4570345Smax.romanov@nginx.com                             "Failed to send message to application");
4571343Smax.romanov@nginx.com         goto release_port;
4572122Smax.romanov@nginx.com     }
4573343Smax.romanov@nginx.com 
4574343Smax.romanov@nginx.com release_port:
4575343Smax.romanov@nginx.com 
4576345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
4577345Smax.romanov@nginx.com 
4578425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
457953Sigor@sysoev.ru }
458053Sigor@sysoev.ru 
458153Sigor@sysoev.ru 
4582743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4583743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4584743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4585743Smax.romanov@nginx.com };
4586743Smax.romanov@nginx.com 
4587743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4588743Smax.romanov@nginx.com 
4589743Smax.romanov@nginx.com 
4590743Smax.romanov@nginx.com static nxt_http_field_t *
4591743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4592216Sigor@sysoev.ru {
4593743Smax.romanov@nginx.com     if (part == NULL) {
4594743Smax.romanov@nginx.com         return NULL;
4595216Sigor@sysoev.ru     }
4596216Sigor@sysoev.ru 
4597743Smax.romanov@nginx.com     while (part->nelts == 0) {
4598743Smax.romanov@nginx.com         part = part->next;
4599743Smax.romanov@nginx.com         if (part == NULL) {
4600743Smax.romanov@nginx.com             return NULL;
4601743Smax.romanov@nginx.com         }
4602216Sigor@sysoev.ru     }
4603216Sigor@sysoev.ru 
4604743Smax.romanov@nginx.com     i->part = part;
4605743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4606743Smax.romanov@nginx.com 
4607743Smax.romanov@nginx.com     return i->field;
4608743Smax.romanov@nginx.com }
4609743Smax.romanov@nginx.com 
4610743Smax.romanov@nginx.com 
4611743Smax.romanov@nginx.com static nxt_http_field_t *
4612743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4613743Smax.romanov@nginx.com {
4614743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4615743Smax.romanov@nginx.com }
4616743Smax.romanov@nginx.com 
4617743Smax.romanov@nginx.com 
4618743Smax.romanov@nginx.com static nxt_http_field_t *
4619743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4620743Smax.romanov@nginx.com {
4621743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4622743Smax.romanov@nginx.com 
4623743Smax.romanov@nginx.com     end += i->part->nelts;
4624743Smax.romanov@nginx.com     i->field++;
4625743Smax.romanov@nginx.com 
4626743Smax.romanov@nginx.com     if (i->field < end) {
4627743Smax.romanov@nginx.com         return i->field;
4628216Sigor@sysoev.ru     }
4629216Sigor@sysoev.ru 
4630743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4631216Sigor@sysoev.ru }
4632216Sigor@sysoev.ru 
4633216Sigor@sysoev.ru 
4634743Smax.romanov@nginx.com static nxt_buf_t *
4635*1007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
4636743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix)
4637216Sigor@sysoev.ru {
4638*1007Salexander.borisov@nginx.com     void                *target_pos, *query_pos;
4639*1007Salexander.borisov@nginx.com     u_char              *pos, *end, *p, c;
4640*1007Salexander.borisov@nginx.com     size_t              fields_count, req_size, size, free_size;
4641*1007Salexander.borisov@nginx.com     size_t              copy_size;
4642*1007Salexander.borisov@nginx.com     nxt_off_t           content_length;
4643*1007Salexander.borisov@nginx.com     nxt_buf_t           *b, *buf, *out, **tail;
4644*1007Salexander.borisov@nginx.com     nxt_http_field_t    *field, *dup;
4645*1007Salexander.borisov@nginx.com     nxt_unit_field_t    *dst_field;
4646*1007Salexander.borisov@nginx.com     nxt_fields_iter_t   iter, dup_iter;
4647*1007Salexander.borisov@nginx.com     nxt_unit_request_t  *req;
4648216Sigor@sysoev.ru 
4649743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
4650*1007Salexander.borisov@nginx.com                + r->method->length + 1
4651*1007Salexander.borisov@nginx.com                + r->version.length + 1
4652*1007Salexander.borisov@nginx.com                + r->remote->length + 1
4653*1007Salexander.borisov@nginx.com                + r->local->length + 1
4654*1007Salexander.borisov@nginx.com                + r->server_name.length + 1
4655*1007Salexander.borisov@nginx.com                + r->target.length + 1
4656*1007Salexander.borisov@nginx.com                + (r->path->start != r->target.start ? r->path->length + 1 : 0);
4657*1007Salexander.borisov@nginx.com 
4658*1007Salexander.borisov@nginx.com     content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
4659743Smax.romanov@nginx.com     fields_count = 0;
4660743Smax.romanov@nginx.com 
4661*1007Salexander.borisov@nginx.com     nxt_list_each(field, r->fields) {
4662743Smax.romanov@nginx.com         fields_count++;
4663743Smax.romanov@nginx.com 
4664743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4665743Smax.romanov@nginx.com                     + field->value_length + 1;
4666743Smax.romanov@nginx.com     } nxt_list_loop;
4667743Smax.romanov@nginx.com 
4668743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4669743Smax.romanov@nginx.com 
4670743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4671743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4672743Smax.romanov@nginx.com                   (int) req_size);
4673743Smax.romanov@nginx.com 
4674743Smax.romanov@nginx.com         return NULL;
4675743Smax.romanov@nginx.com     }
4676743Smax.romanov@nginx.com 
4677743Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, port,
4678*1007Salexander.borisov@nginx.com               nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
4679743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4680743Smax.romanov@nginx.com         return NULL;
4681743Smax.romanov@nginx.com     }
4682743Smax.romanov@nginx.com 
4683743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4684743Smax.romanov@nginx.com     out->mem.free += req_size;
4685743Smax.romanov@nginx.com 
4686*1007Salexander.borisov@nginx.com     req->content_length = content_length;
4687743Smax.romanov@nginx.com 
4688743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4689743Smax.romanov@nginx.com 
4690743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4691743Smax.romanov@nginx.com 
4692*1007Salexander.borisov@nginx.com     req->method_length = r->method->length;
4693743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
4694*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->method->start, r->method->length);
4695743Smax.romanov@nginx.com     *p++ = '\0';
4696743Smax.romanov@nginx.com 
4697*1007Salexander.borisov@nginx.com     req->version_length = r->version.length;
4698743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
4699*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->version.start, r->version.length);
4700743Smax.romanov@nginx.com     *p++ = '\0';
4701743Smax.romanov@nginx.com 
4702*1007Salexander.borisov@nginx.com     req->remote_length = r->remote->address_length;
4703743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
4704*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
4705*1007Salexander.borisov@nginx.com                    r->remote->address_length);
4706743Smax.romanov@nginx.com     *p++ = '\0';
4707743Smax.romanov@nginx.com 
4708*1007Salexander.borisov@nginx.com     req->local_length = r->local->address_length;
4709743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
4710*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
4711743Smax.romanov@nginx.com     *p++ = '\0';
4712743Smax.romanov@nginx.com 
4713*1007Salexander.borisov@nginx.com     req->server_name_length = r->server_name.length;
4714967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
4715*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
4716967Svbart@nginx.com     *p++ = '\0';
4717967Svbart@nginx.com 
4718743Smax.romanov@nginx.com     target_pos = p;
4719*1007Salexander.borisov@nginx.com     req->target_length = (uint32_t) r->target.length;
4720743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
4721*1007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->target.start, r->target.length);
4722743Smax.romanov@nginx.com     *p++ = '\0';
4723743Smax.romanov@nginx.com 
4724*1007Salexander.borisov@nginx.com     req->path_length = (uint32_t) r->path->length;
4725*1007Salexander.borisov@nginx.com     if (r->path->start == r->target.start) {
4726743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
4727277Sigor@sysoev.ru 
4728216Sigor@sysoev.ru     } else {
4729743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
4730*1007Salexander.borisov@nginx.com         p = nxt_cpymem(p, r->path->start, r->path->length);
4731743Smax.romanov@nginx.com         *p++ = '\0';
4732305Smax.romanov@nginx.com     }
4733216Sigor@sysoev.ru 
4734*1007Salexander.borisov@nginx.com     req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
4735*1007Salexander.borisov@nginx.com     if (r->args != NULL && r->args->start != NULL) {
4736743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
4737*1007Salexander.borisov@nginx.com                                    r->args->start - r->target.start);
4738743Smax.romanov@nginx.com 
4739743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
4740277Sigor@sysoev.ru 
4741216Sigor@sysoev.ru     } else {
4742743Smax.romanov@nginx.com         req->query.offset = 0;
4743216Sigor@sysoev.ru     }
4744216Sigor@sysoev.ru 
4745743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
4746743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
4747743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
4748743Smax.romanov@nginx.com 
4749743Smax.romanov@nginx.com     dst_field = req->fields;
4750743Smax.romanov@nginx.com 
4751*1007Salexander.borisov@nginx.com     for (field = nxt_fields_first(r->fields, &iter);
4752743Smax.romanov@nginx.com          field != NULL;
4753743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
4754743Smax.romanov@nginx.com     {
4755743Smax.romanov@nginx.com         if (field->skip) {
4756743Smax.romanov@nginx.com             continue;
4757743Smax.romanov@nginx.com         }
4758743Smax.romanov@nginx.com 
4759743Smax.romanov@nginx.com         dst_field->hash = field->hash;
4760743Smax.romanov@nginx.com         dst_field->skip = 0;
4761743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
4762743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
4763743Smax.romanov@nginx.com 
4764*1007Salexander.borisov@nginx.com         if (field == r->content_length) {
4765743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
4766743Smax.romanov@nginx.com 
4767*1007Salexander.borisov@nginx.com         } else if (field == r->content_type) {
4768743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
4769743Smax.romanov@nginx.com 
4770*1007Salexander.borisov@nginx.com         } else if (field == r->cookie) {
4771743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
4772743Smax.romanov@nginx.com         }
4773743Smax.romanov@nginx.com 
4774743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
4775743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
4776743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
4777743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
4778743Smax.romanov@nginx.com 
4779743Smax.romanov@nginx.com         if (prefix->length != 0) {
4780743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4781743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
4782743Smax.romanov@nginx.com 
4783743Smax.romanov@nginx.com             end = field->name + field->name_length;
4784743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
4785743Smax.romanov@nginx.com                 c = *pos;
4786743Smax.romanov@nginx.com 
4787743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
4788743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
4789743Smax.romanov@nginx.com                     continue;
4790743Smax.romanov@nginx.com                 }
4791743Smax.romanov@nginx.com 
4792743Smax.romanov@nginx.com                 if (c == '-') {
4793743Smax.romanov@nginx.com                     *p++ = '_';
4794743Smax.romanov@nginx.com                     continue;
4795743Smax.romanov@nginx.com                 }
4796743Smax.romanov@nginx.com 
4797743Smax.romanov@nginx.com                 *p++ = c;
4798743Smax.romanov@nginx.com             }
4799743Smax.romanov@nginx.com 
4800743Smax.romanov@nginx.com         } else {
4801743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4802743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
4803743Smax.romanov@nginx.com         }
4804743Smax.romanov@nginx.com 
4805743Smax.romanov@nginx.com         *p++ = '\0';
4806743Smax.romanov@nginx.com 
4807743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
4808743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
4809743Smax.romanov@nginx.com 
4810743Smax.romanov@nginx.com         if (prefix->length != 0) {
4811743Smax.romanov@nginx.com             dup_iter = iter;
4812743Smax.romanov@nginx.com 
4813743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
4814743Smax.romanov@nginx.com                  dup != NULL;
4815743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
4816743Smax.romanov@nginx.com             {
4817743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
4818743Smax.romanov@nginx.com                     || dup->skip
4819743Smax.romanov@nginx.com                     || dup->hash != field->hash
4820743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
4821743Smax.romanov@nginx.com                 {
4822743Smax.romanov@nginx.com                     continue;
4823743Smax.romanov@nginx.com                 }
4824743Smax.romanov@nginx.com 
4825743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
4826743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
4827743Smax.romanov@nginx.com 
4828743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
4829743Smax.romanov@nginx.com 
4830743Smax.romanov@nginx.com                 dup->skip = 1;
4831743Smax.romanov@nginx.com             }
4832743Smax.romanov@nginx.com         }
4833743Smax.romanov@nginx.com 
4834743Smax.romanov@nginx.com         *p++ = '\0';
4835743Smax.romanov@nginx.com 
4836743Smax.romanov@nginx.com         dst_field++;
4837743Smax.romanov@nginx.com     }
4838743Smax.romanov@nginx.com 
4839*1007Salexander.borisov@nginx.com     req->fields_count = (uint32_t) (dst_field - req->fields);
4840743Smax.romanov@nginx.com 
4841743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
4842743Smax.romanov@nginx.com 
4843743Smax.romanov@nginx.com     buf = out;
4844743Smax.romanov@nginx.com     tail = &buf->next;
4845216Sigor@sysoev.ru 
4846*1007Salexander.borisov@nginx.com     for (b = r->body; b != NULL; b = b->next) {
4847743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
4848743Smax.romanov@nginx.com         pos = b->mem.pos;
4849743Smax.romanov@nginx.com 
4850743Smax.romanov@nginx.com         while (size > 0) {
4851743Smax.romanov@nginx.com             if (buf == NULL) {
4852743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
4853743Smax.romanov@nginx.com 
4854743Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, port, free_size);
4855743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
4856743Smax.romanov@nginx.com                     while (out != NULL) {
4857743Smax.romanov@nginx.com                         buf = out->next;
4858743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
4859743Smax.romanov@nginx.com                         out = buf;
4860743Smax.romanov@nginx.com                     }
4861743Smax.romanov@nginx.com                     return NULL;
4862743Smax.romanov@nginx.com                 }
4863743Smax.romanov@nginx.com 
4864743Smax.romanov@nginx.com                 *tail = buf;
4865743Smax.romanov@nginx.com                 tail = &buf->next;
4866743Smax.romanov@nginx.com 
4867743Smax.romanov@nginx.com             } else {
4868743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
4869743Smax.romanov@nginx.com                 if (free_size < size
4870743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
4871743Smax.romanov@nginx.com                        == NXT_OK)
4872743Smax.romanov@nginx.com                 {
4873743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
4874743Smax.romanov@nginx.com                 }
4875743Smax.romanov@nginx.com             }
4876743Smax.romanov@nginx.com 
4877743Smax.romanov@nginx.com             if (free_size > 0) {
4878743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
4879743Smax.romanov@nginx.com 
4880743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
4881743Smax.romanov@nginx.com 
4882743Smax.romanov@nginx.com                 size -= copy_size;
4883743Smax.romanov@nginx.com                 pos += copy_size;
4884743Smax.romanov@nginx.com 
4885743Smax.romanov@nginx.com                 if (size == 0) {
4886743Smax.romanov@nginx.com                     break;
4887743Smax.romanov@nginx.com                 }
4888743Smax.romanov@nginx.com             }
4889743Smax.romanov@nginx.com 
4890743Smax.romanov@nginx.com             buf = NULL;
4891743Smax.romanov@nginx.com         }
4892216Sigor@sysoev.ru     }
4893216Sigor@sysoev.ru 
4894743Smax.romanov@nginx.com     return out;
4895584Salexander.borisov@nginx.com }
4896584Salexander.borisov@nginx.com 
4897584Salexander.borisov@nginx.com 
489853Sigor@sysoev.ru static void
4899318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
4900318Smax.romanov@nginx.com {
4901615Smax.romanov@nginx.com     nxt_app_t                *app;
4902615Smax.romanov@nginx.com     nxt_bool_t               cancelled, unlinked;
4903615Smax.romanov@nginx.com     nxt_port_t               *port;
4904615Smax.romanov@nginx.com     nxt_timer_t              *timer;
4905615Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
4906*1007Salexander.borisov@nginx.com     nxt_http_request_t       *r;
4907615Smax.romanov@nginx.com     nxt_req_app_link_t       *pending_ra;
4908615Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
4909615Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4910318Smax.romanov@nginx.com 
4911318Smax.romanov@nginx.com     timer = obj;
4912318Smax.romanov@nginx.com 
4913318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
4914318Smax.romanov@nginx.com 
4915*1007Salexander.borisov@nginx.com     r = nxt_timer_data(timer, nxt_http_request_t, timer);
4916*1007Salexander.borisov@nginx.com     rc = r->timer_data;
4917615Smax.romanov@nginx.com     app = rc->app;
4918615Smax.romanov@nginx.com 
4919615Smax.romanov@nginx.com     if (app == NULL) {
4920615Smax.romanov@nginx.com         goto generate_error;
4921615Smax.romanov@nginx.com     }
4922615Smax.romanov@nginx.com 
4923615Smax.romanov@nginx.com     port = NULL;
4924615Smax.romanov@nginx.com     pending_ra = NULL;
4925615Smax.romanov@nginx.com 
4926615Smax.romanov@nginx.com     if (rc->app_port != NULL) {
4927615Smax.romanov@nginx.com         port = rc->app_port;
4928615Smax.romanov@nginx.com         rc->app_port = NULL;
4929615Smax.romanov@nginx.com     }
4930615Smax.romanov@nginx.com 
4931615Smax.romanov@nginx.com     if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) {
4932615Smax.romanov@nginx.com         port = rc->ra->app_port;
4933615Smax.romanov@nginx.com         rc->ra->app_port = NULL;
4934615Smax.romanov@nginx.com     }
4935615Smax.romanov@nginx.com 
4936615Smax.romanov@nginx.com     if (port == NULL) {
4937615Smax.romanov@nginx.com         goto generate_error;
4938431Sigor@sysoev.ru     }
4939615Smax.romanov@nginx.com 
4940615Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4941615Smax.romanov@nginx.com 
4942615Smax.romanov@nginx.com     unlinked = nxt_queue_chk_remove(&port->app_link);
4943615Smax.romanov@nginx.com 
4944615Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&port->pending_requests)) {
4945615Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
4946615Smax.romanov@nginx.com 
4947615Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
4948615Smax.romanov@nginx.com                                          link_port_pending);
4949615Smax.romanov@nginx.com 
4950615Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
4951615Smax.romanov@nginx.com 
4952615Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pending request #%uD found",
4953615Smax.romanov@nginx.com                   &app->name, pending_ra->stream);
4954615Smax.romanov@nginx.com 
4955615Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info,
4956615Smax.romanov@nginx.com                                           pending_ra->stream);
4957615Smax.romanov@nginx.com 
4958615Smax.romanov@nginx.com         if (cancelled) {
4959615Smax.romanov@nginx.com             nxt_router_ra_inc_use(pending_ra);
4960615Smax.romanov@nginx.com 
4961615Smax.romanov@nginx.com             state.ra = pending_ra;
4962615Smax.romanov@nginx.com             state.app = app;
4963615Smax.romanov@nginx.com 
4964615Smax.romanov@nginx.com             nxt_router_port_select(task, &state);
4965615Smax.romanov@nginx.com 
4966615Smax.romanov@nginx.com         } else {
4967615Smax.romanov@nginx.com             pending_ra = NULL;
4968615Smax.romanov@nginx.com         }
4969615Smax.romanov@nginx.com     }
4970615Smax.romanov@nginx.com 
4971615Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4972615Smax.romanov@nginx.com 
4973615Smax.romanov@nginx.com     if (pending_ra != NULL
4974615Smax.romanov@nginx.com         && nxt_router_port_post_select(task, &state) == NXT_OK)
4975615Smax.romanov@nginx.com     {
4976615Smax.romanov@nginx.com         nxt_router_app_prepare_request(task, pending_ra);
4977615Smax.romanov@nginx.com     }
4978615Smax.romanov@nginx.com 
4979615Smax.romanov@nginx.com     nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid);
4980615Smax.romanov@nginx.com 
4981615Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4982615Smax.romanov@nginx.com 
4983615Smax.romanov@nginx.com     nxt_port_use(task, port, unlinked ? -2 : -1);
4984615Smax.romanov@nginx.com 
4985615Smax.romanov@nginx.com generate_error:
4986615Smax.romanov@nginx.com 
4987*1007Salexander.borisov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
4988615Smax.romanov@nginx.com 
4989615Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
4990318Smax.romanov@nginx.com }
4991*1007Salexander.borisov@nginx.com 
4992*1007Salexander.borisov@nginx.com 
4993*1007Salexander.borisov@nginx.com static nxt_int_t
4994*1007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r)
4995*1007Salexander.borisov@nginx.com {
4996*1007Salexander.borisov@nginx.com     r->timer.handler = nxt_router_http_request_release;
4997*1007Salexander.borisov@nginx.com     nxt_timer_add(task->thread->engine, &r->timer, 0);
4998*1007Salexander.borisov@nginx.com 
4999*1007Salexander.borisov@nginx.com     return NXT_OK;
5000*1007Salexander.borisov@nginx.com }
5001*1007Salexander.borisov@nginx.com 
5002*1007Salexander.borisov@nginx.com 
5003*1007Salexander.borisov@nginx.com static void
5004*1007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
5005*1007Salexander.borisov@nginx.com {
5006*1007Salexander.borisov@nginx.com     nxt_http_request_t  *r;
5007*1007Salexander.borisov@nginx.com 
5008*1007Salexander.borisov@nginx.com     nxt_debug(task, "http app release");
5009*1007Salexander.borisov@nginx.com 
5010*1007Salexander.borisov@nginx.com     r = nxt_timer_data(obj, nxt_http_request_t, timer);
5011*1007Salexander.borisov@nginx.com 
5012*1007Salexander.borisov@nginx.com     nxt_mp_release(r->mem_pool);
5013*1007Salexander.borisov@nginx.com }
5014