xref: /unit/src/nxt_router.c (revision 771)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
10431Sigor@sysoev.ru #include <nxt_http.h>
11743Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
12743Smax.romanov@nginx.com #include <nxt_unit_request.h>
13743Smax.romanov@nginx.com #include <nxt_unit_response.h>
1420Sigor@sysoev.ru 
1520Sigor@sysoev.ru 
16115Sigor@sysoev.ru typedef struct {
17318Smax.romanov@nginx.com     nxt_str_t         type;
18507Smax.romanov@nginx.com     uint32_t          processes;
19507Smax.romanov@nginx.com     uint32_t          max_processes;
20507Smax.romanov@nginx.com     uint32_t          spare_processes;
21318Smax.romanov@nginx.com     nxt_msec_t        timeout;
22427Smax.romanov@nginx.com     nxt_msec_t        res_timeout;
23507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
24318Smax.romanov@nginx.com     uint32_t          requests;
25318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
26507Smax.romanov@nginx.com     nxt_conf_value_t  *processes_value;
27133Sigor@sysoev.ru } nxt_router_app_conf_t;
28133Sigor@sysoev.ru 
29133Sigor@sysoev.ru 
30133Sigor@sysoev.ru typedef struct {
31133Sigor@sysoev.ru     nxt_str_t  application;
32115Sigor@sysoev.ru } nxt_router_listener_conf_t;
33115Sigor@sysoev.ru 
34115Sigor@sysoev.ru 
35423Smax.romanov@nginx.com typedef struct nxt_msg_info_s {
36423Smax.romanov@nginx.com     nxt_buf_t                 *buf;
37423Smax.romanov@nginx.com     nxt_port_mmap_tracking_t  tracking;
38423Smax.romanov@nginx.com     nxt_work_handler_t        completion_handler;
39423Smax.romanov@nginx.com } nxt_msg_info_t;
40423Smax.romanov@nginx.com 
41423Smax.romanov@nginx.com 
42167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t;
43141Smax.romanov@nginx.com 
44141Smax.romanov@nginx.com 
45318Smax.romanov@nginx.com typedef struct {
46431Sigor@sysoev.ru     uint32_t                 stream;
47431Sigor@sysoev.ru     nxt_app_t                *app;
48431Sigor@sysoev.ru     nxt_port_t               *app_port;
49431Sigor@sysoev.ru     nxt_app_parse_ctx_t      *ap;
50431Sigor@sysoev.ru     nxt_msg_info_t           msg_info;
51431Sigor@sysoev.ru     nxt_req_app_link_t       *ra;
52431Sigor@sysoev.ru 
53431Sigor@sysoev.ru     nxt_queue_link_t         link;     /* for nxt_conn_t.requests */
54318Smax.romanov@nginx.com } nxt_req_conn_link_t;
55318Smax.romanov@nginx.com 
56318Smax.romanov@nginx.com 
57167Smax.romanov@nginx.com struct nxt_req_app_link_s {
58318Smax.romanov@nginx.com     uint32_t             stream;
59425Smax.romanov@nginx.com     nxt_atomic_t         use_count;
60167Smax.romanov@nginx.com     nxt_port_t           *app_port;
61167Smax.romanov@nginx.com     nxt_port_t           *reply_port;
62167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
63423Smax.romanov@nginx.com     nxt_msg_info_t       msg_info;
64167Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
65167Smax.romanov@nginx.com 
66427Smax.romanov@nginx.com     nxt_nsec_t           res_time;
67427Smax.romanov@nginx.com 
68425Smax.romanov@nginx.com     nxt_queue_link_t     link_app_requests; /* for nxt_app_t.requests */
69425Smax.romanov@nginx.com     nxt_queue_link_t     link_port_pending; /* for nxt_port_t.pending_requests */
70427Smax.romanov@nginx.com     nxt_queue_link_t     link_app_pending;  /* for nxt_app_t.pending */
71167Smax.romanov@nginx.com 
72167Smax.romanov@nginx.com     nxt_mp_t             *mem_pool;
73167Smax.romanov@nginx.com     nxt_work_t           work;
74345Smax.romanov@nginx.com 
75345Smax.romanov@nginx.com     int                  err_code;
76345Smax.romanov@nginx.com     const char           *err_str;
77167Smax.romanov@nginx.com };
78167Smax.romanov@nginx.com 
79167Smax.romanov@nginx.com 
80198Sigor@sysoev.ru typedef struct {
81198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
82198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
83198Sigor@sysoev.ru } nxt_socket_rpc_t;
84198Sigor@sysoev.ru 
85198Sigor@sysoev.ru 
86507Smax.romanov@nginx.com typedef struct {
87507Smax.romanov@nginx.com     nxt_app_t               *app;
88507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
89507Smax.romanov@nginx.com } nxt_app_rpc_t;
90507Smax.romanov@nginx.com 
91507Smax.romanov@nginx.com 
92427Smax.romanov@nginx.com struct nxt_port_select_state_s {
93427Smax.romanov@nginx.com     nxt_app_t           *app;
94427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
95427Smax.romanov@nginx.com 
96427Smax.romanov@nginx.com     nxt_port_t          *failed_port;
97427Smax.romanov@nginx.com     int                 failed_port_use_delta;
98427Smax.romanov@nginx.com 
99507Smax.romanov@nginx.com     uint8_t             start_process;    /* 1 bit */
100427Smax.romanov@nginx.com     nxt_req_app_link_t  *shared_ra;
101427Smax.romanov@nginx.com     nxt_port_t          *port;
102427Smax.romanov@nginx.com };
103427Smax.romanov@nginx.com 
104427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t;
105427Smax.romanov@nginx.com 
106662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task,
107662Smax.romanov@nginx.com     nxt_port_t *controller_port);
108662Smax.romanov@nginx.com 
109427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task,
110427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
111427Smax.romanov@nginx.com 
112427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task,
113427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
114427Smax.romanov@nginx.com 
115507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
116343Smax.romanov@nginx.com 
117425Smax.romanov@nginx.com nxt_inline void
118425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra)
119425Smax.romanov@nginx.com {
120425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, 1);
121425Smax.romanov@nginx.com }
122425Smax.romanov@nginx.com 
123425Smax.romanov@nginx.com nxt_inline void
124425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra)
125425Smax.romanov@nginx.com {
126538Svbart@nginx.com #if (NXT_DEBUG)
127425Smax.romanov@nginx.com     int  c;
128425Smax.romanov@nginx.com 
129425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, -1);
130425Smax.romanov@nginx.com 
131425Smax.romanov@nginx.com     nxt_assert(c > 1);
132538Svbart@nginx.com #else
133538Svbart@nginx.com     (void) nxt_atomic_fetch_add(&ra->use_count, -1);
134538Svbart@nginx.com #endif
135425Smax.romanov@nginx.com }
136425Smax.romanov@nginx.com 
137425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i);
138425Smax.romanov@nginx.com 
139139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
140198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
141198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
142139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
143139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
144139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
145139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
146193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
14753Sigor@sysoev.ru 
148115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
149115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
150133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
151133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
152133Sigor@sysoev.ru     nxt_str_t *name);
153198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
154198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
155198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
156198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
157198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
158198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
159507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
160507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
161507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
162507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
163507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
164507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
165359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
166359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
167359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
168359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
16953Sigor@sysoev.ru 
17053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
17153Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
17253Sigor@sysoev.ru     const nxt_event_interface_t *interface);
173115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
174115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
175115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
176115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
177115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
178115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
179154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
180154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
181154Sigor@sysoev.ru     nxt_work_handler_t handler);
182313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
183313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
184139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
185139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
18653Sigor@sysoev.ru 
18753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
18853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
18953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
19053Sigor@sysoev.ru     nxt_event_engine_t *engine);
191343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
192133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
19353Sigor@sysoev.ru 
194315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
195315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
196315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
197315Sigor@sysoev.ru     nxt_work_t *jobs);
19853Sigor@sysoev.ru 
19953Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
20053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
20153Sigor@sysoev.ru     void *data);
20253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
20353Sigor@sysoev.ru     void *data);
20453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
20553Sigor@sysoev.ru     void *data);
206313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
207313Sigor@sysoev.ru     void *data);
20853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
20953Sigor@sysoev.ru     void *data);
21053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
21153Sigor@sysoev.ru     void *data);
212359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
213359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
21453Sigor@sysoev.ru 
215630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task,
216630Svbart@nginx.com     nxt_http_request_t *r, nxt_router_access_log_t *access_log);
217630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
218630Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
219630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task,
220630Svbart@nginx.com     nxt_router_temp_conf_t *tmcf);
221630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task,
222630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
223630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task,
224630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
225630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task,
226630Svbart@nginx.com     nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
227651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
228651Svbart@nginx.com     void *data);
229631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
230631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
231631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task,
232631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
233630Svbart@nginx.com 
234343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
235343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
236343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
237343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
238343Smax.romanov@nginx.com 
239753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
240343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
241343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response);
242427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
243427Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
244141Smax.romanov@nginx.com 
245425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
246343Smax.romanov@nginx.com     nxt_req_app_link_t *ra);
247743Smax.romanov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
248743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix);
249510Salexander.borisov@nginx.com 
250318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
251507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
252507Smax.romanov@nginx.com     void *data);
253507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
254507Smax.romanov@nginx.com     void *data);
255753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
256507Smax.romanov@nginx.com     void *data);
257753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
258431Sigor@sysoev.ru 
259431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
260431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
261141Smax.romanov@nginx.com 
262753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task,
263753Smax.romanov@nginx.com     nxt_app_joint_t *app_joint, int i);
264753Smax.romanov@nginx.com 
265119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
26620Sigor@sysoev.ru 
267743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
268743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
269743Smax.romanov@nginx.com 
270743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
271743Smax.romanov@nginx.com     &http_prefix,
272743Smax.romanov@nginx.com     &http_prefix,
273743Smax.romanov@nginx.com     &empty_prefix,
274743Smax.romanov@nginx.com     &http_prefix,
275743Smax.romanov@nginx.com     &http_prefix,
276216Sigor@sysoev.ru };
277216Sigor@sysoev.ru 
278216Sigor@sysoev.ru 
279662Smax.romanov@nginx.com nxt_port_handlers_t  nxt_router_process_port_handlers = {
280662Smax.romanov@nginx.com     .quit         = nxt_worker_process_quit_handler,
281662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
282662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
283662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
284662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
285662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
286662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
287662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
288662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
289662Smax.romanov@nginx.com };
290662Smax.romanov@nginx.com 
291662Smax.romanov@nginx.com 
29220Sigor@sysoev.ru nxt_int_t
293141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
29420Sigor@sysoev.ru {
295141Smax.romanov@nginx.com     nxt_int_t      ret;
296662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
297141Smax.romanov@nginx.com     nxt_router_t   *router;
298141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
299141Smax.romanov@nginx.com 
300141Smax.romanov@nginx.com     rt = task->thread->runtime;
30153Sigor@sysoev.ru 
302*771Sigor@sysoev.ru #if (NXT_TLS)
303*771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
304*771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
305*771Sigor@sysoev.ru         return NXT_ERROR;
306*771Sigor@sysoev.ru     }
307*771Sigor@sysoev.ru 
308*771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
309*771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
310*771Sigor@sysoev.ru         return ret;
311*771Sigor@sysoev.ru     }
312*771Sigor@sysoev.ru #endif
313*771Sigor@sysoev.ru 
314431Sigor@sysoev.ru     ret = nxt_http_init(task, rt);
31588Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
31688Smax.romanov@nginx.com         return ret;
31788Smax.romanov@nginx.com     }
31888Smax.romanov@nginx.com 
31953Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
32053Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
32153Sigor@sysoev.ru         return NXT_ERROR;
32253Sigor@sysoev.ru     }
32353Sigor@sysoev.ru 
32453Sigor@sysoev.ru     nxt_queue_init(&router->engines);
32553Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
326133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
32753Sigor@sysoev.ru 
328119Smax.romanov@nginx.com     nxt_router = router;
329119Smax.romanov@nginx.com 
330662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
331662Smax.romanov@nginx.com     if (controller_port != NULL) {
332662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
333662Smax.romanov@nginx.com     }
334662Smax.romanov@nginx.com 
335115Sigor@sysoev.ru     return NXT_OK;
336115Sigor@sysoev.ru }
337115Sigor@sysoev.ru 
338115Sigor@sysoev.ru 
339343Smax.romanov@nginx.com static void
340662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
341662Smax.romanov@nginx.com {
342662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
343662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
344662Smax.romanov@nginx.com }
345662Smax.romanov@nginx.com 
346662Smax.romanov@nginx.com 
347662Smax.romanov@nginx.com static void
348507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
349507Smax.romanov@nginx.com     void *data)
350167Smax.romanov@nginx.com {
351343Smax.romanov@nginx.com     size_t         size;
352343Smax.romanov@nginx.com     uint32_t       stream;
353430Sigor@sysoev.ru     nxt_mp_t       *mp;
354648Svbart@nginx.com     nxt_int_t      ret;
355343Smax.romanov@nginx.com     nxt_app_t      *app;
356343Smax.romanov@nginx.com     nxt_buf_t      *b;
357343Smax.romanov@nginx.com     nxt_port_t     *main_port;
358343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
359343Smax.romanov@nginx.com 
360343Smax.romanov@nginx.com     app = data;
361167Smax.romanov@nginx.com 
362167Smax.romanov@nginx.com     rt = task->thread->runtime;
363240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
364167Smax.romanov@nginx.com 
365507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
366343Smax.romanov@nginx.com 
367343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
368343Smax.romanov@nginx.com 
369343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
370343Smax.romanov@nginx.com 
371343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
372343Smax.romanov@nginx.com         goto failed;
373167Smax.romanov@nginx.com     }
374167Smax.romanov@nginx.com 
375343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
376343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
377343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
378343Smax.romanov@nginx.com 
379753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
380753Smax.romanov@nginx.com 
381343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
382343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
383343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
384753Smax.romanov@nginx.com                                            -1, app->joint);
385343Smax.romanov@nginx.com 
386343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
387753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
388753Smax.romanov@nginx.com 
389343Smax.romanov@nginx.com         goto failed;
390343Smax.romanov@nginx.com     }
391343Smax.romanov@nginx.com 
392648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
393648Svbart@nginx.com                                 stream, port->id, b);
394648Svbart@nginx.com 
395648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
396648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
397753Smax.romanov@nginx.com 
398753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
399753Smax.romanov@nginx.com 
400648Svbart@nginx.com         goto failed;
401648Svbart@nginx.com     }
402343Smax.romanov@nginx.com 
403753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
404753Smax.romanov@nginx.com 
405343Smax.romanov@nginx.com     return;
406343Smax.romanov@nginx.com 
407343Smax.romanov@nginx.com failed:
408343Smax.romanov@nginx.com 
409648Svbart@nginx.com     if (b != NULL) {
410648Svbart@nginx.com         mp = b->data;
411648Svbart@nginx.com         nxt_mp_free(mp, b);
412648Svbart@nginx.com         nxt_mp_release(mp);
413648Svbart@nginx.com     }
414648Svbart@nginx.com 
415343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
416343Smax.romanov@nginx.com 
417507Smax.romanov@nginx.com     app->pending_processes--;
418343Smax.romanov@nginx.com 
419343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
420343Smax.romanov@nginx.com 
421343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
422167Smax.romanov@nginx.com }
423167Smax.romanov@nginx.com 
424167Smax.romanov@nginx.com 
425753Smax.romanov@nginx.com static void
426753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
427753Smax.romanov@nginx.com {
428753Smax.romanov@nginx.com     app_joint->use_count += i;
429753Smax.romanov@nginx.com 
430753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
431753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
432753Smax.romanov@nginx.com 
433753Smax.romanov@nginx.com         nxt_free(app_joint);
434753Smax.romanov@nginx.com     }
435753Smax.romanov@nginx.com }
436753Smax.romanov@nginx.com 
437753Smax.romanov@nginx.com 
438343Smax.romanov@nginx.com static nxt_int_t
439507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
440141Smax.romanov@nginx.com {
441343Smax.romanov@nginx.com     nxt_int_t      res;
442343Smax.romanov@nginx.com     nxt_port_t     *router_port;
443343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
444343Smax.romanov@nginx.com 
445343Smax.romanov@nginx.com     rt = task->thread->runtime;
446343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
447343Smax.romanov@nginx.com 
448343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
449343Smax.romanov@nginx.com 
450507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
451343Smax.romanov@nginx.com                         app);
452343Smax.romanov@nginx.com 
453343Smax.romanov@nginx.com     if (res == NXT_OK) {
454343Smax.romanov@nginx.com         return res;
455318Smax.romanov@nginx.com     }
456318Smax.romanov@nginx.com 
457343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
458343Smax.romanov@nginx.com 
459507Smax.romanov@nginx.com     app->pending_processes--;
460343Smax.romanov@nginx.com 
461343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
462343Smax.romanov@nginx.com 
463343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
464343Smax.romanov@nginx.com 
465343Smax.romanov@nginx.com     return NXT_ERROR;
466318Smax.romanov@nginx.com }
467318Smax.romanov@nginx.com 
468318Smax.romanov@nginx.com 
469351Smax.romanov@nginx.com nxt_inline void
470351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
471351Smax.romanov@nginx.com     nxt_req_conn_link_t *rc)
472167Smax.romanov@nginx.com {
473318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
474351Smax.romanov@nginx.com 
475318Smax.romanov@nginx.com     engine = task->thread->engine;
476167Smax.romanov@nginx.com 
477167Smax.romanov@nginx.com     nxt_memzero(ra, sizeof(nxt_req_app_link_t));
478167Smax.romanov@nginx.com 
479318Smax.romanov@nginx.com     ra->stream = rc->stream;
480425Smax.romanov@nginx.com     ra->use_count = 1;
481167Smax.romanov@nginx.com     ra->rc = rc;
482318Smax.romanov@nginx.com     rc->ra = ra;
483318Smax.romanov@nginx.com     ra->reply_port = engine->port;
484351Smax.romanov@nginx.com     ra->ap = rc->ap;
485167Smax.romanov@nginx.com 
486167Smax.romanov@nginx.com     ra->work.handler = NULL;
487318Smax.romanov@nginx.com     ra->work.task = &engine->task;
488167Smax.romanov@nginx.com     ra->work.obj = ra;
489318Smax.romanov@nginx.com     ra->work.data = engine;
490351Smax.romanov@nginx.com }
491351Smax.romanov@nginx.com 
492351Smax.romanov@nginx.com 
493351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t *
494351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
495351Smax.romanov@nginx.com {
496351Smax.romanov@nginx.com     nxt_mp_t            *mp;
497351Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
498351Smax.romanov@nginx.com 
499425Smax.romanov@nginx.com     if (ra_src->mem_pool != NULL) {
500425Smax.romanov@nginx.com         return ra_src;
501425Smax.romanov@nginx.com     }
502425Smax.romanov@nginx.com 
503351Smax.romanov@nginx.com     mp = ra_src->ap->mem_pool;
504351Smax.romanov@nginx.com 
505430Sigor@sysoev.ru     ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t));
506351Smax.romanov@nginx.com 
507351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
508351Smax.romanov@nginx.com 
509351Smax.romanov@nginx.com         ra_src->rc->ra = NULL;
510351Smax.romanov@nginx.com         ra_src->rc = NULL;
511351Smax.romanov@nginx.com 
512351Smax.romanov@nginx.com         return NULL;
513351Smax.romanov@nginx.com     }
514351Smax.romanov@nginx.com 
515430Sigor@sysoev.ru     nxt_mp_retain(mp);
516430Sigor@sysoev.ru 
517351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, ra_src->rc);
518351Smax.romanov@nginx.com 
519351Smax.romanov@nginx.com     ra->mem_pool = mp;
520167Smax.romanov@nginx.com 
521167Smax.romanov@nginx.com     return ra;
522167Smax.romanov@nginx.com }
523167Smax.romanov@nginx.com 
524167Smax.romanov@nginx.com 
525423Smax.romanov@nginx.com nxt_inline nxt_bool_t
526423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
527423Smax.romanov@nginx.com     uint32_t stream)
528423Smax.romanov@nginx.com {
529423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
530423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
531423Smax.romanov@nginx.com 
532423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
533423Smax.romanov@nginx.com         return 0;
534423Smax.romanov@nginx.com     }
535423Smax.romanov@nginx.com 
536423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
537423Smax.romanov@nginx.com                                               stream);
538423Smax.romanov@nginx.com 
539423Smax.romanov@nginx.com     if (cancelled) {
540423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
541423Smax.romanov@nginx.com     }
542423Smax.romanov@nginx.com 
543423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
544423Smax.romanov@nginx.com         next = b->next;
545423Smax.romanov@nginx.com 
546423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
547423Smax.romanov@nginx.com 
548423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
549423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
550423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
551423Smax.romanov@nginx.com         }
552423Smax.romanov@nginx.com     }
553423Smax.romanov@nginx.com 
554423Smax.romanov@nginx.com     msg_info->buf = NULL;
555423Smax.romanov@nginx.com 
556423Smax.romanov@nginx.com     return cancelled;
557423Smax.romanov@nginx.com }
558423Smax.romanov@nginx.com 
559423Smax.romanov@nginx.com 
560167Smax.romanov@nginx.com static void
561425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra);
562425Smax.romanov@nginx.com 
563425Smax.romanov@nginx.com 
564425Smax.romanov@nginx.com static void
565425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data)
566167Smax.romanov@nginx.com {
567425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
568425Smax.romanov@nginx.com 
569425Smax.romanov@nginx.com     ra = obj;
570425Smax.romanov@nginx.com 
571425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
572425Smax.romanov@nginx.com 
573425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
574425Smax.romanov@nginx.com }
575425Smax.romanov@nginx.com 
576425Smax.romanov@nginx.com 
577425Smax.romanov@nginx.com static void
578425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra)
579425Smax.romanov@nginx.com {
580343Smax.romanov@nginx.com     nxt_event_engine_t   *engine;
581343Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
582318Smax.romanov@nginx.com 
583425Smax.romanov@nginx.com     engine = ra->work.data;
584318Smax.romanov@nginx.com 
585343Smax.romanov@nginx.com     if (task->thread->engine != engine) {
586425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
587425Smax.romanov@nginx.com 
588425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_update_peer_handler;
589318Smax.romanov@nginx.com         ra->work.task = &engine->task;
590318Smax.romanov@nginx.com         ra->work.next = NULL;
591318Smax.romanov@nginx.com 
592425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post update peer to %p",
593318Smax.romanov@nginx.com                   ra->stream, engine);
594318Smax.romanov@nginx.com 
595318Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
596318Smax.romanov@nginx.com 
597318Smax.romanov@nginx.com         return;
598318Smax.romanov@nginx.com     }
599318Smax.romanov@nginx.com 
600425Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD update peer", ra->stream);
601425Smax.romanov@nginx.com 
602425Smax.romanov@nginx.com     rc = ra->rc;
603425Smax.romanov@nginx.com 
604425Smax.romanov@nginx.com     if (rc != NULL && ra->app_port != NULL) {
605425Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid);
606425Smax.romanov@nginx.com     }
607425Smax.romanov@nginx.com 
608425Smax.romanov@nginx.com     nxt_router_ra_use(task, ra, -1);
609425Smax.romanov@nginx.com }
610425Smax.romanov@nginx.com 
611425Smax.romanov@nginx.com 
612425Smax.romanov@nginx.com static void
613425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra)
614425Smax.romanov@nginx.com {
615431Sigor@sysoev.ru     nxt_mp_t                *mp;
616431Sigor@sysoev.ru     nxt_req_conn_link_t     *rc;
617425Smax.romanov@nginx.com 
618425Smax.romanov@nginx.com     nxt_assert(task->thread->engine == ra->work.data);
619425Smax.romanov@nginx.com     nxt_assert(ra->use_count == 0);
620425Smax.romanov@nginx.com 
621343Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD release", ra->stream);
622343Smax.romanov@nginx.com 
623343Smax.romanov@nginx.com     rc = ra->rc;
624343Smax.romanov@nginx.com 
625343Smax.romanov@nginx.com     if (rc != NULL) {
626423Smax.romanov@nginx.com         if (nxt_slow_path(ra->err_code != 0)) {
627431Sigor@sysoev.ru             nxt_http_request_error(task, rc->ap->request, ra->err_code);
628423Smax.romanov@nginx.com 
629423Smax.romanov@nginx.com         } else {
630423Smax.romanov@nginx.com             rc->app_port = ra->app_port;
631423Smax.romanov@nginx.com             rc->msg_info = ra->msg_info;
632423Smax.romanov@nginx.com 
633425Smax.romanov@nginx.com             if (rc->app->timeout != 0) {
634431Sigor@sysoev.ru                 rc->ap->timer.handler = nxt_router_app_timeout;
635615Smax.romanov@nginx.com                 rc->ap->timer_data = rc;
636431Sigor@sysoev.ru                 nxt_timer_add(task->thread->engine, &rc->ap->timer,
637425Smax.romanov@nginx.com                               rc->app->timeout);
638425Smax.romanov@nginx.com             }
639425Smax.romanov@nginx.com 
640423Smax.romanov@nginx.com             ra->app_port = NULL;
641423Smax.romanov@nginx.com             ra->msg_info.buf = NULL;
642423Smax.romanov@nginx.com         }
643343Smax.romanov@nginx.com 
644343Smax.romanov@nginx.com         rc->ra = NULL;
645343Smax.romanov@nginx.com         ra->rc = NULL;
646343Smax.romanov@nginx.com     }
647343Smax.romanov@nginx.com 
648343Smax.romanov@nginx.com     if (ra->app_port != NULL) {
649343Smax.romanov@nginx.com         nxt_router_app_port_release(task, ra->app_port, 0, 1);
650343Smax.romanov@nginx.com 
651343Smax.romanov@nginx.com         ra->app_port = NULL;
652167Smax.romanov@nginx.com     }
653167Smax.romanov@nginx.com 
654423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
655423Smax.romanov@nginx.com 
656430Sigor@sysoev.ru     mp = ra->mem_pool;
657430Sigor@sysoev.ru 
658430Sigor@sysoev.ru     if (mp != NULL) {
659430Sigor@sysoev.ru         nxt_mp_free(mp, ra);
660430Sigor@sysoev.ru         nxt_mp_release(mp);
661351Smax.romanov@nginx.com     }
662167Smax.romanov@nginx.com }
663167Smax.romanov@nginx.com 
664167Smax.romanov@nginx.com 
665425Smax.romanov@nginx.com static void
666425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data)
667425Smax.romanov@nginx.com {
668425Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
669425Smax.romanov@nginx.com 
670425Smax.romanov@nginx.com     ra = obj;
671425Smax.romanov@nginx.com 
672425Smax.romanov@nginx.com     nxt_assert(ra->work.data == data);
673425Smax.romanov@nginx.com 
674425Smax.romanov@nginx.com     nxt_atomic_fetch_add(&ra->use_count, -1);
675425Smax.romanov@nginx.com 
676425Smax.romanov@nginx.com     nxt_router_ra_release(task, ra);
677425Smax.romanov@nginx.com }
678425Smax.romanov@nginx.com 
679425Smax.romanov@nginx.com 
680425Smax.romanov@nginx.com static void
681425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i)
682425Smax.romanov@nginx.com {
683425Smax.romanov@nginx.com     int                 c;
684425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
685425Smax.romanov@nginx.com 
686425Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&ra->use_count, i);
687425Smax.romanov@nginx.com 
688425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
689425Smax.romanov@nginx.com         engine = ra->work.data;
690425Smax.romanov@nginx.com 
691425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
692425Smax.romanov@nginx.com             nxt_router_ra_release(task, ra);
693425Smax.romanov@nginx.com 
694425Smax.romanov@nginx.com             return;
695425Smax.romanov@nginx.com         }
696425Smax.romanov@nginx.com 
697425Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
698425Smax.romanov@nginx.com 
699425Smax.romanov@nginx.com         ra->work.handler = nxt_router_ra_release_handler;
700425Smax.romanov@nginx.com         ra->work.task = &engine->task;
701425Smax.romanov@nginx.com         ra->work.next = NULL;
702425Smax.romanov@nginx.com 
703425Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD post release to %p",
704425Smax.romanov@nginx.com                   ra->stream, engine);
705425Smax.romanov@nginx.com 
706425Smax.romanov@nginx.com         nxt_event_engine_post(engine, &ra->work);
707425Smax.romanov@nginx.com     }
708425Smax.romanov@nginx.com }
709425Smax.romanov@nginx.com 
710425Smax.romanov@nginx.com 
711423Smax.romanov@nginx.com nxt_inline void
712521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str)
713345Smax.romanov@nginx.com {
714423Smax.romanov@nginx.com     ra->app_port = NULL;
715423Smax.romanov@nginx.com     ra->err_code = code;
716423Smax.romanov@nginx.com     ra->err_str = str;
717345Smax.romanov@nginx.com }
718345Smax.romanov@nginx.com 
719345Smax.romanov@nginx.com 
720427Smax.romanov@nginx.com nxt_inline void
721427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
722427Smax.romanov@nginx.com {
723427Smax.romanov@nginx.com     nxt_queue_insert_tail(&ra->app_port->pending_requests,
724427Smax.romanov@nginx.com                           &ra->link_port_pending);
725427Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &ra->link_app_pending);
726427Smax.romanov@nginx.com 
727427Smax.romanov@nginx.com     nxt_router_ra_inc_use(ra);
728427Smax.romanov@nginx.com 
729427Smax.romanov@nginx.com     ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout;
730427Smax.romanov@nginx.com 
731427Smax.romanov@nginx.com     nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream);
732427Smax.romanov@nginx.com }
733427Smax.romanov@nginx.com 
734427Smax.romanov@nginx.com 
735425Smax.romanov@nginx.com nxt_inline nxt_bool_t
736425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
737425Smax.romanov@nginx.com {
738425Smax.romanov@nginx.com     if (lnk->next != NULL) {
739425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
740425Smax.romanov@nginx.com 
741425Smax.romanov@nginx.com         lnk->next = NULL;
742425Smax.romanov@nginx.com 
743425Smax.romanov@nginx.com         return 1;
744425Smax.romanov@nginx.com     }
745425Smax.romanov@nginx.com 
746425Smax.romanov@nginx.com     return 0;
747425Smax.romanov@nginx.com }
748425Smax.romanov@nginx.com 
749425Smax.romanov@nginx.com 
750343Smax.romanov@nginx.com nxt_inline void
751343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
752343Smax.romanov@nginx.com {
753425Smax.romanov@nginx.com     int                 ra_use_delta;
754343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
755343Smax.romanov@nginx.com 
756343Smax.romanov@nginx.com     if (rc->app_port != NULL) {
757343Smax.romanov@nginx.com         nxt_router_app_port_release(task, rc->app_port, 0, 1);
758343Smax.romanov@nginx.com 
759343Smax.romanov@nginx.com         rc->app_port = NULL;
760343Smax.romanov@nginx.com     }
761343Smax.romanov@nginx.com 
762423Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &rc->msg_info, rc->stream);
763423Smax.romanov@nginx.com 
764343Smax.romanov@nginx.com     ra = rc->ra;
765343Smax.romanov@nginx.com 
766343Smax.romanov@nginx.com     if (ra != NULL) {
767343Smax.romanov@nginx.com         rc->ra = NULL;
768343Smax.romanov@nginx.com         ra->rc = NULL;
769343Smax.romanov@nginx.com 
770425Smax.romanov@nginx.com         ra_use_delta = 0;
771425Smax.romanov@nginx.com 
772343Smax.romanov@nginx.com         nxt_thread_mutex_lock(&rc->app->mutex);
773343Smax.romanov@nginx.com 
774425Smax.romanov@nginx.com         if (ra->link_app_requests.next == NULL
775427Smax.romanov@nginx.com             && ra->link_port_pending.next == NULL
776427Smax.romanov@nginx.com             && ra->link_app_pending.next == NULL)
777425Smax.romanov@nginx.com         {
778425Smax.romanov@nginx.com             ra = NULL;
779343Smax.romanov@nginx.com 
780343Smax.romanov@nginx.com         } else {
781425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests);
782425Smax.romanov@nginx.com             ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending);
783427Smax.romanov@nginx.com             nxt_queue_chk_remove(&ra->link_app_pending);
784343Smax.romanov@nginx.com         }
785343Smax.romanov@nginx.com 
786343Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&rc->app->mutex);
787425Smax.romanov@nginx.com 
788425Smax.romanov@nginx.com         if (ra != NULL) {
789425Smax.romanov@nginx.com             nxt_router_ra_use(task, ra, ra_use_delta);
790425Smax.romanov@nginx.com         }
791343Smax.romanov@nginx.com     }
792343Smax.romanov@nginx.com 
793343Smax.romanov@nginx.com     if (rc->app != NULL) {
794343Smax.romanov@nginx.com         nxt_router_app_use(task, rc->app, -1);
795343Smax.romanov@nginx.com 
796343Smax.romanov@nginx.com         rc->app = NULL;
797343Smax.romanov@nginx.com     }
798343Smax.romanov@nginx.com 
799346Smax.romanov@nginx.com     if (rc->ap != NULL) {
800615Smax.romanov@nginx.com         rc->ap->timer_data = NULL;
801615Smax.romanov@nginx.com 
802346Smax.romanov@nginx.com         nxt_app_http_req_done(task, rc->ap);
803346Smax.romanov@nginx.com 
804346Smax.romanov@nginx.com         rc->ap = NULL;
805346Smax.romanov@nginx.com     }
806343Smax.romanov@nginx.com }
807343Smax.romanov@nginx.com 
808343Smax.romanov@nginx.com 
809141Smax.romanov@nginx.com void
810141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
811141Smax.romanov@nginx.com {
812141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
813141Smax.romanov@nginx.com 
814670Smax.romanov@nginx.com     if (msg->u.new_port != NULL
815670Smax.romanov@nginx.com         && msg->u.new_port->type == NXT_PROCESS_CONTROLLER)
816670Smax.romanov@nginx.com     {
817662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
818662Smax.romanov@nginx.com     }
819662Smax.romanov@nginx.com 
820192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
821141Smax.romanov@nginx.com         return;
822141Smax.romanov@nginx.com     }
823141Smax.romanov@nginx.com 
824426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
825426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
826347Smax.romanov@nginx.com     {
827192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
828141Smax.romanov@nginx.com     }
829192Smax.romanov@nginx.com 
830192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
831141Smax.romanov@nginx.com }
832141Smax.romanov@nginx.com 
833141Smax.romanov@nginx.com 
834139Sigor@sysoev.ru void
835139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
836115Sigor@sysoev.ru {
837198Sigor@sysoev.ru     nxt_int_t               ret;
838139Sigor@sysoev.ru     nxt_buf_t               *b;
839139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
840139Sigor@sysoev.ru 
841139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
842139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
843139Sigor@sysoev.ru         return;
84453Sigor@sysoev.ru     }
84553Sigor@sysoev.ru 
846494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
847423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
848493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
849423Smax.romanov@nginx.com 
850591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
851139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
852139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
853198Sigor@sysoev.ru                                        msg->port_msg.pid,
854198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
855198Sigor@sysoev.ru 
856591Sigor@sysoev.ru     b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool,
857591Sigor@sysoev.ru                                msg->buf, msg->size);
858551Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
859551Smax.romanov@nginx.com         nxt_router_conf_error(task, tmcf);
860551Smax.romanov@nginx.com 
861551Smax.romanov@nginx.com         return;
862551Smax.romanov@nginx.com     }
863551Smax.romanov@nginx.com 
864198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
865198Sigor@sysoev.ru 
866198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
867198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
868198Sigor@sysoev.ru 
869198Sigor@sysoev.ru     } else {
870198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
871139Sigor@sysoev.ru     }
87253Sigor@sysoev.ru }
87353Sigor@sysoev.ru 
87453Sigor@sysoev.ru 
875347Smax.romanov@nginx.com static void
876507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
877507Smax.romanov@nginx.com     void *data)
878347Smax.romanov@nginx.com {
879347Smax.romanov@nginx.com     union {
880347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
881347Smax.romanov@nginx.com         void       *data;
882347Smax.romanov@nginx.com     } u;
883347Smax.romanov@nginx.com 
884347Smax.romanov@nginx.com     u.data = data;
885347Smax.romanov@nginx.com 
886347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
887347Smax.romanov@nginx.com }
888347Smax.romanov@nginx.com 
889347Smax.romanov@nginx.com 
890192Smax.romanov@nginx.com void
891192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
892192Smax.romanov@nginx.com {
893347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
894318Smax.romanov@nginx.com 
895192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
896192Smax.romanov@nginx.com 
897192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
898192Smax.romanov@nginx.com         return;
899192Smax.romanov@nginx.com     }
900192Smax.romanov@nginx.com 
901318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
902318Smax.romanov@nginx.com     {
903507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
904347Smax.romanov@nginx.com                       msg->u.data);
905318Smax.romanov@nginx.com     }
906318Smax.romanov@nginx.com     nxt_queue_loop;
907318Smax.romanov@nginx.com 
908192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
909192Smax.romanov@nginx.com 
910192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
911192Smax.romanov@nginx.com }
912192Smax.romanov@nginx.com 
913192Smax.romanov@nginx.com 
91453Sigor@sysoev.ru static nxt_router_temp_conf_t *
915139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
91653Sigor@sysoev.ru {
91765Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
91853Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
91953Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
92053Sigor@sysoev.ru 
92165Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
92253Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
92353Sigor@sysoev.ru         return NULL;
92453Sigor@sysoev.ru     }
92553Sigor@sysoev.ru 
92665Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
92753Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
92853Sigor@sysoev.ru         goto fail;
92953Sigor@sysoev.ru     }
93053Sigor@sysoev.ru 
93153Sigor@sysoev.ru     rtcf->mem_pool = mp;
93253Sigor@sysoev.ru 
93365Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
93453Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
93553Sigor@sysoev.ru         goto fail;
93653Sigor@sysoev.ru     }
93753Sigor@sysoev.ru 
93865Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
93953Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
94053Sigor@sysoev.ru         goto temp_fail;
94153Sigor@sysoev.ru     }
94253Sigor@sysoev.ru 
94353Sigor@sysoev.ru     tmcf->mem_pool = tmp;
944591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
945139Sigor@sysoev.ru     tmcf->count = 1;
946139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
94753Sigor@sysoev.ru 
94853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
94953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
95053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
95153Sigor@sysoev.ru         goto temp_fail;
95253Sigor@sysoev.ru     }
95353Sigor@sysoev.ru 
95453Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
95553Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
95653Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
95753Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
95853Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
959416Smax.romanov@nginx.com 
960133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
961133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
96253Sigor@sysoev.ru 
96353Sigor@sysoev.ru     return tmcf;
96453Sigor@sysoev.ru 
96553Sigor@sysoev.ru temp_fail:
96653Sigor@sysoev.ru 
96765Sigor@sysoev.ru     nxt_mp_destroy(tmp);
96853Sigor@sysoev.ru 
96953Sigor@sysoev.ru fail:
97053Sigor@sysoev.ru 
97165Sigor@sysoev.ru     nxt_mp_destroy(mp);
97253Sigor@sysoev.ru 
97353Sigor@sysoev.ru     return NULL;
97453Sigor@sysoev.ru }
97553Sigor@sysoev.ru 
97653Sigor@sysoev.ru 
977507Smax.romanov@nginx.com nxt_inline nxt_bool_t
978507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
979507Smax.romanov@nginx.com {
980507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
981507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
982507Smax.romanov@nginx.com }
983507Smax.romanov@nginx.com 
984507Smax.romanov@nginx.com 
985507Smax.romanov@nginx.com nxt_inline nxt_bool_t
986507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
987507Smax.romanov@nginx.com {
988507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
989507Smax.romanov@nginx.com             < app->spare_processes;
990507Smax.romanov@nginx.com }
991507Smax.romanov@nginx.com 
992507Smax.romanov@nginx.com 
993198Sigor@sysoev.ru static void
994198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
995139Sigor@sysoev.ru {
996139Sigor@sysoev.ru     nxt_int_t                    ret;
997507Smax.romanov@nginx.com     nxt_app_t                    *app;
998139Sigor@sysoev.ru     nxt_router_t                 *router;
999139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1000198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1001198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1002630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1003198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1004139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1005139Sigor@sysoev.ru 
1006198Sigor@sysoev.ru     tmcf = obj;
1007198Sigor@sysoev.ru 
1008198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
1009198Sigor@sysoev.ru 
1010198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
1011198Sigor@sysoev.ru         nxt_queue_remove(qlk);
1012198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
1013198Sigor@sysoev.ru 
1014198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1015198Sigor@sysoev.ru 
1016198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1017198Sigor@sysoev.ru 
1018198Sigor@sysoev.ru         return;
1019139Sigor@sysoev.ru     }
1020139Sigor@sysoev.ru 
1021507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1022507Smax.romanov@nginx.com 
1023507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1024507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1025507Smax.romanov@nginx.com             return;
1026507Smax.romanov@nginx.com         }
1027507Smax.romanov@nginx.com 
1028507Smax.romanov@nginx.com     } nxt_queue_loop;
1029507Smax.romanov@nginx.com 
1030630Svbart@nginx.com     rtcf = tmcf->router_conf;
1031630Svbart@nginx.com 
1032630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1033630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1034630Svbart@nginx.com         return;
1035630Svbart@nginx.com     }
1036630Svbart@nginx.com 
1037139Sigor@sysoev.ru     rt = task->thread->runtime;
1038139Sigor@sysoev.ru 
1039139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1040139Sigor@sysoev.ru 
1041630Svbart@nginx.com     router = rtcf->router;
1042198Sigor@sysoev.ru 
1043139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1044139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1045198Sigor@sysoev.ru         goto fail;
1046139Sigor@sysoev.ru     }
1047139Sigor@sysoev.ru 
1048139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1049139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1050198Sigor@sysoev.ru         goto fail;
1051139Sigor@sysoev.ru     }
1052139Sigor@sysoev.ru 
1053343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1054139Sigor@sysoev.ru 
1055315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1056139Sigor@sysoev.ru 
1057139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
1058139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
1059139Sigor@sysoev.ru 
1060630Svbart@nginx.com     router->access_log = rtcf->access_log;
1061630Svbart@nginx.com 
1062198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1063198Sigor@sysoev.ru 
1064198Sigor@sysoev.ru     return;
1065198Sigor@sysoev.ru 
1066198Sigor@sysoev.ru fail:
1067198Sigor@sysoev.ru 
1068198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1069198Sigor@sysoev.ru 
1070198Sigor@sysoev.ru     return;
1071139Sigor@sysoev.ru }
1072139Sigor@sysoev.ru 
1073139Sigor@sysoev.ru 
1074139Sigor@sysoev.ru static void
1075139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1076139Sigor@sysoev.ru {
1077153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1078153Sigor@sysoev.ru 
1079153Sigor@sysoev.ru     job = obj;
1080153Sigor@sysoev.ru 
1081198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1082139Sigor@sysoev.ru }
1083139Sigor@sysoev.ru 
1084139Sigor@sysoev.ru 
1085139Sigor@sysoev.ru static void
1086198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1087139Sigor@sysoev.ru {
1088139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
1089139Sigor@sysoev.ru 
1090139Sigor@sysoev.ru     if (--tmcf->count == 0) {
1091193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1092139Sigor@sysoev.ru     }
1093139Sigor@sysoev.ru }
1094139Sigor@sysoev.ru 
1095139Sigor@sysoev.ru 
1096139Sigor@sysoev.ru static void
1097139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1098139Sigor@sysoev.ru {
1099507Smax.romanov@nginx.com     nxt_app_t          *app;
1100568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1101148Sigor@sysoev.ru     nxt_socket_t       s;
1102149Sigor@sysoev.ru     nxt_router_t       *router;
1103148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1104148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1105630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1106148Sigor@sysoev.ru 
1107564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1108198Sigor@sysoev.ru 
1109148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
1110148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
1111148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1112148Sigor@sysoev.ru     {
1113148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1114359Sigor@sysoev.ru         s = skcf->listen->socket;
1115148Sigor@sysoev.ru 
1116148Sigor@sysoev.ru         if (s != -1) {
1117148Sigor@sysoev.ru             nxt_socket_close(task, s);
1118148Sigor@sysoev.ru         }
1119148Sigor@sysoev.ru 
1120359Sigor@sysoev.ru         nxt_free(skcf->listen);
1121148Sigor@sysoev.ru     }
1122148Sigor@sysoev.ru 
1123568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
1124568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->updating);
1125568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->pending);
1126568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->creating);
1127568Smax.romanov@nginx.com 
1128568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1129568Smax.romanov@nginx.com 
1130568Smax.romanov@nginx.com         if (skcf->application != NULL) {
1131568Smax.romanov@nginx.com             nxt_router_app_use(task, skcf->application, -1);
1132568Smax.romanov@nginx.com             skcf->application = NULL;
1133568Smax.romanov@nginx.com         }
1134568Smax.romanov@nginx.com 
1135568Smax.romanov@nginx.com     } nxt_queue_loop;
1136568Smax.romanov@nginx.com 
1137507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1138507Smax.romanov@nginx.com 
1139753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1140507Smax.romanov@nginx.com 
1141507Smax.romanov@nginx.com     } nxt_queue_loop;
1142507Smax.romanov@nginx.com 
1143630Svbart@nginx.com     rtcf = tmcf->router_conf;
1144630Svbart@nginx.com     router = rtcf->router;
1145149Sigor@sysoev.ru 
1146149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1147149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1148149Sigor@sysoev.ru 
1149416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1150416Smax.romanov@nginx.com 
1151148Sigor@sysoev.ru     // TODO: new engines and threads
1152148Sigor@sysoev.ru 
1153630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1154630Svbart@nginx.com 
1155630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1156139Sigor@sysoev.ru 
1157193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1158139Sigor@sysoev.ru }
1159139Sigor@sysoev.ru 
1160139Sigor@sysoev.ru 
1161139Sigor@sysoev.ru static void
1162139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1163193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1164139Sigor@sysoev.ru {
1165193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1166139Sigor@sysoev.ru }
1167139Sigor@sysoev.ru 
1168139Sigor@sysoev.ru 
1169115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1170115Sigor@sysoev.ru     {
1171133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1172115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1173115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1174115Sigor@sysoev.ru     },
1175115Sigor@sysoev.ru };
1176115Sigor@sysoev.ru 
1177115Sigor@sysoev.ru 
1178133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1179115Sigor@sysoev.ru     {
1180133Sigor@sysoev.ru         nxt_string("type"),
1181115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1182133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1183115Sigor@sysoev.ru     },
1184115Sigor@sysoev.ru 
1185115Sigor@sysoev.ru     {
1186507Smax.romanov@nginx.com         nxt_string("limits"),
1187507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1188507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1189133Sigor@sysoev.ru     },
1190318Smax.romanov@nginx.com 
1191318Smax.romanov@nginx.com     {
1192507Smax.romanov@nginx.com         nxt_string("processes"),
1193507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1194507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1195507Smax.romanov@nginx.com     },
1196507Smax.romanov@nginx.com 
1197507Smax.romanov@nginx.com     {
1198507Smax.romanov@nginx.com         nxt_string("processes"),
1199318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1200507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1201318Smax.romanov@nginx.com     },
1202318Smax.romanov@nginx.com };
1203318Smax.romanov@nginx.com 
1204318Smax.romanov@nginx.com 
1205318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1206318Smax.romanov@nginx.com     {
1207318Smax.romanov@nginx.com         nxt_string("timeout"),
1208318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1209318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1210318Smax.romanov@nginx.com     },
1211318Smax.romanov@nginx.com 
1212318Smax.romanov@nginx.com     {
1213427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1214427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1215427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1216427Smax.romanov@nginx.com     },
1217427Smax.romanov@nginx.com 
1218427Smax.romanov@nginx.com     {
1219318Smax.romanov@nginx.com         nxt_string("requests"),
1220318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1221318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1222318Smax.romanov@nginx.com     },
1223133Sigor@sysoev.ru };
1224133Sigor@sysoev.ru 
1225133Sigor@sysoev.ru 
1226507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1227507Smax.romanov@nginx.com     {
1228507Smax.romanov@nginx.com         nxt_string("spare"),
1229507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1230507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1231507Smax.romanov@nginx.com     },
1232507Smax.romanov@nginx.com 
1233507Smax.romanov@nginx.com     {
1234507Smax.romanov@nginx.com         nxt_string("max"),
1235507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1236507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1237507Smax.romanov@nginx.com     },
1238507Smax.romanov@nginx.com 
1239507Smax.romanov@nginx.com     {
1240507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1241507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1242507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1243507Smax.romanov@nginx.com     },
1244507Smax.romanov@nginx.com };
1245507Smax.romanov@nginx.com 
1246507Smax.romanov@nginx.com 
1247133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1248133Sigor@sysoev.ru     {
1249133Sigor@sysoev.ru         nxt_string("application"),
1250133Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1251133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1252115Sigor@sysoev.ru     },
1253115Sigor@sysoev.ru };
1254115Sigor@sysoev.ru 
1255115Sigor@sysoev.ru 
1256115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1257115Sigor@sysoev.ru     {
1258115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1259115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1260115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1261115Sigor@sysoev.ru     },
1262115Sigor@sysoev.ru 
1263115Sigor@sysoev.ru     {
1264115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1265115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1266115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1267115Sigor@sysoev.ru     },
1268115Sigor@sysoev.ru 
1269115Sigor@sysoev.ru     {
1270206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1271206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1272206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1273206Smax.romanov@nginx.com     },
1274206Smax.romanov@nginx.com 
1275206Smax.romanov@nginx.com     {
1276206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1277206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1278206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1279206Smax.romanov@nginx.com     },
1280206Smax.romanov@nginx.com 
1281206Smax.romanov@nginx.com     {
1282206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1283206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1284206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1285206Smax.romanov@nginx.com     },
1286206Smax.romanov@nginx.com 
1287206Smax.romanov@nginx.com     {
1288431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1289431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1290431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1291431Sigor@sysoev.ru     },
1292431Sigor@sysoev.ru 
1293431Sigor@sysoev.ru     {
1294115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1295115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1296115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1297115Sigor@sysoev.ru     },
1298206Smax.romanov@nginx.com 
1299206Smax.romanov@nginx.com     {
1300206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1301206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1302206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1303206Smax.romanov@nginx.com     },
1304431Sigor@sysoev.ru 
1305431Sigor@sysoev.ru     {
1306431Sigor@sysoev.ru         nxt_string("send_timeout"),
1307431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1308431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1309431Sigor@sysoev.ru     },
1310115Sigor@sysoev.ru };
1311115Sigor@sysoev.ru 
1312115Sigor@sysoev.ru 
131353Sigor@sysoev.ru static nxt_int_t
1314115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1315115Sigor@sysoev.ru     u_char *start, u_char *end)
131653Sigor@sysoev.ru {
1317133Sigor@sysoev.ru     u_char                      *p;
1318133Sigor@sysoev.ru     size_t                      size;
1319115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1320115Sigor@sysoev.ru     uint32_t                    next;
1321115Sigor@sysoev.ru     nxt_int_t                   ret;
1322630Svbart@nginx.com     nxt_str_t                   name, path;
1323133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1324359Sigor@sysoev.ru     nxt_router_t                *router;
1325753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
1326630Svbart@nginx.com     nxt_conf_value_t            *conf, *http, *value;
1327133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1328133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1329115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1330507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1331216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1332133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1333630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1334115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1335115Sigor@sysoev.ru 
1336716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1337133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1338115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1339630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1340115Sigor@sysoev.ru 
1341208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1342115Sigor@sysoev.ru     if (conf == NULL) {
1343564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1344115Sigor@sysoev.ru         return NXT_ERROR;
1345115Sigor@sysoev.ru     }
1346115Sigor@sysoev.ru 
1347591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1348213Svbart@nginx.com 
1349213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1350591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1351115Sigor@sysoev.ru     if (ret != NXT_OK) {
1352564Svbart@nginx.com         nxt_alert(task, "root map error");
1353115Sigor@sysoev.ru         return NXT_ERROR;
1354115Sigor@sysoev.ru     }
1355115Sigor@sysoev.ru 
1356591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1357591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1358117Sigor@sysoev.ru     }
1359117Sigor@sysoev.ru 
1360133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
1361133Sigor@sysoev.ru     if (applications == NULL) {
1362564Svbart@nginx.com         nxt_alert(task, "no \"applications\" block");
1363115Sigor@sysoev.ru         return NXT_ERROR;
1364115Sigor@sysoev.ru     }
1365115Sigor@sysoev.ru 
1366591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1367359Sigor@sysoev.ru 
1368133Sigor@sysoev.ru     next = 0;
1369133Sigor@sysoev.ru 
1370133Sigor@sysoev.ru     for ( ;; ) {
1371133Sigor@sysoev.ru         application = nxt_conf_next_object_member(applications, &name, &next);
1372133Sigor@sysoev.ru         if (application == NULL) {
1373133Sigor@sysoev.ru             break;
1374133Sigor@sysoev.ru         }
1375133Sigor@sysoev.ru 
1376133Sigor@sysoev.ru         nxt_debug(task, "application \"%V\"", &name);
1377133Sigor@sysoev.ru 
1378144Smax.romanov@nginx.com         size = nxt_conf_json_length(application, NULL);
1379144Smax.romanov@nginx.com 
1380144Smax.romanov@nginx.com         app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
1381133Sigor@sysoev.ru         if (app == NULL) {
1382133Sigor@sysoev.ru             goto fail;
1383133Sigor@sysoev.ru         }
1384133Sigor@sysoev.ru 
1385144Smax.romanov@nginx.com         nxt_memzero(app, sizeof(nxt_app_t));
1386144Smax.romanov@nginx.com 
1387144Smax.romanov@nginx.com         app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1388144Smax.romanov@nginx.com         app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length);
1389133Sigor@sysoev.ru 
1390133Sigor@sysoev.ru         p = nxt_conf_json_print(app->conf.start, application, NULL);
1391133Sigor@sysoev.ru         app->conf.length = p - app->conf.start;
1392133Sigor@sysoev.ru 
1393144Smax.romanov@nginx.com         nxt_assert(app->conf.length <= size);
1394144Smax.romanov@nginx.com 
1395133Sigor@sysoev.ru         nxt_debug(task, "application conf \"%V\"", &app->conf);
1396133Sigor@sysoev.ru 
1397359Sigor@sysoev.ru         prev = nxt_router_app_find(&router->apps, &name);
1398133Sigor@sysoev.ru 
1399133Sigor@sysoev.ru         if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1400133Sigor@sysoev.ru             nxt_free(app);
1401133Sigor@sysoev.ru 
1402133Sigor@sysoev.ru             nxt_queue_remove(&prev->link);
1403133Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1404133Sigor@sysoev.ru             continue;
1405133Sigor@sysoev.ru         }
1406133Sigor@sysoev.ru 
1407507Smax.romanov@nginx.com         apcf.processes = 1;
1408507Smax.romanov@nginx.com         apcf.max_processes = 1;
1409537Svbart@nginx.com         apcf.spare_processes = 0;
1410318Smax.romanov@nginx.com         apcf.timeout = 0;
1411427Smax.romanov@nginx.com         apcf.res_timeout = 1000;
1412507Smax.romanov@nginx.com         apcf.idle_timeout = 15000;
1413318Smax.romanov@nginx.com         apcf.requests = 0;
1414318Smax.romanov@nginx.com         apcf.limits_value = NULL;
1415507Smax.romanov@nginx.com         apcf.processes_value = NULL;
1416263Smax.romanov@nginx.com 
1417753Smax.romanov@nginx.com         app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
1418753Smax.romanov@nginx.com         if (nxt_slow_path(app_joint == NULL)) {
1419753Smax.romanov@nginx.com             goto app_fail;
1420753Smax.romanov@nginx.com         }
1421753Smax.romanov@nginx.com 
1422753Smax.romanov@nginx.com         nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
1423753Smax.romanov@nginx.com 
1424213Svbart@nginx.com         ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1425136Svbart@nginx.com                                   nxt_nitems(nxt_router_app_conf), &apcf);
1426133Sigor@sysoev.ru         if (ret != NXT_OK) {
1427564Svbart@nginx.com             nxt_alert(task, "application map error");
1428133Sigor@sysoev.ru             goto app_fail;
1429133Sigor@sysoev.ru         }
1430115Sigor@sysoev.ru 
1431318Smax.romanov@nginx.com         if (apcf.limits_value != NULL) {
1432318Smax.romanov@nginx.com 
1433318Smax.romanov@nginx.com             if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1434564Svbart@nginx.com                 nxt_alert(task, "application limits is not object");
1435318Smax.romanov@nginx.com                 goto app_fail;
1436318Smax.romanov@nginx.com             }
1437318Smax.romanov@nginx.com 
1438318Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.limits_value,
1439318Smax.romanov@nginx.com                                       nxt_router_app_limits_conf,
1440318Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_limits_conf),
1441318Smax.romanov@nginx.com                                       &apcf);
1442318Smax.romanov@nginx.com             if (ret != NXT_OK) {
1443564Svbart@nginx.com                 nxt_alert(task, "application limits map error");
1444318Smax.romanov@nginx.com                 goto app_fail;
1445318Smax.romanov@nginx.com             }
1446318Smax.romanov@nginx.com         }
1447318Smax.romanov@nginx.com 
1448507Smax.romanov@nginx.com         if (apcf.processes_value != NULL
1449507Smax.romanov@nginx.com             && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1450507Smax.romanov@nginx.com         {
1451507Smax.romanov@nginx.com             ret = nxt_conf_map_object(mp, apcf.processes_value,
1452507Smax.romanov@nginx.com                                       nxt_router_app_processes_conf,
1453507Smax.romanov@nginx.com                                       nxt_nitems(nxt_router_app_processes_conf),
1454507Smax.romanov@nginx.com                                       &apcf);
1455507Smax.romanov@nginx.com             if (ret != NXT_OK) {
1456564Svbart@nginx.com                 nxt_alert(task, "application processes map error");
1457507Smax.romanov@nginx.com                 goto app_fail;
1458507Smax.romanov@nginx.com             }
1459507Smax.romanov@nginx.com 
1460507Smax.romanov@nginx.com         } else {
1461507Smax.romanov@nginx.com             apcf.max_processes = apcf.processes;
1462507Smax.romanov@nginx.com             apcf.spare_processes = apcf.processes;
1463507Smax.romanov@nginx.com         }
1464507Smax.romanov@nginx.com 
1465133Sigor@sysoev.ru         nxt_debug(task, "application type: %V", &apcf.type);
1466507Smax.romanov@nginx.com         nxt_debug(task, "application processes: %D", apcf.processes);
1467507Smax.romanov@nginx.com         nxt_debug(task, "application request timeout: %M", apcf.timeout);
1468507Smax.romanov@nginx.com         nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout);
1469318Smax.romanov@nginx.com         nxt_debug(task, "application requests: %D", apcf.requests);
1470133Sigor@sysoev.ru 
1471216Sigor@sysoev.ru         lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1472216Sigor@sysoev.ru 
1473216Sigor@sysoev.ru         if (lang == NULL) {
1474564Svbart@nginx.com             nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1475141Smax.romanov@nginx.com             goto app_fail;
1476141Smax.romanov@nginx.com         }
1477141Smax.romanov@nginx.com 
1478216Sigor@sysoev.ru         nxt_debug(task, "application language module: \"%s\"", lang->file);
1479216Sigor@sysoev.ru 
1480133Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&app->mutex);
1481133Sigor@sysoev.ru         if (ret != NXT_OK) {
1482133Sigor@sysoev.ru             goto app_fail;
1483133Sigor@sysoev.ru         }
1484133Sigor@sysoev.ru 
1485141Smax.romanov@nginx.com         nxt_queue_init(&app->ports);
1486507Smax.romanov@nginx.com         nxt_queue_init(&app->spare_ports);
1487507Smax.romanov@nginx.com         nxt_queue_init(&app->idle_ports);
1488141Smax.romanov@nginx.com         nxt_queue_init(&app->requests);
1489427Smax.romanov@nginx.com         nxt_queue_init(&app->pending);
1490141Smax.romanov@nginx.com 
1491144Smax.romanov@nginx.com         app->name.length = name.length;
1492144Smax.romanov@nginx.com         nxt_memcpy(app->name.start, name.start, name.length);
1493144Smax.romanov@nginx.com 
1494356Svbart@nginx.com         app->type = lang->type;
1495507Smax.romanov@nginx.com         app->max_processes = apcf.max_processes;
1496507Smax.romanov@nginx.com         app->spare_processes = apcf.spare_processes;
1497507Smax.romanov@nginx.com         app->max_pending_processes = apcf.spare_processes
1498507Smax.romanov@nginx.com                                       ? apcf.spare_processes : 1;
1499318Smax.romanov@nginx.com         app->timeout = apcf.timeout;
1500427Smax.romanov@nginx.com         app->res_timeout = apcf.res_timeout * 1000000;
1501507Smax.romanov@nginx.com         app->idle_timeout = apcf.idle_timeout;
1502343Smax.romanov@nginx.com         app->max_pending_responses = 2;
1503428Smax.romanov@nginx.com         app->max_requests = apcf.requests;
1504133Sigor@sysoev.ru 
1505507Smax.romanov@nginx.com         engine = task->thread->engine;
1506507Smax.romanov@nginx.com 
1507507Smax.romanov@nginx.com         app->engine = engine;
1508507Smax.romanov@nginx.com 
1509507Smax.romanov@nginx.com         app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1510507Smax.romanov@nginx.com         app->adjust_idle_work.task = &engine->task;
1511507Smax.romanov@nginx.com         app->adjust_idle_work.obj = app;
1512507Smax.romanov@nginx.com 
1513133Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->apps, &app->link);
1514343Smax.romanov@nginx.com 
1515343Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
1516753Smax.romanov@nginx.com 
1517753Smax.romanov@nginx.com         app->joint = app_joint;
1518753Smax.romanov@nginx.com 
1519753Smax.romanov@nginx.com         app_joint->use_count = 1;
1520753Smax.romanov@nginx.com         app_joint->app = app;
1521753Smax.romanov@nginx.com 
1522753Smax.romanov@nginx.com         app_joint->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION;
1523753Smax.romanov@nginx.com         app_joint->idle_timer.work_queue = &engine->fast_work_queue;
1524753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
1525753Smax.romanov@nginx.com         app_joint->idle_timer.task = &engine->task;
1526753Smax.romanov@nginx.com         app_joint->idle_timer.log = app_joint->idle_timer.task->log;
1527753Smax.romanov@nginx.com 
1528753Smax.romanov@nginx.com         app_joint->free_app_work.handler = nxt_router_free_app;
1529753Smax.romanov@nginx.com         app_joint->free_app_work.task = &engine->task;
1530753Smax.romanov@nginx.com         app_joint->free_app_work.obj = app_joint;
1531133Sigor@sysoev.ru     }
1532133Sigor@sysoev.ru 
1533133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1534133Sigor@sysoev.ru #if 0
1535133Sigor@sysoev.ru     if (http == NULL) {
1536564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1537133Sigor@sysoev.ru         return NXT_ERROR;
1538133Sigor@sysoev.ru     }
1539133Sigor@sysoev.ru #endif
1540133Sigor@sysoev.ru 
1541133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
1542115Sigor@sysoev.ru     if (listeners == NULL) {
1543564Svbart@nginx.com         nxt_alert(task, "no \"listeners\" block");
1544115Sigor@sysoev.ru         return NXT_ERROR;
1545115Sigor@sysoev.ru     }
154653Sigor@sysoev.ru 
1547133Sigor@sysoev.ru     next = 0;
154853Sigor@sysoev.ru 
1549115Sigor@sysoev.ru     for ( ;; ) {
1550115Sigor@sysoev.ru         listener = nxt_conf_next_object_member(listeners, &name, &next);
1551115Sigor@sysoev.ru         if (listener == NULL) {
1552115Sigor@sysoev.ru             break;
1553115Sigor@sysoev.ru         }
155453Sigor@sysoev.ru 
1555359Sigor@sysoev.ru         skcf = nxt_router_socket_conf(task, tmcf, &name);
1556115Sigor@sysoev.ru         if (skcf == NULL) {
1557133Sigor@sysoev.ru             goto fail;
1558115Sigor@sysoev.ru         }
155953Sigor@sysoev.ru 
1560770Smax.romanov@nginx.com         nxt_memzero(&lscf, sizeof(lscf));
1561770Smax.romanov@nginx.com 
1562213Svbart@nginx.com         ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1563136Svbart@nginx.com                                   nxt_nitems(nxt_router_listener_conf), &lscf);
1564115Sigor@sysoev.ru         if (ret != NXT_OK) {
1565564Svbart@nginx.com             nxt_alert(task, "listener map error");
1566133Sigor@sysoev.ru             goto fail;
1567115Sigor@sysoev.ru         }
156853Sigor@sysoev.ru 
1569133Sigor@sysoev.ru         nxt_debug(task, "application: %V", &lscf.application);
1570133Sigor@sysoev.ru 
1571133Sigor@sysoev.ru         // STUB, default values if http block is not defined.
1572133Sigor@sysoev.ru         skcf->header_buffer_size = 2048;
1573133Sigor@sysoev.ru         skcf->large_header_buffer_size = 8192;
1574206Smax.romanov@nginx.com         skcf->large_header_buffers = 4;
1575206Smax.romanov@nginx.com         skcf->body_buffer_size = 16 * 1024;
1576715Svbart@nginx.com         skcf->max_body_size = 8 * 1024 * 1024;
1577715Svbart@nginx.com         skcf->idle_timeout = 180 * 1000;
1578715Svbart@nginx.com         skcf->header_read_timeout = 30 * 1000;
1579715Svbart@nginx.com         skcf->body_read_timeout = 30 * 1000;
1580715Svbart@nginx.com         skcf->send_timeout = 30 * 1000;
158153Sigor@sysoev.ru 
1582133Sigor@sysoev.ru         if (http != NULL) {
1583213Svbart@nginx.com             ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1584136Svbart@nginx.com                                       nxt_nitems(nxt_router_http_conf), skcf);
1585133Sigor@sysoev.ru             if (ret != NXT_OK) {
1586564Svbart@nginx.com                 nxt_alert(task, "http map error");
1587133Sigor@sysoev.ru                 goto fail;
1588133Sigor@sysoev.ru             }
1589115Sigor@sysoev.ru         }
1590115Sigor@sysoev.ru 
1591431Sigor@sysoev.ru         skcf->listen->handler = nxt_http_conn_init;
1592591Sigor@sysoev.ru         skcf->router_conf = tmcf->router_conf;
1593160Sigor@sysoev.ru         skcf->router_conf->count++;
1594770Smax.romanov@nginx.com 
1595770Smax.romanov@nginx.com         if (lscf.application.length > 0) {
1596770Smax.romanov@nginx.com             skcf->application = nxt_router_listener_application(tmcf,
1597133Sigor@sysoev.ru                                                             &lscf.application);
1598770Smax.romanov@nginx.com             nxt_router_app_use(task, skcf->application, 1);
1599770Smax.romanov@nginx.com         }
1600115Sigor@sysoev.ru     }
160153Sigor@sysoev.ru 
1602630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1603630Svbart@nginx.com 
1604630Svbart@nginx.com     if (value != NULL) {
1605630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1606630Svbart@nginx.com 
1607630Svbart@nginx.com         access_log = router->access_log;
1608630Svbart@nginx.com 
1609630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1610630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1611630Svbart@nginx.com             access_log->count++;
1612630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1613630Svbart@nginx.com 
1614630Svbart@nginx.com         } else {
1615630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1616630Svbart@nginx.com                                     + path.length);
1617630Svbart@nginx.com             if (access_log == NULL) {
1618630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1619630Svbart@nginx.com                 goto fail;
1620630Svbart@nginx.com             }
1621630Svbart@nginx.com 
1622630Svbart@nginx.com             access_log->fd = -1;
1623630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1624630Svbart@nginx.com             access_log->count = 1;
1625630Svbart@nginx.com 
1626630Svbart@nginx.com             access_log->path.length = path.length;
1627630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1628630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1629630Svbart@nginx.com 
1630630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1631630Svbart@nginx.com         }
1632630Svbart@nginx.com 
1633630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1634630Svbart@nginx.com     }
1635630Svbart@nginx.com 
1636359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1637359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1638198Sigor@sysoev.ru 
163953Sigor@sysoev.ru     return NXT_OK;
1640133Sigor@sysoev.ru 
1641133Sigor@sysoev.ru app_fail:
1642133Sigor@sysoev.ru 
1643133Sigor@sysoev.ru     nxt_free(app);
1644133Sigor@sysoev.ru 
1645133Sigor@sysoev.ru fail:
1646133Sigor@sysoev.ru 
1647141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1648141Smax.romanov@nginx.com 
1649141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1650133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1651133Sigor@sysoev.ru         nxt_free(app);
1652141Smax.romanov@nginx.com 
1653141Smax.romanov@nginx.com     } nxt_queue_loop;
1654133Sigor@sysoev.ru 
1655133Sigor@sysoev.ru     return NXT_ERROR;
1656133Sigor@sysoev.ru }
1657133Sigor@sysoev.ru 
1658133Sigor@sysoev.ru 
1659133Sigor@sysoev.ru static nxt_app_t *
1660133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1661133Sigor@sysoev.ru {
1662141Smax.romanov@nginx.com     nxt_app_t  *app;
1663141Smax.romanov@nginx.com 
1664141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1665133Sigor@sysoev.ru 
1666133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1667133Sigor@sysoev.ru             return app;
1668133Sigor@sysoev.ru         }
1669141Smax.romanov@nginx.com 
1670141Smax.romanov@nginx.com     } nxt_queue_loop;
1671133Sigor@sysoev.ru 
1672133Sigor@sysoev.ru     return NULL;
1673133Sigor@sysoev.ru }
1674133Sigor@sysoev.ru 
1675133Sigor@sysoev.ru 
1676133Sigor@sysoev.ru static nxt_app_t *
1677133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1678133Sigor@sysoev.ru {
1679133Sigor@sysoev.ru     nxt_app_t  *app;
1680133Sigor@sysoev.ru 
1681133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1682133Sigor@sysoev.ru 
1683133Sigor@sysoev.ru     if (app == NULL) {
1684134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1685133Sigor@sysoev.ru     }
1686133Sigor@sysoev.ru 
1687133Sigor@sysoev.ru     return app;
168853Sigor@sysoev.ru }
168953Sigor@sysoev.ru 
169053Sigor@sysoev.ru 
169153Sigor@sysoev.ru static nxt_socket_conf_t *
1692359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1693359Sigor@sysoev.ru     nxt_str_t *name)
169453Sigor@sysoev.ru {
1695359Sigor@sysoev.ru     size_t               size;
1696359Sigor@sysoev.ru     nxt_int_t            ret;
1697359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1698359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1699359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1700359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1701359Sigor@sysoev.ru 
1702359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1703359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1704564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1705359Sigor@sysoev.ru         return NULL;
1706359Sigor@sysoev.ru     }
1707359Sigor@sysoev.ru 
1708359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1709359Sigor@sysoev.ru 
1710359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1711493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1712359Sigor@sysoev.ru 
1713591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1714163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
171553Sigor@sysoev.ru         return NULL;
171653Sigor@sysoev.ru     }
171753Sigor@sysoev.ru 
1718359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1719359Sigor@sysoev.ru 
1720359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1721359Sigor@sysoev.ru 
1722359Sigor@sysoev.ru     if (ret != NXT_OK) {
1723359Sigor@sysoev.ru 
1724359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1725359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1726359Sigor@sysoev.ru             return NULL;
1727359Sigor@sysoev.ru         }
1728359Sigor@sysoev.ru 
1729359Sigor@sysoev.ru         skcf->listen = ls;
1730359Sigor@sysoev.ru 
1731359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1732359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1733359Sigor@sysoev.ru 
1734359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1735359Sigor@sysoev.ru 
1736359Sigor@sysoev.ru         ls->socket = -1;
1737359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1738359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1739359Sigor@sysoev.ru         ls->read_after_accept = 1;
1740359Sigor@sysoev.ru     }
1741359Sigor@sysoev.ru 
1742359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1743359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1744359Sigor@sysoev.ru     case AF_UNIX:
1745359Sigor@sysoev.ru         wildcard = 0;
1746359Sigor@sysoev.ru         break;
1747359Sigor@sysoev.ru #endif
1748359Sigor@sysoev.ru #if (NXT_INET6)
1749359Sigor@sysoev.ru     case AF_INET6:
1750359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1751359Sigor@sysoev.ru         break;
1752359Sigor@sysoev.ru #endif
1753359Sigor@sysoev.ru     case AF_INET:
1754359Sigor@sysoev.ru     default:
1755359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1756359Sigor@sysoev.ru         break;
1757359Sigor@sysoev.ru     }
1758359Sigor@sysoev.ru 
1759359Sigor@sysoev.ru     if (!wildcard) {
1760591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
1761359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1762359Sigor@sysoev.ru             return NULL;
1763359Sigor@sysoev.ru         }
1764359Sigor@sysoev.ru 
1765359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1766359Sigor@sysoev.ru     }
1767163Smax.romanov@nginx.com 
1768163Smax.romanov@nginx.com     return skcf;
176953Sigor@sysoev.ru }
177053Sigor@sysoev.ru 
177153Sigor@sysoev.ru 
1772359Sigor@sysoev.ru static nxt_int_t
1773359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1774359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
177553Sigor@sysoev.ru {
1776359Sigor@sysoev.ru     nxt_router_t       *router;
1777359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1778359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1779359Sigor@sysoev.ru 
1780591Sigor@sysoev.ru     router = tmcf->router_conf->router;
1781359Sigor@sysoev.ru 
1782359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
1783359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
1784359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
178553Sigor@sysoev.ru     {
1786359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1787359Sigor@sysoev.ru 
1788359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
1789359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
1790359Sigor@sysoev.ru 
1791359Sigor@sysoev.ru             nxt_queue_remove(qlk);
1792359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
1793359Sigor@sysoev.ru 
1794359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
1795359Sigor@sysoev.ru 
1796359Sigor@sysoev.ru             return NXT_OK;
179753Sigor@sysoev.ru         }
179853Sigor@sysoev.ru     }
179953Sigor@sysoev.ru 
1800359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
1801359Sigor@sysoev.ru 
1802359Sigor@sysoev.ru     return NXT_DECLINED;
180353Sigor@sysoev.ru }
180453Sigor@sysoev.ru 
180553Sigor@sysoev.ru 
1806198Sigor@sysoev.ru static void
1807198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
1808198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
1809198Sigor@sysoev.ru {
1810358Sigor@sysoev.ru     size_t            size;
1811198Sigor@sysoev.ru     uint32_t          stream;
1812648Svbart@nginx.com     nxt_int_t         ret;
1813198Sigor@sysoev.ru     nxt_buf_t         *b;
1814198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
1815198Sigor@sysoev.ru     nxt_runtime_t     *rt;
1816198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
1817198Sigor@sysoev.ru 
1818198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
1819198Sigor@sysoev.ru     if (rpc == NULL) {
1820198Sigor@sysoev.ru         goto fail;
1821198Sigor@sysoev.ru     }
1822198Sigor@sysoev.ru 
1823198Sigor@sysoev.ru     rpc->socket_conf = skcf;
1824198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
1825198Sigor@sysoev.ru 
1826359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
1827358Sigor@sysoev.ru 
1828358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1829198Sigor@sysoev.ru     if (b == NULL) {
1830198Sigor@sysoev.ru         goto fail;
1831198Sigor@sysoev.ru     }
1832198Sigor@sysoev.ru 
1833359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
1834198Sigor@sysoev.ru 
1835198Sigor@sysoev.ru     rt = task->thread->runtime;
1836240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1837198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1838198Sigor@sysoev.ru 
1839198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
1840198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
1841198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
1842198Sigor@sysoev.ru                                            main_port->pid, rpc);
1843645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
1844198Sigor@sysoev.ru         goto fail;
1845198Sigor@sysoev.ru     }
1846198Sigor@sysoev.ru 
1847648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
1848648Svbart@nginx.com                                 stream, router_port->id, b);
1849648Svbart@nginx.com 
1850648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1851648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
1852648Svbart@nginx.com         goto fail;
1853648Svbart@nginx.com     }
1854198Sigor@sysoev.ru 
1855198Sigor@sysoev.ru     return;
1856198Sigor@sysoev.ru 
1857198Sigor@sysoev.ru fail:
1858198Sigor@sysoev.ru 
1859198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1860198Sigor@sysoev.ru }
1861198Sigor@sysoev.ru 
1862198Sigor@sysoev.ru 
1863198Sigor@sysoev.ru static void
1864198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1865198Sigor@sysoev.ru     void *data)
186653Sigor@sysoev.ru {
1867359Sigor@sysoev.ru     nxt_int_t         ret;
1868359Sigor@sysoev.ru     nxt_socket_t      s;
1869359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
187053Sigor@sysoev.ru 
1871198Sigor@sysoev.ru     rpc = data;
1872198Sigor@sysoev.ru 
1873198Sigor@sysoev.ru     s = msg->fd;
1874198Sigor@sysoev.ru 
1875198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
1876198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1877198Sigor@sysoev.ru         goto fail;
187853Sigor@sysoev.ru     }
187953Sigor@sysoev.ru 
1880359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
1881198Sigor@sysoev.ru 
1882198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
1883198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1884198Sigor@sysoev.ru         goto fail;
1885198Sigor@sysoev.ru     }
1886198Sigor@sysoev.ru 
1887359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
1888198Sigor@sysoev.ru 
1889198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1890198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
1891198Sigor@sysoev.ru 
1892198Sigor@sysoev.ru     return;
1893148Sigor@sysoev.ru 
1894148Sigor@sysoev.ru fail:
1895148Sigor@sysoev.ru 
1896148Sigor@sysoev.ru     nxt_socket_close(task, s);
1897148Sigor@sysoev.ru 
1898198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
1899198Sigor@sysoev.ru }
1900198Sigor@sysoev.ru 
1901198Sigor@sysoev.ru 
1902198Sigor@sysoev.ru static void
1903198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1904198Sigor@sysoev.ru     void *data)
1905198Sigor@sysoev.ru {
1906198Sigor@sysoev.ru     u_char                  *p;
1907198Sigor@sysoev.ru     size_t                  size;
1908198Sigor@sysoev.ru     uint8_t                 error;
1909198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
1910198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
1911198Sigor@sysoev.ru     nxt_socket_rpc_t        *rpc;
1912198Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
1913198Sigor@sysoev.ru 
1914198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
1915198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
1916198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
1917198Sigor@sysoev.ru         nxt_string("ListenerPort"),
1918198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
1919198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
1920198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
1921198Sigor@sysoev.ru         nxt_string("ListenerPath"),
1922198Sigor@sysoev.ru     };
1923198Sigor@sysoev.ru 
1924198Sigor@sysoev.ru     rpc = data;
1925359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
1926352Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
1927352Smax.romanov@nginx.com 
1928352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
1929352Smax.romanov@nginx.com 
1930551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
1931551Smax.romanov@nginx.com         return;
1932551Smax.romanov@nginx.com     }
1933352Smax.romanov@nginx.com 
1934198Sigor@sysoev.ru     p = in->mem.pos;
1935198Sigor@sysoev.ru 
1936198Sigor@sysoev.ru     error = *p++;
1937198Sigor@sysoev.ru 
1938703Svbart@nginx.com     size = nxt_length("listen socket error: ")
1939703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
1940198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
1941198Sigor@sysoev.ru 
1942198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1943198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
1944198Sigor@sysoev.ru         return;
1945198Sigor@sysoev.ru     }
1946198Sigor@sysoev.ru 
1947198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
1948198Sigor@sysoev.ru                         "listen socket error: "
1949198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
1950493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
1951198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
1952198Sigor@sysoev.ru 
1953198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
1954198Sigor@sysoev.ru 
1955198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
195653Sigor@sysoev.ru }
195753Sigor@sysoev.ru 
195853Sigor@sysoev.ru 
1959507Smax.romanov@nginx.com static void
1960507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
1961507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
1962507Smax.romanov@nginx.com {
1963507Smax.romanov@nginx.com     size_t         size;
1964507Smax.romanov@nginx.com     uint32_t       stream;
1965648Svbart@nginx.com     nxt_int_t      ret;
1966507Smax.romanov@nginx.com     nxt_buf_t      *b;
1967507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
1968507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1969507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
1970507Smax.romanov@nginx.com 
1971507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
1972507Smax.romanov@nginx.com     if (rpc == NULL) {
1973507Smax.romanov@nginx.com         goto fail;
1974507Smax.romanov@nginx.com     }
1975507Smax.romanov@nginx.com 
1976507Smax.romanov@nginx.com     rpc->app = app;
1977507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
1978507Smax.romanov@nginx.com 
1979507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
1980507Smax.romanov@nginx.com 
1981507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
1982507Smax.romanov@nginx.com 
1983507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
1984507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1985507Smax.romanov@nginx.com         goto fail;
1986507Smax.romanov@nginx.com     }
1987507Smax.romanov@nginx.com 
1988507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
1989507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
1990507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
1991507Smax.romanov@nginx.com 
1992507Smax.romanov@nginx.com     rt = task->thread->runtime;
1993507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1994507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1995507Smax.romanov@nginx.com 
1996507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
1997507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
1998507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
1999507Smax.romanov@nginx.com                                            -1, rpc);
2000507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2001507Smax.romanov@nginx.com         goto fail;
2002507Smax.romanov@nginx.com     }
2003507Smax.romanov@nginx.com 
2004648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2005648Svbart@nginx.com                                 stream, router_port->id, b);
2006648Svbart@nginx.com 
2007648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2008648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2009648Svbart@nginx.com         goto fail;
2010648Svbart@nginx.com     }
2011648Svbart@nginx.com 
2012507Smax.romanov@nginx.com     app->pending_processes++;
2013507Smax.romanov@nginx.com 
2014507Smax.romanov@nginx.com     return;
2015507Smax.romanov@nginx.com 
2016507Smax.romanov@nginx.com fail:
2017507Smax.romanov@nginx.com 
2018507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2019507Smax.romanov@nginx.com }
2020507Smax.romanov@nginx.com 
2021507Smax.romanov@nginx.com 
2022507Smax.romanov@nginx.com static void
2023507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2024507Smax.romanov@nginx.com     void *data)
2025507Smax.romanov@nginx.com {
2026507Smax.romanov@nginx.com     nxt_app_t           *app;
2027507Smax.romanov@nginx.com     nxt_port_t          *port;
2028507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2029507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2030507Smax.romanov@nginx.com 
2031507Smax.romanov@nginx.com     rpc = data;
2032507Smax.romanov@nginx.com     app = rpc->app;
2033507Smax.romanov@nginx.com 
2034507Smax.romanov@nginx.com     port = msg->u.new_port;
2035507Smax.romanov@nginx.com     port->app = app;
2036507Smax.romanov@nginx.com 
2037507Smax.romanov@nginx.com     app->pending_processes--;
2038507Smax.romanov@nginx.com     app->processes++;
2039507Smax.romanov@nginx.com     app->idle_processes++;
2040507Smax.romanov@nginx.com 
2041507Smax.romanov@nginx.com     engine = task->thread->engine;
2042507Smax.romanov@nginx.com 
2043507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2044507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2045507Smax.romanov@nginx.com 
2046507Smax.romanov@nginx.com     port->idle_start = 0;
2047507Smax.romanov@nginx.com 
2048507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2049507Smax.romanov@nginx.com 
2050507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2051507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2052507Smax.romanov@nginx.com }
2053507Smax.romanov@nginx.com 
2054507Smax.romanov@nginx.com 
2055507Smax.romanov@nginx.com static void
2056507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2057507Smax.romanov@nginx.com     void *data)
2058507Smax.romanov@nginx.com {
2059507Smax.romanov@nginx.com     nxt_app_t               *app;
2060507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2061507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2062507Smax.romanov@nginx.com 
2063507Smax.romanov@nginx.com     rpc = data;
2064507Smax.romanov@nginx.com     app = rpc->app;
2065507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2066507Smax.romanov@nginx.com 
2067507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2068507Smax.romanov@nginx.com             &app->name);
2069507Smax.romanov@nginx.com 
2070507Smax.romanov@nginx.com     app->pending_processes--;
2071507Smax.romanov@nginx.com 
2072507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2073507Smax.romanov@nginx.com }
2074507Smax.romanov@nginx.com 
2075507Smax.romanov@nginx.com 
207653Sigor@sysoev.ru static nxt_int_t
207753Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
207853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
207953Sigor@sysoev.ru {
208053Sigor@sysoev.ru     nxt_int_t                 ret;
208153Sigor@sysoev.ru     nxt_uint_t                n, threads;
208253Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
208353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
208453Sigor@sysoev.ru 
2085591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
208653Sigor@sysoev.ru 
208753Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
208853Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
208953Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
209053Sigor@sysoev.ru         return NXT_ERROR;
209153Sigor@sysoev.ru     }
209253Sigor@sysoev.ru 
209353Sigor@sysoev.ru     n = 0;
209453Sigor@sysoev.ru 
209553Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
209653Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
209753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
209853Sigor@sysoev.ru     {
209953Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
210053Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
210153Sigor@sysoev.ru             return NXT_ERROR;
210253Sigor@sysoev.ru         }
210353Sigor@sysoev.ru 
2104115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
210553Sigor@sysoev.ru 
210653Sigor@sysoev.ru         if (n < threads) {
2107315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2108115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
210953Sigor@sysoev.ru 
211053Sigor@sysoev.ru         } else {
2111315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2112115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
211353Sigor@sysoev.ru         }
211453Sigor@sysoev.ru 
211553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
211653Sigor@sysoev.ru             return ret;
211753Sigor@sysoev.ru         }
211853Sigor@sysoev.ru 
211953Sigor@sysoev.ru         n++;
212053Sigor@sysoev.ru     }
212153Sigor@sysoev.ru 
212253Sigor@sysoev.ru     tmcf->new_threads = n;
212353Sigor@sysoev.ru 
212453Sigor@sysoev.ru     while (n < threads) {
212553Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
212653Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
212753Sigor@sysoev.ru             return NXT_ERROR;
212853Sigor@sysoev.ru         }
212953Sigor@sysoev.ru 
2130315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2131315Sigor@sysoev.ru 
213253Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
213353Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
213453Sigor@sysoev.ru             return NXT_ERROR;
213553Sigor@sysoev.ru         }
213653Sigor@sysoev.ru 
2137115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
213853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
213953Sigor@sysoev.ru             return ret;
214053Sigor@sysoev.ru         }
214153Sigor@sysoev.ru 
214253Sigor@sysoev.ru         n++;
214353Sigor@sysoev.ru     }
214453Sigor@sysoev.ru 
214553Sigor@sysoev.ru     return NXT_OK;
214653Sigor@sysoev.ru }
214753Sigor@sysoev.ru 
214853Sigor@sysoev.ru 
214953Sigor@sysoev.ru static nxt_int_t
2150115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2151115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
215253Sigor@sysoev.ru {
2153359Sigor@sysoev.ru     nxt_int_t  ret;
215453Sigor@sysoev.ru 
2155154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2156154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2157115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2158115Sigor@sysoev.ru         return ret;
2159115Sigor@sysoev.ru     }
2160115Sigor@sysoev.ru 
2161154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2162154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
216353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
216453Sigor@sysoev.ru         return ret;
216553Sigor@sysoev.ru     }
216653Sigor@sysoev.ru 
2167115Sigor@sysoev.ru     return ret;
216853Sigor@sysoev.ru }
216953Sigor@sysoev.ru 
217053Sigor@sysoev.ru 
217153Sigor@sysoev.ru static nxt_int_t
2172115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2173115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
217453Sigor@sysoev.ru {
2175359Sigor@sysoev.ru     nxt_int_t  ret;
217653Sigor@sysoev.ru 
2177154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2178154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
217953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
218053Sigor@sysoev.ru         return ret;
218153Sigor@sysoev.ru     }
218253Sigor@sysoev.ru 
2183154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2184154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
218553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
218653Sigor@sysoev.ru         return ret;
218753Sigor@sysoev.ru     }
218853Sigor@sysoev.ru 
2189139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
2190115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2191115Sigor@sysoev.ru         return ret;
2192115Sigor@sysoev.ru     }
2193115Sigor@sysoev.ru 
2194115Sigor@sysoev.ru     return ret;
219553Sigor@sysoev.ru }
219653Sigor@sysoev.ru 
219753Sigor@sysoev.ru 
219853Sigor@sysoev.ru static nxt_int_t
2199115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2200115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
220153Sigor@sysoev.ru {
220253Sigor@sysoev.ru     nxt_int_t  ret;
220353Sigor@sysoev.ru 
2204313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2205313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2206313Sigor@sysoev.ru         return ret;
2207313Sigor@sysoev.ru     }
2208313Sigor@sysoev.ru 
2209139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
221053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
221153Sigor@sysoev.ru         return ret;
221253Sigor@sysoev.ru     }
221353Sigor@sysoev.ru 
2214139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
221553Sigor@sysoev.ru }
221653Sigor@sysoev.ru 
221753Sigor@sysoev.ru 
221853Sigor@sysoev.ru static nxt_int_t
2219154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2220154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
222153Sigor@sysoev.ru     nxt_work_handler_t handler)
222253Sigor@sysoev.ru {
2223153Sigor@sysoev.ru     nxt_joint_job_t          *job;
222453Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2225155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
222653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
222753Sigor@sysoev.ru 
222853Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
222953Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
223053Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
223153Sigor@sysoev.ru     {
2232154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2233153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2234139Sigor@sysoev.ru             return NXT_ERROR;
2235139Sigor@sysoev.ru         }
2236139Sigor@sysoev.ru 
2237154Sigor@sysoev.ru         job->work.next = recf->jobs;
2238154Sigor@sysoev.ru         recf->jobs = &job->work;
2239154Sigor@sysoev.ru 
2240153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2241153Sigor@sysoev.ru         job->work.handler = handler;
2242153Sigor@sysoev.ru         job->work.task = &job->task;
2243153Sigor@sysoev.ru         job->work.obj = job;
2244153Sigor@sysoev.ru         job->tmcf = tmcf;
224553Sigor@sysoev.ru 
2246154Sigor@sysoev.ru         tmcf->count++;
2247154Sigor@sysoev.ru 
2248591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2249154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
225053Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
225153Sigor@sysoev.ru             return NXT_ERROR;
225253Sigor@sysoev.ru         }
225353Sigor@sysoev.ru 
2254153Sigor@sysoev.ru         job->work.data = joint;
225553Sigor@sysoev.ru 
225653Sigor@sysoev.ru         joint->count = 1;
2257155Sigor@sysoev.ru 
2258155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2259155Sigor@sysoev.ru         skcf->count++;
2260155Sigor@sysoev.ru         joint->socket_conf = skcf;
2261155Sigor@sysoev.ru 
226288Smax.romanov@nginx.com         joint->engine = recf->engine;
226353Sigor@sysoev.ru     }
226453Sigor@sysoev.ru 
226520Sigor@sysoev.ru     return NXT_OK;
226620Sigor@sysoev.ru }
226720Sigor@sysoev.ru 
226820Sigor@sysoev.ru 
226920Sigor@sysoev.ru static nxt_int_t
2270313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2271313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2272313Sigor@sysoev.ru {
2273313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2274313Sigor@sysoev.ru 
2275313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2276313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2277313Sigor@sysoev.ru         return NXT_ERROR;
2278313Sigor@sysoev.ru     }
2279313Sigor@sysoev.ru 
2280313Sigor@sysoev.ru     job->work.next = recf->jobs;
2281313Sigor@sysoev.ru     recf->jobs = &job->work;
2282313Sigor@sysoev.ru 
2283313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2284313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2285313Sigor@sysoev.ru     job->work.task = &job->task;
2286313Sigor@sysoev.ru     job->work.obj = NULL;
2287313Sigor@sysoev.ru     job->work.data = NULL;
2288313Sigor@sysoev.ru     job->tmcf = NULL;
2289313Sigor@sysoev.ru 
2290313Sigor@sysoev.ru     return NXT_OK;
2291313Sigor@sysoev.ru }
2292313Sigor@sysoev.ru 
2293313Sigor@sysoev.ru 
2294313Sigor@sysoev.ru static nxt_int_t
2295139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2296139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
229720Sigor@sysoev.ru {
2298153Sigor@sysoev.ru     nxt_joint_job_t   *job;
229953Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
230020Sigor@sysoev.ru 
230153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
230253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
230353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
230453Sigor@sysoev.ru     {
2305154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2306153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2307139Sigor@sysoev.ru             return NXT_ERROR;
2308139Sigor@sysoev.ru         }
2309139Sigor@sysoev.ru 
2310154Sigor@sysoev.ru         job->work.next = recf->jobs;
2311154Sigor@sysoev.ru         recf->jobs = &job->work;
2312154Sigor@sysoev.ru 
2313153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2314153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2315153Sigor@sysoev.ru         job->work.task = &job->task;
2316153Sigor@sysoev.ru         job->work.obj = job;
2317153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2318153Sigor@sysoev.ru         job->tmcf = tmcf;
2319154Sigor@sysoev.ru 
2320154Sigor@sysoev.ru         tmcf->count++;
232120Sigor@sysoev.ru     }
232220Sigor@sysoev.ru 
232353Sigor@sysoev.ru     return NXT_OK;
232453Sigor@sysoev.ru }
232520Sigor@sysoev.ru 
232620Sigor@sysoev.ru 
232753Sigor@sysoev.ru static nxt_int_t
232853Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
232953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
233053Sigor@sysoev.ru {
233153Sigor@sysoev.ru     nxt_int_t                 ret;
233253Sigor@sysoev.ru     nxt_uint_t                i, threads;
233353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
233420Sigor@sysoev.ru 
233553Sigor@sysoev.ru     recf = tmcf->engines->elts;
2336591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
233720Sigor@sysoev.ru 
233853Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
233953Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
234053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
234153Sigor@sysoev.ru             return ret;
234253Sigor@sysoev.ru         }
234320Sigor@sysoev.ru     }
234420Sigor@sysoev.ru 
234520Sigor@sysoev.ru     return NXT_OK;
234620Sigor@sysoev.ru }
234753Sigor@sysoev.ru 
234853Sigor@sysoev.ru 
234953Sigor@sysoev.ru static nxt_int_t
235053Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
235153Sigor@sysoev.ru     nxt_event_engine_t *engine)
235253Sigor@sysoev.ru {
235353Sigor@sysoev.ru     nxt_int_t            ret;
235453Sigor@sysoev.ru     nxt_thread_link_t    *link;
235553Sigor@sysoev.ru     nxt_thread_handle_t  handle;
235653Sigor@sysoev.ru 
235753Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
235853Sigor@sysoev.ru 
235953Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
236053Sigor@sysoev.ru         return NXT_ERROR;
236153Sigor@sysoev.ru     }
236253Sigor@sysoev.ru 
236353Sigor@sysoev.ru     link->start = nxt_router_thread_start;
236453Sigor@sysoev.ru     link->engine = engine;
236553Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
236653Sigor@sysoev.ru     link->work.task = task;
236753Sigor@sysoev.ru     link->work.data = link;
236853Sigor@sysoev.ru 
236953Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
237053Sigor@sysoev.ru 
237153Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
237253Sigor@sysoev.ru 
237353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
237453Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
237553Sigor@sysoev.ru     }
237653Sigor@sysoev.ru 
237753Sigor@sysoev.ru     return ret;
237853Sigor@sysoev.ru }
237953Sigor@sysoev.ru 
238053Sigor@sysoev.ru 
238153Sigor@sysoev.ru static void
2382343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2383343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2384133Sigor@sysoev.ru {
2385507Smax.romanov@nginx.com     nxt_app_t  *app;
2386141Smax.romanov@nginx.com 
2387141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2388133Sigor@sysoev.ru 
2389753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2390343Smax.romanov@nginx.com 
2391141Smax.romanov@nginx.com     } nxt_queue_loop;
2392133Sigor@sysoev.ru 
2393133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2394133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2395133Sigor@sysoev.ru }
2396133Sigor@sysoev.ru 
2397133Sigor@sysoev.ru 
2398133Sigor@sysoev.ru static void
2399315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
240053Sigor@sysoev.ru {
240153Sigor@sysoev.ru     nxt_uint_t                n;
2402315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
240353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
240453Sigor@sysoev.ru 
240553Sigor@sysoev.ru     recf = tmcf->engines->elts;
240653Sigor@sysoev.ru 
240753Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2408315Sigor@sysoev.ru         engine = recf->engine;
2409315Sigor@sysoev.ru 
2410315Sigor@sysoev.ru         switch (recf->action) {
2411315Sigor@sysoev.ru 
2412315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2413315Sigor@sysoev.ru             break;
2414315Sigor@sysoev.ru 
2415315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2416315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2417315Sigor@sysoev.ru             break;
2418315Sigor@sysoev.ru 
2419315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2420315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2421315Sigor@sysoev.ru             break;
2422315Sigor@sysoev.ru         }
2423315Sigor@sysoev.ru 
2424316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2425316Sigor@sysoev.ru 
242653Sigor@sysoev.ru         recf++;
242753Sigor@sysoev.ru     }
242853Sigor@sysoev.ru }
242953Sigor@sysoev.ru 
243053Sigor@sysoev.ru 
243153Sigor@sysoev.ru static void
2432315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
243353Sigor@sysoev.ru {
2434154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2435154Sigor@sysoev.ru 
2436315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2437154Sigor@sysoev.ru         next = work->next;
2438154Sigor@sysoev.ru         work->next = NULL;
2439154Sigor@sysoev.ru 
2440315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
244153Sigor@sysoev.ru     }
244253Sigor@sysoev.ru }
244353Sigor@sysoev.ru 
244453Sigor@sysoev.ru 
2445320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2446616Smax.romanov@nginx.com     .rpc_error = nxt_port_rpc_handler,
2447616Smax.romanov@nginx.com     .mmap      = nxt_port_mmap_handler,
2448616Smax.romanov@nginx.com     .data      = nxt_port_rpc_handler,
244988Smax.romanov@nginx.com };
245088Smax.romanov@nginx.com 
245188Smax.romanov@nginx.com 
245288Smax.romanov@nginx.com static void
245353Sigor@sysoev.ru nxt_router_thread_start(void *data)
245453Sigor@sysoev.ru {
2455141Smax.romanov@nginx.com     nxt_int_t           ret;
2456141Smax.romanov@nginx.com     nxt_port_t          *port;
245788Smax.romanov@nginx.com     nxt_task_t          *task;
245853Sigor@sysoev.ru     nxt_thread_t        *thread;
245953Sigor@sysoev.ru     nxt_thread_link_t   *link;
246053Sigor@sysoev.ru     nxt_event_engine_t  *engine;
246153Sigor@sysoev.ru 
246253Sigor@sysoev.ru     link = data;
246353Sigor@sysoev.ru     engine = link->engine;
246488Smax.romanov@nginx.com     task = &engine->task;
246553Sigor@sysoev.ru 
246653Sigor@sysoev.ru     thread = nxt_thread();
246753Sigor@sysoev.ru 
2468165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2469165Smax.romanov@nginx.com 
247053Sigor@sysoev.ru     /* STUB */
247153Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
247253Sigor@sysoev.ru 
247353Sigor@sysoev.ru     engine->task.thread = thread;
247453Sigor@sysoev.ru     engine->task.log = thread->log;
247553Sigor@sysoev.ru     thread->engine = engine;
247663Sigor@sysoev.ru     thread->task = &engine->task;
2477326Svbart@nginx.com #if 0
247853Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2479326Svbart@nginx.com #endif
248053Sigor@sysoev.ru 
248163Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2482337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2483337Sigor@sysoev.ru         return;
2484337Sigor@sysoev.ru     }
248553Sigor@sysoev.ru 
2486197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2487197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2488141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2489141Smax.romanov@nginx.com         return;
2490141Smax.romanov@nginx.com     }
2491141Smax.romanov@nginx.com 
2492141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2493141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2494343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2495141Smax.romanov@nginx.com         return;
2496141Smax.romanov@nginx.com     }
2497141Smax.romanov@nginx.com 
2498141Smax.romanov@nginx.com     engine->port = port;
2499141Smax.romanov@nginx.com 
2500320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2501141Smax.romanov@nginx.com 
250253Sigor@sysoev.ru     nxt_event_engine_start(engine);
250353Sigor@sysoev.ru }
250453Sigor@sysoev.ru 
250553Sigor@sysoev.ru 
250653Sigor@sysoev.ru static void
250753Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
250853Sigor@sysoev.ru {
2509153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2510359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2511359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
251253Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2513359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
251453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
251553Sigor@sysoev.ru 
2516153Sigor@sysoev.ru     job = obj;
251753Sigor@sysoev.ru     joint = data;
251853Sigor@sysoev.ru 
2519159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2520159Sigor@sysoev.ru 
2521359Sigor@sysoev.ru     skcf = joint->socket_conf;
2522359Sigor@sysoev.ru     ls = skcf->listen;
2523359Sigor@sysoev.ru 
2524359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2525359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2526359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
252753Sigor@sysoev.ru         return;
252853Sigor@sysoev.ru     }
252953Sigor@sysoev.ru 
2530359Sigor@sysoev.ru     lev->socket.data = joint;
2531359Sigor@sysoev.ru 
2532359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2533359Sigor@sysoev.ru 
2534359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2535359Sigor@sysoev.ru     ls->count++;
2536359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2537139Sigor@sysoev.ru 
2538153Sigor@sysoev.ru     job->work.next = NULL;
2539153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2540153Sigor@sysoev.ru 
2541153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
254253Sigor@sysoev.ru }
254353Sigor@sysoev.ru 
254453Sigor@sysoev.ru 
254553Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
254653Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
254753Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
254853Sigor@sysoev.ru {
2549115Sigor@sysoev.ru     nxt_socket_t        fd;
2550115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2551359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2552359Sigor@sysoev.ru 
2553359Sigor@sysoev.ru     fd = skcf->listen->socket;
255453Sigor@sysoev.ru 
2555115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2556115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2557115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
255853Sigor@sysoev.ru     {
2559359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2560359Sigor@sysoev.ru 
2561359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2562359Sigor@sysoev.ru             return lev;
256353Sigor@sysoev.ru         }
256453Sigor@sysoev.ru     }
256553Sigor@sysoev.ru 
256653Sigor@sysoev.ru     return NULL;
256753Sigor@sysoev.ru }
256853Sigor@sysoev.ru 
256953Sigor@sysoev.ru 
257053Sigor@sysoev.ru static void
257153Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
257253Sigor@sysoev.ru {
2573153Sigor@sysoev.ru     nxt_joint_job_t          *job;
257453Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2575359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
257653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
257753Sigor@sysoev.ru 
2578153Sigor@sysoev.ru     job = obj;
257953Sigor@sysoev.ru     joint = data;
258053Sigor@sysoev.ru 
2581139Sigor@sysoev.ru     engine = task->thread->engine;
2582139Sigor@sysoev.ru 
2583159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2584159Sigor@sysoev.ru 
2585359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2586359Sigor@sysoev.ru                                   joint->socket_conf);
2587359Sigor@sysoev.ru 
2588359Sigor@sysoev.ru     old = lev->socket.data;
2589359Sigor@sysoev.ru     lev->socket.data = joint;
2590359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
259153Sigor@sysoev.ru 
2592153Sigor@sysoev.ru     job->work.next = NULL;
2593153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2594153Sigor@sysoev.ru 
2595153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2596139Sigor@sysoev.ru 
2597181Smax.romanov@nginx.com     /*
2598181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2599181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2600181Smax.romanov@nginx.com      */
2601181Smax.romanov@nginx.com 
2602181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
260353Sigor@sysoev.ru }
260453Sigor@sysoev.ru 
260553Sigor@sysoev.ru 
260653Sigor@sysoev.ru static void
260753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
260853Sigor@sysoev.ru {
2609153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2610153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2611359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2612153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2613153Sigor@sysoev.ru 
2614153Sigor@sysoev.ru     job = obj;
261553Sigor@sysoev.ru     skcf = data;
261653Sigor@sysoev.ru 
2617139Sigor@sysoev.ru     engine = task->thread->engine;
2618139Sigor@sysoev.ru 
2619359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2620359Sigor@sysoev.ru 
2621359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
262253Sigor@sysoev.ru 
2623163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2624359Sigor@sysoev.ru               lev->socket.fd);
2625359Sigor@sysoev.ru 
2626359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2627359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2628359Sigor@sysoev.ru 
2629359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2630139Sigor@sysoev.ru 
2631153Sigor@sysoev.ru     job->work.next = NULL;
2632153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2633153Sigor@sysoev.ru 
2634153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
263553Sigor@sysoev.ru }
263653Sigor@sysoev.ru 
263753Sigor@sysoev.ru 
263853Sigor@sysoev.ru static void
2639313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2640313Sigor@sysoev.ru {
2641313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2642313Sigor@sysoev.ru 
2643313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2644313Sigor@sysoev.ru 
2645313Sigor@sysoev.ru     engine = task->thread->engine;
2646313Sigor@sysoev.ru 
2647313Sigor@sysoev.ru     engine->shutdown = 1;
2648313Sigor@sysoev.ru 
2649313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2650313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2651313Sigor@sysoev.ru     }
2652313Sigor@sysoev.ru }
2653313Sigor@sysoev.ru 
2654313Sigor@sysoev.ru 
2655313Sigor@sysoev.ru static void
265653Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
265753Sigor@sysoev.ru {
265853Sigor@sysoev.ru     nxt_timer_t              *timer;
2659359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
266053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
266153Sigor@sysoev.ru 
266253Sigor@sysoev.ru     timer = obj;
2663359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
266453Sigor@sysoev.ru 
2665163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2666359Sigor@sysoev.ru               lev->socket.fd);
2667359Sigor@sysoev.ru 
2668359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2669359Sigor@sysoev.ru 
2670683Sigor@sysoev.ru     joint = lev->socket.data;
2671683Sigor@sysoev.ru     lev->socket.data = NULL;
2672683Sigor@sysoev.ru 
2673359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2674123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2675123Smax.romanov@nginx.com 
2676359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2677359Sigor@sysoev.ru 
2678683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
267953Sigor@sysoev.ru }
268053Sigor@sysoev.ru 
268153Sigor@sysoev.ru 
268253Sigor@sysoev.ru static void
2683359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
268453Sigor@sysoev.ru {
2685359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
268653Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
268753Sigor@sysoev.ru 
2688359Sigor@sysoev.ru     ls = skcf->listen;
2689118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
269053Sigor@sysoev.ru 
269153Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
269253Sigor@sysoev.ru 
2693359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2694359Sigor@sysoev.ru               task->thread->engine, ls->count);
2695359Sigor@sysoev.ru 
2696359Sigor@sysoev.ru     if (--ls->count != 0) {
2697359Sigor@sysoev.ru         ls = NULL;
269853Sigor@sysoev.ru     }
269953Sigor@sysoev.ru 
270053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
270153Sigor@sysoev.ru 
2702359Sigor@sysoev.ru     if (ls != NULL) {
2703359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
2704359Sigor@sysoev.ru         nxt_free(ls);
270553Sigor@sysoev.ru     }
270653Sigor@sysoev.ru }
270753Sigor@sysoev.ru 
270853Sigor@sysoev.ru 
2709683Sigor@sysoev.ru void
2710683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
2711683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
2712683Sigor@sysoev.ru {
2713683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2714683Sigor@sysoev.ru 
2715683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
2716683Sigor@sysoev.ru 
2717683Sigor@sysoev.ru     if (--lev->count == 0) {
2718683Sigor@sysoev.ru         nxt_free(lev);
2719683Sigor@sysoev.ru     }
2720683Sigor@sysoev.ru 
2721683Sigor@sysoev.ru     if (joint != NULL) {
2722683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
2723683Sigor@sysoev.ru     }
2724683Sigor@sysoev.ru 
2725683Sigor@sysoev.ru     engine = task->thread->engine;
2726683Sigor@sysoev.ru 
2727683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
2728683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2729683Sigor@sysoev.ru     }
2730683Sigor@sysoev.ru }
2731683Sigor@sysoev.ru 
2732683Sigor@sysoev.ru 
2733683Sigor@sysoev.ru void
273453Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
273553Sigor@sysoev.ru {
2736567Smax.romanov@nginx.com     nxt_app_t              *app;
273753Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
273853Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
273953Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
274053Sigor@sysoev.ru 
2741163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
274253Sigor@sysoev.ru 
274353Sigor@sysoev.ru     if (--joint->count != 0) {
274453Sigor@sysoev.ru         return;
274553Sigor@sysoev.ru     }
274653Sigor@sysoev.ru 
274753Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
274853Sigor@sysoev.ru 
2749530Sigor@sysoev.ru     /*
2750530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
2751530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
2752530Sigor@sysoev.ru      * be already destroyed by another thread.
2753530Sigor@sysoev.ru      */
275453Sigor@sysoev.ru     skcf = joint->socket_conf;
2755567Smax.romanov@nginx.com     app = skcf->application;
275653Sigor@sysoev.ru     rtcf = skcf->router_conf;
275753Sigor@sysoev.ru     lock = &rtcf->router->lock;
275853Sigor@sysoev.ru 
275953Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
276053Sigor@sysoev.ru 
2761163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
2762163Smax.romanov@nginx.com               rtcf, rtcf->count);
2763163Smax.romanov@nginx.com 
276453Sigor@sysoev.ru     if (--skcf->count != 0) {
276553Sigor@sysoev.ru         rtcf = NULL;
2766567Smax.romanov@nginx.com         app = NULL;
276753Sigor@sysoev.ru 
276853Sigor@sysoev.ru     } else {
276953Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
277053Sigor@sysoev.ru 
277153Sigor@sysoev.ru         if (--rtcf->count != 0) {
277253Sigor@sysoev.ru             rtcf = NULL;
277353Sigor@sysoev.ru         }
277453Sigor@sysoev.ru     }
277553Sigor@sysoev.ru 
277653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
277753Sigor@sysoev.ru 
2778567Smax.romanov@nginx.com     if (app != NULL) {
2779567Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
2780567Smax.romanov@nginx.com     }
2781567Smax.romanov@nginx.com 
2782141Smax.romanov@nginx.com     /* TODO remove engine->port */
2783141Smax.romanov@nginx.com     /* TODO excude from connected ports */
2784141Smax.romanov@nginx.com 
278553Sigor@sysoev.ru     if (rtcf != NULL) {
2786115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
2787131Smax.romanov@nginx.com 
2788*771Sigor@sysoev.ru #if (NXT_TLS)
2789*771Sigor@sysoev.ru         if (skcf->tls != NULL) {
2790*771Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
2791*771Sigor@sysoev.ru         }
2792*771Sigor@sysoev.ru #endif
2793*771Sigor@sysoev.ru 
2794630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
2795630Svbart@nginx.com 
2796131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
2797131Smax.romanov@nginx.com 
279865Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
279953Sigor@sysoev.ru     }
280053Sigor@sysoev.ru }
280153Sigor@sysoev.ru 
280253Sigor@sysoev.ru 
280353Sigor@sysoev.ru static void
2804630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
2805630Svbart@nginx.com     nxt_router_access_log_t *access_log)
2806630Svbart@nginx.com {
2807630Svbart@nginx.com     size_t     size;
2808630Svbart@nginx.com     u_char     *buf, *p;
2809630Svbart@nginx.com     nxt_off_t  bytes;
2810630Svbart@nginx.com 
2811630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
2812630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
2813630Svbart@nginx.com         nxt_router_access_log_date,
2814630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
2815703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
2816630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
2817630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
2818630Svbart@nginx.com     };
2819630Svbart@nginx.com 
2820630Svbart@nginx.com     size = r->remote->address_length
2821630Svbart@nginx.com            + 6                  /* ' - - [' */
2822630Svbart@nginx.com            + date_cache.size
2823630Svbart@nginx.com            + 3                  /* '] "' */
2824630Svbart@nginx.com            + r->method->length
2825630Svbart@nginx.com            + 1                  /* space */
2826630Svbart@nginx.com            + r->target.length
2827630Svbart@nginx.com            + 1                  /* space */
2828630Svbart@nginx.com            + r->version.length
2829630Svbart@nginx.com            + 2                  /* '" ' */
2830630Svbart@nginx.com            + 3                  /* status */
2831630Svbart@nginx.com            + 1                  /* space */
2832630Svbart@nginx.com            + NXT_OFF_T_LEN
2833630Svbart@nginx.com            + 2                  /* ' "' */
2834630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
2835630Svbart@nginx.com            + 3                  /* '" "' */
2836630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
2837630Svbart@nginx.com            + 2                  /* '"\n' */
2838630Svbart@nginx.com     ;
2839630Svbart@nginx.com 
2840630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
2841630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
2842630Svbart@nginx.com         return;
2843630Svbart@nginx.com     }
2844630Svbart@nginx.com 
2845630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
2846630Svbart@nginx.com                    r->remote->address_length);
2847630Svbart@nginx.com 
2848630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
2849630Svbart@nginx.com 
2850630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
2851630Svbart@nginx.com 
2852630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
2853630Svbart@nginx.com 
2854630Svbart@nginx.com     if (r->method->length != 0) {
2855630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
2856630Svbart@nginx.com 
2857630Svbart@nginx.com         if (r->target.length != 0) {
2858630Svbart@nginx.com             *p++ = ' ';
2859630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
2860630Svbart@nginx.com 
2861630Svbart@nginx.com             if (r->version.length != 0) {
2862630Svbart@nginx.com                 *p++ = ' ';
2863630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
2864630Svbart@nginx.com             }
2865630Svbart@nginx.com         }
2866630Svbart@nginx.com 
2867630Svbart@nginx.com     } else {
2868630Svbart@nginx.com         *p++ = '-';
2869630Svbart@nginx.com     }
2870630Svbart@nginx.com 
2871630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
2872630Svbart@nginx.com 
2873630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
2874630Svbart@nginx.com 
2875630Svbart@nginx.com     *p++ = ' ';
2876630Svbart@nginx.com 
2877630Svbart@nginx.com     bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto);
2878630Svbart@nginx.com 
2879630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
2880630Svbart@nginx.com 
2881630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
2882630Svbart@nginx.com 
2883630Svbart@nginx.com     if (r->referer != NULL) {
2884630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
2885630Svbart@nginx.com 
2886630Svbart@nginx.com     } else {
2887630Svbart@nginx.com         *p++ = '-';
2888630Svbart@nginx.com     }
2889630Svbart@nginx.com 
2890630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
2891630Svbart@nginx.com 
2892630Svbart@nginx.com     if (r->user_agent != NULL) {
2893630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
2894630Svbart@nginx.com 
2895630Svbart@nginx.com     } else {
2896630Svbart@nginx.com         *p++ = '-';
2897630Svbart@nginx.com     }
2898630Svbart@nginx.com 
2899630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
2900630Svbart@nginx.com 
2901630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
2902630Svbart@nginx.com }
2903630Svbart@nginx.com 
2904630Svbart@nginx.com 
2905630Svbart@nginx.com static u_char *
2906630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
2907630Svbart@nginx.com     size_t size, const char *format)
2908630Svbart@nginx.com {
2909630Svbart@nginx.com     u_char  sign;
2910630Svbart@nginx.com     time_t  gmtoff;
2911630Svbart@nginx.com 
2912630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2913630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2914630Svbart@nginx.com 
2915630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
2916630Svbart@nginx.com 
2917630Svbart@nginx.com     if (gmtoff < 0) {
2918630Svbart@nginx.com         gmtoff = -gmtoff;
2919630Svbart@nginx.com         sign = '-';
2920630Svbart@nginx.com 
2921630Svbart@nginx.com     } else {
2922630Svbart@nginx.com         sign = '+';
2923630Svbart@nginx.com     }
2924630Svbart@nginx.com 
2925630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
2926630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
2927630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
2928630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
2929630Svbart@nginx.com }
2930630Svbart@nginx.com 
2931630Svbart@nginx.com 
2932630Svbart@nginx.com static void
2933630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
2934630Svbart@nginx.com {
2935630Svbart@nginx.com     uint32_t                 stream;
2936648Svbart@nginx.com     nxt_int_t                ret;
2937630Svbart@nginx.com     nxt_buf_t                *b;
2938630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
2939630Svbart@nginx.com     nxt_runtime_t            *rt;
2940630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
2941630Svbart@nginx.com 
2942630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
2943630Svbart@nginx.com 
2944630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
2945630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
2946630Svbart@nginx.com         goto fail;
2947630Svbart@nginx.com     }
2948630Svbart@nginx.com 
2949630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
2950630Svbart@nginx.com     *b->mem.free++ = '\0';
2951630Svbart@nginx.com 
2952630Svbart@nginx.com     rt = task->thread->runtime;
2953630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2954630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2955630Svbart@nginx.com 
2956630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2957630Svbart@nginx.com                                            nxt_router_access_log_ready,
2958630Svbart@nginx.com                                            nxt_router_access_log_error,
2959630Svbart@nginx.com                                            -1, tmcf);
2960630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
2961630Svbart@nginx.com         goto fail;
2962630Svbart@nginx.com     }
2963630Svbart@nginx.com 
2964648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
2965648Svbart@nginx.com                                 stream, router_port->id, b);
2966648Svbart@nginx.com 
2967648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2968648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2969648Svbart@nginx.com         goto fail;
2970648Svbart@nginx.com     }
2971630Svbart@nginx.com 
2972630Svbart@nginx.com     return;
2973630Svbart@nginx.com 
2974630Svbart@nginx.com fail:
2975630Svbart@nginx.com 
2976630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2977630Svbart@nginx.com }
2978630Svbart@nginx.com 
2979630Svbart@nginx.com 
2980630Svbart@nginx.com static void
2981630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2982630Svbart@nginx.com     void *data)
2983630Svbart@nginx.com {
2984630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
2985630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
2986630Svbart@nginx.com 
2987630Svbart@nginx.com     tmcf = data;
2988630Svbart@nginx.com 
2989630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
2990630Svbart@nginx.com 
2991630Svbart@nginx.com     access_log->fd = msg->fd;
2992630Svbart@nginx.com 
2993630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2994630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2995630Svbart@nginx.com }
2996630Svbart@nginx.com 
2997630Svbart@nginx.com 
2998630Svbart@nginx.com static void
2999630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3000630Svbart@nginx.com     void *data)
3001630Svbart@nginx.com {
3002630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3003630Svbart@nginx.com 
3004630Svbart@nginx.com     tmcf = data;
3005630Svbart@nginx.com 
3006630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3007630Svbart@nginx.com }
3008630Svbart@nginx.com 
3009630Svbart@nginx.com 
3010630Svbart@nginx.com static void
3011630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3012630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3013630Svbart@nginx.com {
3014630Svbart@nginx.com     if (access_log == NULL) {
3015630Svbart@nginx.com         return;
3016630Svbart@nginx.com     }
3017630Svbart@nginx.com 
3018630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3019630Svbart@nginx.com 
3020630Svbart@nginx.com     if (--access_log->count != 0) {
3021630Svbart@nginx.com         access_log = NULL;
3022630Svbart@nginx.com     }
3023630Svbart@nginx.com 
3024630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3025630Svbart@nginx.com 
3026630Svbart@nginx.com     if (access_log != NULL) {
3027630Svbart@nginx.com 
3028630Svbart@nginx.com         if (access_log->fd != -1) {
3029630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3030630Svbart@nginx.com         }
3031630Svbart@nginx.com 
3032630Svbart@nginx.com         nxt_free(access_log);
3033630Svbart@nginx.com     }
3034630Svbart@nginx.com }
3035630Svbart@nginx.com 
3036630Svbart@nginx.com 
3037631Svbart@nginx.com typedef struct {
3038631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3039631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3040631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3041631Svbart@nginx.com 
3042631Svbart@nginx.com 
3043631Svbart@nginx.com void
3044631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3045631Svbart@nginx.com {
3046631Svbart@nginx.com     nxt_mp_t                        *mp;
3047631Svbart@nginx.com     uint32_t                        stream;
3048631Svbart@nginx.com     nxt_int_t                       ret;
3049631Svbart@nginx.com     nxt_buf_t                       *b;
3050631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3051631Svbart@nginx.com     nxt_runtime_t                   *rt;
3052631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3053631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3054631Svbart@nginx.com 
3055631Svbart@nginx.com     access_log = nxt_router->access_log;
3056631Svbart@nginx.com 
3057631Svbart@nginx.com     if (access_log == NULL) {
3058631Svbart@nginx.com         return;
3059631Svbart@nginx.com     }
3060631Svbart@nginx.com 
3061631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3062631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3063631Svbart@nginx.com         return;
3064631Svbart@nginx.com     }
3065631Svbart@nginx.com 
3066631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3067631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3068631Svbart@nginx.com         goto fail;
3069631Svbart@nginx.com     }
3070631Svbart@nginx.com 
3071631Svbart@nginx.com     reopen->mem_pool = mp;
3072631Svbart@nginx.com     reopen->access_log = access_log;
3073631Svbart@nginx.com 
3074631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3075631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3076631Svbart@nginx.com         goto fail;
3077631Svbart@nginx.com     }
3078631Svbart@nginx.com 
3079651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3080651Svbart@nginx.com 
3081631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3082631Svbart@nginx.com     *b->mem.free++ = '\0';
3083631Svbart@nginx.com 
3084631Svbart@nginx.com     rt = task->thread->runtime;
3085631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3086631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3087631Svbart@nginx.com 
3088631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3089631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3090631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3091631Svbart@nginx.com                                            -1, reopen);
3092631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3093631Svbart@nginx.com         goto fail;
3094631Svbart@nginx.com     }
3095631Svbart@nginx.com 
3096631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3097631Svbart@nginx.com                                 stream, router_port->id, b);
3098631Svbart@nginx.com 
3099631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3100631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3101631Svbart@nginx.com         goto fail;
3102631Svbart@nginx.com     }
3103631Svbart@nginx.com 
3104651Svbart@nginx.com     nxt_mp_retain(mp);
3105651Svbart@nginx.com 
3106631Svbart@nginx.com     return;
3107631Svbart@nginx.com 
3108631Svbart@nginx.com fail:
3109631Svbart@nginx.com 
3110631Svbart@nginx.com     nxt_mp_destroy(mp);
3111631Svbart@nginx.com }
3112631Svbart@nginx.com 
3113631Svbart@nginx.com 
3114631Svbart@nginx.com static void
3115651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3116651Svbart@nginx.com {
3117651Svbart@nginx.com     nxt_mp_t   *mp;
3118651Svbart@nginx.com     nxt_buf_t  *b;
3119651Svbart@nginx.com 
3120651Svbart@nginx.com     b = obj;
3121651Svbart@nginx.com     mp = b->data;
3122651Svbart@nginx.com 
3123651Svbart@nginx.com     nxt_mp_release(mp);
3124651Svbart@nginx.com }
3125651Svbart@nginx.com 
3126651Svbart@nginx.com 
3127651Svbart@nginx.com static void
3128631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3129631Svbart@nginx.com     void *data)
3130631Svbart@nginx.com {
3131631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3132631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3133631Svbart@nginx.com 
3134631Svbart@nginx.com     reopen = data;
3135631Svbart@nginx.com 
3136631Svbart@nginx.com     access_log = reopen->access_log;
3137631Svbart@nginx.com 
3138631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3139631Svbart@nginx.com 
3140631Svbart@nginx.com         if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) {
3141631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3142631Svbart@nginx.com                       msg->fd, access_log->fd, nxt_errno);
3143631Svbart@nginx.com         }
3144631Svbart@nginx.com     }
3145631Svbart@nginx.com 
3146631Svbart@nginx.com     nxt_fd_close(msg->fd);
3147651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3148631Svbart@nginx.com }
3149631Svbart@nginx.com 
3150631Svbart@nginx.com 
3151631Svbart@nginx.com static void
3152631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3153631Svbart@nginx.com     void *data)
3154631Svbart@nginx.com {
3155631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3156631Svbart@nginx.com 
3157631Svbart@nginx.com     reopen = data;
3158631Svbart@nginx.com 
3159651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3160631Svbart@nginx.com }
3161631Svbart@nginx.com 
3162631Svbart@nginx.com 
3163630Svbart@nginx.com static void
316453Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
316553Sigor@sysoev.ru {
3166141Smax.romanov@nginx.com     nxt_port_t           *port;
316753Sigor@sysoev.ru     nxt_thread_link_t    *link;
316853Sigor@sysoev.ru     nxt_event_engine_t   *engine;
316953Sigor@sysoev.ru     nxt_thread_handle_t  handle;
317053Sigor@sysoev.ru 
317158Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
317253Sigor@sysoev.ru     link = data;
317353Sigor@sysoev.ru 
317453Sigor@sysoev.ru     nxt_thread_wait(handle);
317553Sigor@sysoev.ru 
317653Sigor@sysoev.ru     engine = link->engine;
317753Sigor@sysoev.ru 
317853Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
317953Sigor@sysoev.ru 
3180141Smax.romanov@nginx.com     port = engine->port;
3181141Smax.romanov@nginx.com 
3182141Smax.romanov@nginx.com     // TODO notify all apps
3183141Smax.romanov@nginx.com 
3184343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3185163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3186343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3187163Smax.romanov@nginx.com 
3188163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
318963Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
319053Sigor@sysoev.ru 
319153Sigor@sysoev.ru     nxt_event_engine_free(engine);
319253Sigor@sysoev.ru 
319353Sigor@sysoev.ru     nxt_free(link);
319453Sigor@sysoev.ru }
319553Sigor@sysoev.ru 
319653Sigor@sysoev.ru 
319753Sigor@sysoev.ru static void
3198318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3199318Smax.romanov@nginx.com     void *data)
320088Smax.romanov@nginx.com {
320188Smax.romanov@nginx.com     size_t               dump_size;
3202431Sigor@sysoev.ru     nxt_int_t            ret;
3203608Sigor@sysoev.ru     nxt_buf_t            *b;
3204431Sigor@sysoev.ru     nxt_http_request_t   *r;
320588Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3206431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
3207743Smax.romanov@nginx.com     nxt_unit_response_t  *resp;
320888Smax.romanov@nginx.com 
320988Smax.romanov@nginx.com     b = msg->buf;
3210318Smax.romanov@nginx.com     rc = data;
321188Smax.romanov@nginx.com 
321288Smax.romanov@nginx.com     dump_size = nxt_buf_used_size(b);
321388Smax.romanov@nginx.com 
321488Smax.romanov@nginx.com     if (dump_size > 300) {
321588Smax.romanov@nginx.com         dump_size = 300;
321688Smax.romanov@nginx.com     }
321788Smax.romanov@nginx.com 
3218494Spluknet@nginx.com     nxt_debug(task, "%srouter app data (%uz): %*s",
321988Smax.romanov@nginx.com               msg->port_msg.last ? "last " : "", msg->size, dump_size,
322088Smax.romanov@nginx.com               b->mem.pos);
322188Smax.romanov@nginx.com 
322288Smax.romanov@nginx.com     if (msg->size == 0) {
322388Smax.romanov@nginx.com         b = NULL;
322488Smax.romanov@nginx.com     }
322588Smax.romanov@nginx.com 
3226431Sigor@sysoev.ru     ar = rc->ap;
3227570Smax.romanov@nginx.com     if (nxt_slow_path(ar == NULL)) {
3228570Smax.romanov@nginx.com         return;
3229570Smax.romanov@nginx.com     }
3230425Smax.romanov@nginx.com 
3231608Sigor@sysoev.ru     if (ar->request->error) {
3232608Sigor@sysoev.ru         nxt_router_rc_unlink(task, rc);
3233608Sigor@sysoev.ru         return;
3234608Sigor@sysoev.ru     }
3235608Sigor@sysoev.ru 
323688Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
323788Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
323888Smax.romanov@nginx.com 
3239608Sigor@sysoev.ru         nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request));
3240167Smax.romanov@nginx.com 
3241343Smax.romanov@nginx.com         nxt_router_rc_unlink(task, rc);
3242425Smax.romanov@nginx.com 
3243425Smax.romanov@nginx.com     } else {
3244615Smax.romanov@nginx.com         if (rc->app != NULL && rc->app->timeout != 0) {
3245431Sigor@sysoev.ru             ar->timer.handler = nxt_router_app_timeout;
3246615Smax.romanov@nginx.com             ar->timer_data = rc;
3247431Sigor@sysoev.ru             nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout);
3248425Smax.romanov@nginx.com         }
324988Smax.romanov@nginx.com     }
325088Smax.romanov@nginx.com 
325188Smax.romanov@nginx.com     if (b == NULL) {
325288Smax.romanov@nginx.com         return;
325388Smax.romanov@nginx.com     }
325488Smax.romanov@nginx.com 
3255206Smax.romanov@nginx.com     if (msg->buf == b) {
3256206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3257206Smax.romanov@nginx.com         msg->buf = NULL;
3258206Smax.romanov@nginx.com     }
3259194Smax.romanov@nginx.com 
3260431Sigor@sysoev.ru     r = ar->request;
3261431Sigor@sysoev.ru 
3262431Sigor@sysoev.ru     if (r->header_sent) {
3263431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3264431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3265277Sigor@sysoev.ru 
326688Smax.romanov@nginx.com     } else {
3267743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3268743Smax.romanov@nginx.com 
3269743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3270743Smax.romanov@nginx.com             goto fail;
3271743Smax.romanov@nginx.com         }
3272743Smax.romanov@nginx.com 
3273743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3274743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3275743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3276743Smax.romanov@nginx.com             goto fail;
3277743Smax.romanov@nginx.com         }
3278743Smax.romanov@nginx.com 
3279743Smax.romanov@nginx.com         nxt_unit_field_t  *f;
3280743Smax.romanov@nginx.com         nxt_http_field_t  *field;
3281743Smax.romanov@nginx.com 
3282743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
3283743Smax.romanov@nginx.com             field = nxt_list_add(ar->resp_parser.fields);
3284743Smax.romanov@nginx.com 
3285743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3286743Smax.romanov@nginx.com                 goto fail;
3287743Smax.romanov@nginx.com             }
3288743Smax.romanov@nginx.com 
3289743Smax.romanov@nginx.com             field->hash = f->hash;
3290743Smax.romanov@nginx.com             field->skip = f->skip;
3291743Smax.romanov@nginx.com 
3292743Smax.romanov@nginx.com             field->name_length = f->name_length;
3293743Smax.romanov@nginx.com             field->value_length = f->value_length;
3294743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3295743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3296743Smax.romanov@nginx.com 
3297743Smax.romanov@nginx.com             nxt_debug(task, "header: %*s: %*s",
3298743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3299743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
3300743Smax.romanov@nginx.com         }
3301743Smax.romanov@nginx.com         r->status = resp->status;
3302743Smax.romanov@nginx.com 
3303743Smax.romanov@nginx.com /*
3304431Sigor@sysoev.ru         ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem);
3305431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_DONE)) {
3306431Sigor@sysoev.ru             goto fail;
3307431Sigor@sysoev.ru         }
3308743Smax.romanov@nginx.com */
3309431Sigor@sysoev.ru         r->resp.fields = ar->resp_parser.fields;
3310431Sigor@sysoev.ru 
3311431Sigor@sysoev.ru         ret = nxt_http_fields_process(r->resp.fields,
3312431Sigor@sysoev.ru                                       &nxt_response_fields_hash, r);
3313431Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
3314431Sigor@sysoev.ru             goto fail;
3315431Sigor@sysoev.ru         }
3316431Sigor@sysoev.ru 
3317743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3318743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3319743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3320743Smax.romanov@nginx.com 
3321743Smax.romanov@nginx.com         } else {
3322743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3323743Smax.romanov@nginx.com         }
3324743Smax.romanov@nginx.com 
3325435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
3326435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3327435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3328507Smax.romanov@nginx.com 
3329520Smax.romanov@nginx.com             b = b->next;
3330520Smax.romanov@nginx.com         }
3331520Smax.romanov@nginx.com 
3332520Smax.romanov@nginx.com         if (b != NULL) {
3333431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3334431Sigor@sysoev.ru         }
3335431Sigor@sysoev.ru 
3336431Sigor@sysoev.ru         r->state = &nxt_http_request_send_state;
3337431Sigor@sysoev.ru 
3338431Sigor@sysoev.ru         nxt_http_request_header_send(task, r);
3339431Sigor@sysoev.ru     }
3340431Sigor@sysoev.ru 
3341431Sigor@sysoev.ru     return;
3342431Sigor@sysoev.ru 
3343431Sigor@sysoev.ru fail:
3344431Sigor@sysoev.ru 
3345615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3346615Smax.romanov@nginx.com 
3347431Sigor@sysoev.ru     nxt_router_rc_unlink(task, rc);
3348431Sigor@sysoev.ru }
3349431Sigor@sysoev.ru 
3350431Sigor@sysoev.ru 
3351431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3352431Sigor@sysoev.ru     nxt_aligned(64) =
3353431Sigor@sysoev.ru {
3354431Sigor@sysoev.ru     .ready_handler = nxt_http_request_send_body,
3355431Sigor@sysoev.ru     .error_handler = nxt_http_request_close_handler,
3356431Sigor@sysoev.ru };
3357431Sigor@sysoev.ru 
3358431Sigor@sysoev.ru 
3359431Sigor@sysoev.ru static void
3360431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3361431Sigor@sysoev.ru {
3362431Sigor@sysoev.ru     nxt_buf_t           *out;
3363431Sigor@sysoev.ru     nxt_http_request_t  *r;
3364431Sigor@sysoev.ru 
3365431Sigor@sysoev.ru     r = obj;
3366431Sigor@sysoev.ru 
3367431Sigor@sysoev.ru     out = r->out;
3368431Sigor@sysoev.ru 
3369431Sigor@sysoev.ru     if (out != NULL) {
3370431Sigor@sysoev.ru         r->out = NULL;
3371431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
337288Smax.romanov@nginx.com     }
337388Smax.romanov@nginx.com }
337488Smax.romanov@nginx.com 
3375277Sigor@sysoev.ru 
3376318Smax.romanov@nginx.com static void
3377318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3378318Smax.romanov@nginx.com     void *data)
3379318Smax.romanov@nginx.com {
3380425Smax.romanov@nginx.com     nxt_int_t            res;
3381425Smax.romanov@nginx.com     nxt_port_t           *port;
3382425Smax.romanov@nginx.com     nxt_bool_t           cancelled;
3383425Smax.romanov@nginx.com     nxt_req_app_link_t   *ra;
3384318Smax.romanov@nginx.com     nxt_req_conn_link_t  *rc;
3385318Smax.romanov@nginx.com 
3386318Smax.romanov@nginx.com     rc = data;
3387318Smax.romanov@nginx.com 
3388425Smax.romanov@nginx.com     ra = rc->ra;
3389425Smax.romanov@nginx.com 
3390425Smax.romanov@nginx.com     if (ra != NULL) {
3391425Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream);
3392425Smax.romanov@nginx.com 
3393425Smax.romanov@nginx.com         if (cancelled) {
3394425Smax.romanov@nginx.com             nxt_router_ra_inc_use(ra);
3395425Smax.romanov@nginx.com 
3396427Smax.romanov@nginx.com             res = nxt_router_app_port(task, rc->app, ra);
3397425Smax.romanov@nginx.com 
3398425Smax.romanov@nginx.com             if (res == NXT_OK) {
3399425Smax.romanov@nginx.com                 port = ra->app_port;
3400425Smax.romanov@nginx.com 
3401551Smax.romanov@nginx.com                 if (nxt_slow_path(port == NULL)) {
3402551Smax.romanov@nginx.com                     nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra");
3403551Smax.romanov@nginx.com                     return;
3404551Smax.romanov@nginx.com                 }
3405425Smax.romanov@nginx.com 
3406425Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc,
3407425Smax.romanov@nginx.com                                          port->pid);
3408425Smax.romanov@nginx.com 
3409425Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, ra);
3410425Smax.romanov@nginx.com             }
3411425Smax.romanov@nginx.com 
3412425Smax.romanov@nginx.com             msg->port_msg.last = 0;
3413425Smax.romanov@nginx.com 
3414425Smax.romanov@nginx.com             return;
3415425Smax.romanov@nginx.com         }
3416425Smax.romanov@nginx.com     }
3417425Smax.romanov@nginx.com 
3418616Smax.romanov@nginx.com     if (rc->ap != NULL) {
3419616Smax.romanov@nginx.com         nxt_http_request_error(task, rc->ap->request,
3420616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3421616Smax.romanov@nginx.com     }
3422318Smax.romanov@nginx.com 
3423343Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
3424318Smax.romanov@nginx.com }
3425318Smax.romanov@nginx.com 
3426318Smax.romanov@nginx.com 
3427141Smax.romanov@nginx.com static void
3428343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3429343Smax.romanov@nginx.com     void *data)
3430192Smax.romanov@nginx.com {
3431753Smax.romanov@nginx.com     nxt_app_t        *app;
3432753Smax.romanov@nginx.com     nxt_port_t       *port;
3433753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3434753Smax.romanov@nginx.com 
3435753Smax.romanov@nginx.com     app_joint = data;
3436347Smax.romanov@nginx.com     port = msg->u.new_port;
3437343Smax.romanov@nginx.com 
3438753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3439343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3440343Smax.romanov@nginx.com 
3441753Smax.romanov@nginx.com     app = app_joint->app;
3442753Smax.romanov@nginx.com 
3443753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3444753Smax.romanov@nginx.com 
3445753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3446753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3447753Smax.romanov@nginx.com 
3448753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3449753Smax.romanov@nginx.com 
3450753Smax.romanov@nginx.com         return;
3451753Smax.romanov@nginx.com     }
3452753Smax.romanov@nginx.com 
3453343Smax.romanov@nginx.com     port->app = app;
3454343Smax.romanov@nginx.com 
3455343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3456343Smax.romanov@nginx.com 
3457507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3458507Smax.romanov@nginx.com 
3459507Smax.romanov@nginx.com     app->pending_processes--;
3460507Smax.romanov@nginx.com     app->processes++;
3461343Smax.romanov@nginx.com 
3462343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3463343Smax.romanov@nginx.com 
3464507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3465507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3466343Smax.romanov@nginx.com 
3467343Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, 0, 0);
3468192Smax.romanov@nginx.com }
3469192Smax.romanov@nginx.com 
3470192Smax.romanov@nginx.com 
3471192Smax.romanov@nginx.com static void
3472343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3473343Smax.romanov@nginx.com     void *data)
3474192Smax.romanov@nginx.com {
3475318Smax.romanov@nginx.com     nxt_app_t           *app;
3476753Smax.romanov@nginx.com     nxt_app_joint_t     *app_joint;
3477318Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
3478318Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3479343Smax.romanov@nginx.com 
3480753Smax.romanov@nginx.com     app_joint = data;
3481753Smax.romanov@nginx.com 
3482753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3483753Smax.romanov@nginx.com 
3484753Smax.romanov@nginx.com     app = app_joint->app;
3485753Smax.romanov@nginx.com 
3486753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3487753Smax.romanov@nginx.com 
3488753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3489753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
3490753Smax.romanov@nginx.com 
3491753Smax.romanov@nginx.com         return;
3492753Smax.romanov@nginx.com     }
3493343Smax.romanov@nginx.com 
3494343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
3495343Smax.romanov@nginx.com 
3496343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3497343Smax.romanov@nginx.com 
3498507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3499507Smax.romanov@nginx.com 
3500507Smax.romanov@nginx.com     app->pending_processes--;
3501318Smax.romanov@nginx.com 
3502318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
3503318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
3504318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3505343Smax.romanov@nginx.com         lnk->next = NULL;
3506318Smax.romanov@nginx.com 
3507425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3508318Smax.romanov@nginx.com 
3509343Smax.romanov@nginx.com     } else {
3510343Smax.romanov@nginx.com         ra = NULL;
3511343Smax.romanov@nginx.com     }
3512343Smax.romanov@nginx.com 
3513343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3514343Smax.romanov@nginx.com 
3515343Smax.romanov@nginx.com     if (ra != NULL) {
3516318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
3517318Smax.romanov@nginx.com                   &app->name, app, ra->stream);
3518318Smax.romanov@nginx.com 
3519507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start application process");
3520425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3521318Smax.romanov@nginx.com     }
3522192Smax.romanov@nginx.com }
3523192Smax.romanov@nginx.com 
3524753Smax.romanov@nginx.com nxt_inline nxt_port_t *
3525753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app);
3526192Smax.romanov@nginx.com 
3527343Smax.romanov@nginx.com void
3528343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
3529141Smax.romanov@nginx.com {
3530343Smax.romanov@nginx.com     int  c;
3531343Smax.romanov@nginx.com 
3532343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
3533343Smax.romanov@nginx.com 
3534343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
3535343Smax.romanov@nginx.com 
3536753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
3537753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
3538753Smax.romanov@nginx.com 
3539753Smax.romanov@nginx.com         } else {
3540753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
3541753Smax.romanov@nginx.com         }
3542163Smax.romanov@nginx.com     }
3543343Smax.romanov@nginx.com }
3544343Smax.romanov@nginx.com 
3545343Smax.romanov@nginx.com 
3546424Smax.romanov@nginx.com nxt_inline nxt_bool_t
3547424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
3548424Smax.romanov@nginx.com {
3549424Smax.romanov@nginx.com     nxt_port_t        *port;
3550424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3551424Smax.romanov@nginx.com 
3552424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3553424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3554424Smax.romanov@nginx.com 
3555424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
3556424Smax.romanov@nginx.com }
3557424Smax.romanov@nginx.com 
3558424Smax.romanov@nginx.com 
3559343Smax.romanov@nginx.com nxt_inline nxt_port_t *
3560427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
3561343Smax.romanov@nginx.com {
3562343Smax.romanov@nginx.com     nxt_port_t        *port;
3563343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3564343Smax.romanov@nginx.com 
3565343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3566343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
3567343Smax.romanov@nginx.com 
3568343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3569343Smax.romanov@nginx.com 
3570424Smax.romanov@nginx.com     port->app_pending_responses++;
3571424Smax.romanov@nginx.com 
3572507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3573507Smax.romanov@nginx.com         app->idle_processes--;
3574507Smax.romanov@nginx.com 
3575507Smax.romanov@nginx.com         if (port->idle_start == 0) {
3576507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
3577507Smax.romanov@nginx.com 
3578507Smax.romanov@nginx.com         } else {
3579507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
3580507Smax.romanov@nginx.com 
3581507Smax.romanov@nginx.com             port->idle_start = 0;
3582507Smax.romanov@nginx.com         }
3583507Smax.romanov@nginx.com     }
3584507Smax.romanov@nginx.com 
3585428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
3586428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3587428Smax.romanov@nginx.com         && (app->max_requests == 0
3588428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3589428Smax.romanov@nginx.com                 < app->max_requests))
3590277Sigor@sysoev.ru     {
3591343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
3592343Smax.romanov@nginx.com 
3593425Smax.romanov@nginx.com         nxt_port_inc_use(port);
3594425Smax.romanov@nginx.com 
3595343Smax.romanov@nginx.com     } else {
3596343Smax.romanov@nginx.com         lnk->next = NULL;
3597167Smax.romanov@nginx.com     }
3598167Smax.romanov@nginx.com 
3599343Smax.romanov@nginx.com     return port;
3600163Smax.romanov@nginx.com }
3601163Smax.romanov@nginx.com 
3602163Smax.romanov@nginx.com 
3603507Smax.romanov@nginx.com nxt_inline nxt_port_t *
3604507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
3605141Smax.romanov@nginx.com {
3606343Smax.romanov@nginx.com     nxt_port_t  *port;
3607141Smax.romanov@nginx.com 
3608141Smax.romanov@nginx.com     port = NULL;
3609141Smax.romanov@nginx.com 
3610141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3611141Smax.romanov@nginx.com 
3612343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
3613343Smax.romanov@nginx.com 
3614424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
3615343Smax.romanov@nginx.com             port = NULL;
3616343Smax.romanov@nginx.com 
3617343Smax.romanov@nginx.com             continue;
3618343Smax.romanov@nginx.com         }
3619343Smax.romanov@nginx.com 
3620507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
3621507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
3622507Smax.romanov@nginx.com 
3623507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
3624507Smax.romanov@nginx.com             app->idle_processes--;
3625507Smax.romanov@nginx.com         }
3626507Smax.romanov@nginx.com 
3627507Smax.romanov@nginx.com         port->app = NULL;
3628507Smax.romanov@nginx.com         app->processes--;
3629343Smax.romanov@nginx.com 
3630343Smax.romanov@nginx.com         break;
3631343Smax.romanov@nginx.com 
3632343Smax.romanov@nginx.com     } nxt_queue_loop;
3633141Smax.romanov@nginx.com 
3634141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3635141Smax.romanov@nginx.com 
3636141Smax.romanov@nginx.com     return port;
3637141Smax.romanov@nginx.com }
3638141Smax.romanov@nginx.com 
3639141Smax.romanov@nginx.com 
3640141Smax.romanov@nginx.com static void
3641753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
3642507Smax.romanov@nginx.com {
3643753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
3644507Smax.romanov@nginx.com 
3645507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
3646507Smax.romanov@nginx.com 
3647753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
3648507Smax.romanov@nginx.com }
3649507Smax.romanov@nginx.com 
3650507Smax.romanov@nginx.com 
3651507Smax.romanov@nginx.com static void
3652343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
3653141Smax.romanov@nginx.com {
3654343Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
3655343Smax.romanov@nginx.com 
3656538Svbart@nginx.com     ra = data;
3657538Svbart@nginx.com 
3658538Svbart@nginx.com #if (NXT_DEBUG)
3659538Svbart@nginx.com     {
3660538Svbart@nginx.com     nxt_app_t  *app;
3661538Svbart@nginx.com 
3662343Smax.romanov@nginx.com     app = obj;
3663141Smax.romanov@nginx.com 
3664141Smax.romanov@nginx.com     nxt_assert(app != NULL);
3665343Smax.romanov@nginx.com     nxt_assert(ra != NULL);
3666343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
3667343Smax.romanov@nginx.com 
3668343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
3669343Smax.romanov@nginx.com               &app->name, app, ra->stream);
3670538Svbart@nginx.com     }
3671538Svbart@nginx.com #endif
3672343Smax.romanov@nginx.com 
3673425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
3674343Smax.romanov@nginx.com }
3675343Smax.romanov@nginx.com 
3676343Smax.romanov@nginx.com 
3677343Smax.romanov@nginx.com static void
3678343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
3679343Smax.romanov@nginx.com     uint32_t request_failed, uint32_t got_response)
3680343Smax.romanov@nginx.com {
3681427Smax.romanov@nginx.com     nxt_app_t                *app;
3682507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
3683507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
3684427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
3685427Smax.romanov@nginx.com     nxt_req_app_link_t       *ra, *pending_ra, *re_ra;
3686427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
3687343Smax.romanov@nginx.com 
3688343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3689343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
3690343Smax.romanov@nginx.com 
3691427Smax.romanov@nginx.com     ra = NULL;
3692427Smax.romanov@nginx.com 
3693343Smax.romanov@nginx.com     app = port->app;
3694343Smax.romanov@nginx.com 
3695343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3696343Smax.romanov@nginx.com 
3697424Smax.romanov@nginx.com     port->app_pending_responses -= request_failed + got_response;
3698343Smax.romanov@nginx.com     port->app_responses += got_response;
3699343Smax.romanov@nginx.com 
3700427Smax.romanov@nginx.com     if (port->pair[1] != -1
3701426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
3702428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3703428Smax.romanov@nginx.com         && (app->max_requests == 0
3704428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3705428Smax.romanov@nginx.com                 < app->max_requests))
3706343Smax.romanov@nginx.com     {
3707424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
3708424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
3709424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
3710424Smax.romanov@nginx.com 
3711424Smax.romanov@nginx.com             } else {
3712424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3713424Smax.romanov@nginx.com             }
3714424Smax.romanov@nginx.com 
3715425Smax.romanov@nginx.com             nxt_port_inc_use(port);
3716424Smax.romanov@nginx.com 
3717424Smax.romanov@nginx.com         } else {
3718424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
3719424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
3720424Smax.romanov@nginx.com             {
3721424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
3722424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
3723424Smax.romanov@nginx.com             }
3724424Smax.romanov@nginx.com         }
3725141Smax.romanov@nginx.com     }
3726141Smax.romanov@nginx.com 
3727427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
3728426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
3729343Smax.romanov@nginx.com     {
3730141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
3731141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3732343Smax.romanov@nginx.com         lnk->next = NULL;
3733141Smax.romanov@nginx.com 
3734425Smax.romanov@nginx.com         ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests);
3735425Smax.romanov@nginx.com 
3736427Smax.romanov@nginx.com         ra->app_port = nxt_router_pop_first_port(app);
3737425Smax.romanov@nginx.com 
3738425Smax.romanov@nginx.com         if (ra->app_port->app_pending_responses > 1) {
3739427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
3740425Smax.romanov@nginx.com         }
3741425Smax.romanov@nginx.com     }
3742425Smax.romanov@nginx.com 
3743427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
3744425Smax.romanov@nginx.com     if ((request_failed > 0 || got_response > 0)
3745425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
3746425Smax.romanov@nginx.com     {
3747425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
3748425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3749425Smax.romanov@nginx.com         lnk->next = NULL;
3750425Smax.romanov@nginx.com 
3751427Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
3752427Smax.romanov@nginx.com                                          link_port_pending);
3753427Smax.romanov@nginx.com 
3754427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
3755427Smax.romanov@nginx.com 
3756427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
3757427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
3758425Smax.romanov@nginx.com 
3759425Smax.romanov@nginx.com     } else {
3760427Smax.romanov@nginx.com         pending_ra = NULL;
3761141Smax.romanov@nginx.com     }
3762141Smax.romanov@nginx.com 
3763427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
3764427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
3765427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
3766427Smax.romanov@nginx.com 
3767427Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending);
3768427Smax.romanov@nginx.com 
3769427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
3770427Smax.romanov@nginx.com 
3771427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
3772427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
3773427Smax.romanov@nginx.com 
3774427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
3775427Smax.romanov@nginx.com                                               re_ra->stream);
3776427Smax.romanov@nginx.com 
3777427Smax.romanov@nginx.com             if (cancelled) {
3778427Smax.romanov@nginx.com                 nxt_router_ra_inc_use(re_ra);
3779427Smax.romanov@nginx.com 
3780427Smax.romanov@nginx.com                 state.ra = re_ra;
3781427Smax.romanov@nginx.com                 state.app = app;
3782427Smax.romanov@nginx.com 
3783427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
3784427Smax.romanov@nginx.com 
3785427Smax.romanov@nginx.com                 goto re_ra_cancelled;
3786427Smax.romanov@nginx.com             }
3787427Smax.romanov@nginx.com         }
3788427Smax.romanov@nginx.com     }
3789427Smax.romanov@nginx.com 
3790427Smax.romanov@nginx.com     re_ra = NULL;
3791427Smax.romanov@nginx.com 
3792427Smax.romanov@nginx.com re_ra_cancelled:
3793427Smax.romanov@nginx.com 
3794753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
3795753Smax.romanov@nginx.com                  && port->app_pending_responses == 0
3796753Smax.romanov@nginx.com                  && port->app_responses >= app->max_requests);
3797367Smax.romanov@nginx.com 
3798507Smax.romanov@nginx.com     if (send_quit) {
3799507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
3800507Smax.romanov@nginx.com 
3801507Smax.romanov@nginx.com         port->app = NULL;
3802507Smax.romanov@nginx.com         app->processes--;
3803507Smax.romanov@nginx.com 
3804507Smax.romanov@nginx.com     } else {
3805507Smax.romanov@nginx.com         port_unchained = 0;
3806507Smax.romanov@nginx.com     }
3807507Smax.romanov@nginx.com 
3808507Smax.romanov@nginx.com     adjust_idle_timer = 0;
3809507Smax.romanov@nginx.com 
3810571Smax.romanov@nginx.com     if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) {
3811507Smax.romanov@nginx.com         nxt_assert(port->idle_link.next == NULL);
3812507Smax.romanov@nginx.com 
3813507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
3814507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
3815507Smax.romanov@nginx.com         {
3816507Smax.romanov@nginx.com             adjust_idle_timer = 1;
3817507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
3818507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
3819507Smax.romanov@nginx.com         }
3820507Smax.romanov@nginx.com 
3821507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
3822507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
3823507Smax.romanov@nginx.com 
3824507Smax.romanov@nginx.com         } else {
3825507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
3826507Smax.romanov@nginx.com 
3827507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
3828507Smax.romanov@nginx.com         }
3829507Smax.romanov@nginx.com 
3830507Smax.romanov@nginx.com         app->idle_processes++;
3831507Smax.romanov@nginx.com     }
3832507Smax.romanov@nginx.com 
3833343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3834343Smax.romanov@nginx.com 
3835507Smax.romanov@nginx.com     if (adjust_idle_timer) {
3836507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
3837507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
3838507Smax.romanov@nginx.com     }
3839507Smax.romanov@nginx.com 
3840427Smax.romanov@nginx.com     if (pending_ra != NULL) {
3841427Smax.romanov@nginx.com         nxt_router_ra_use(task, pending_ra, -1);
3842427Smax.romanov@nginx.com     }
3843427Smax.romanov@nginx.com 
3844427Smax.romanov@nginx.com     if (re_ra != NULL) {
3845427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
3846427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3847427Smax.romanov@nginx.com                                nxt_router_app_process_request,
3848427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
3849427Smax.romanov@nginx.com         }
3850425Smax.romanov@nginx.com     }
3851425Smax.romanov@nginx.com 
3852343Smax.romanov@nginx.com     if (ra != NULL) {
3853425Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
3854425Smax.romanov@nginx.com 
3855343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3856343Smax.romanov@nginx.com                            nxt_router_app_process_request,
3857343Smax.romanov@nginx.com                            &task->thread->engine->task, app, ra);
3858343Smax.romanov@nginx.com 
3859343Smax.romanov@nginx.com         goto adjust_use;
3860343Smax.romanov@nginx.com     }
3861343Smax.romanov@nginx.com 
3862343Smax.romanov@nginx.com     /* ? */
3863163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
3864343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
3865343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
3866343Smax.romanov@nginx.com 
3867343Smax.romanov@nginx.com         goto adjust_use;
3868163Smax.romanov@nginx.com     }
3869163Smax.romanov@nginx.com 
3870367Smax.romanov@nginx.com     if (send_quit) {
3871507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
3872167Smax.romanov@nginx.com                   &app->name, app);
3873163Smax.romanov@nginx.com 
3874163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
3875163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
3876163Smax.romanov@nginx.com 
3877507Smax.romanov@nginx.com         if (port_unchained) {
3878507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
3879507Smax.romanov@nginx.com         }
3880507Smax.romanov@nginx.com 
3881343Smax.romanov@nginx.com         goto adjust_use;
3882163Smax.romanov@nginx.com     }
3883163Smax.romanov@nginx.com 
3884167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
3885167Smax.romanov@nginx.com               &app->name, app);
3886141Smax.romanov@nginx.com 
3887343Smax.romanov@nginx.com adjust_use:
3888343Smax.romanov@nginx.com 
3889425Smax.romanov@nginx.com     if (request_failed > 0 || got_response > 0) {
3890425Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3891343Smax.romanov@nginx.com     }
3892141Smax.romanov@nginx.com }
3893141Smax.romanov@nginx.com 
3894141Smax.romanov@nginx.com 
3895343Smax.romanov@nginx.com void
3896343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
3897141Smax.romanov@nginx.com {
3898507Smax.romanov@nginx.com     nxt_app_t         *app;
3899507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
3900507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
3901507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
3902141Smax.romanov@nginx.com 
3903141Smax.romanov@nginx.com     app = port->app;
3904343Smax.romanov@nginx.com 
3905343Smax.romanov@nginx.com     nxt_assert(app != NULL);
3906141Smax.romanov@nginx.com 
3907141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3908141Smax.romanov@nginx.com 
3909507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
3910507Smax.romanov@nginx.com 
3911507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3912507Smax.romanov@nginx.com         app->idle_processes--;
3913507Smax.romanov@nginx.com 
3914507Smax.romanov@nginx.com         if (port->idle_start == 0
3915507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
3916507Smax.romanov@nginx.com         {
3917507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
3918507Smax.romanov@nginx.com 
3919507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
3920507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
3921507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
3922507Smax.romanov@nginx.com 
3923507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
3924507Smax.romanov@nginx.com 
3925507Smax.romanov@nginx.com             idle_port->idle_start = 0;
3926507Smax.romanov@nginx.com         }
3927343Smax.romanov@nginx.com     }
3928343Smax.romanov@nginx.com 
3929507Smax.romanov@nginx.com     app->processes--;
3930507Smax.romanov@nginx.com 
3931753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
3932507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
3933507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
3934507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
3935507Smax.romanov@nginx.com 
3936507Smax.romanov@nginx.com     if (start_process) {
3937507Smax.romanov@nginx.com         app->pending_processes++;
3938163Smax.romanov@nginx.com     }
3939141Smax.romanov@nginx.com 
3940141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3941163Smax.romanov@nginx.com 
3942507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
3943343Smax.romanov@nginx.com 
3944343Smax.romanov@nginx.com     if (unchain) {
3945343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3946163Smax.romanov@nginx.com     }
3947163Smax.romanov@nginx.com 
3948507Smax.romanov@nginx.com     if (start_process) {
3949507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
3950507Smax.romanov@nginx.com     }
3951507Smax.romanov@nginx.com }
3952507Smax.romanov@nginx.com 
3953507Smax.romanov@nginx.com 
3954507Smax.romanov@nginx.com static void
3955507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
3956507Smax.romanov@nginx.com {
3957507Smax.romanov@nginx.com     nxt_app_t           *app;
3958507Smax.romanov@nginx.com     nxt_bool_t          queued;
3959507Smax.romanov@nginx.com     nxt_port_t          *port;
3960507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
3961507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
3962507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
3963507Smax.romanov@nginx.com 
3964507Smax.romanov@nginx.com     app = obj;
3965507Smax.romanov@nginx.com     queued = (data == app);
3966507Smax.romanov@nginx.com 
3967507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
3968507Smax.romanov@nginx.com               &app->name, queued);
3969507Smax.romanov@nginx.com 
3970507Smax.romanov@nginx.com     engine = task->thread->engine;
3971507Smax.romanov@nginx.com 
3972507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
3973507Smax.romanov@nginx.com 
3974753Smax.romanov@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.precision;
3975507Smax.romanov@nginx.com     timeout = 0;
3976507Smax.romanov@nginx.com 
3977507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3978507Smax.romanov@nginx.com 
3979507Smax.romanov@nginx.com     if (queued) {
3980507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
3981343Smax.romanov@nginx.com     }
3982507Smax.romanov@nginx.com 
3983507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
3984507Smax.romanov@nginx.com 
3985551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
3986507Smax.romanov@nginx.com 
3987507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
3988507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
3989507Smax.romanov@nginx.com 
3990507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
3991507Smax.romanov@nginx.com 
3992507Smax.romanov@nginx.com         if (timeout > threshold) {
3993507Smax.romanov@nginx.com             break;
3994507Smax.romanov@nginx.com         }
3995507Smax.romanov@nginx.com 
3996507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3997507Smax.romanov@nginx.com         lnk->next = NULL;
3998507Smax.romanov@nginx.com 
3999507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4000507Smax.romanov@nginx.com 
4001507Smax.romanov@nginx.com         app->idle_processes--;
4002507Smax.romanov@nginx.com         app->processes--;
4003507Smax.romanov@nginx.com         port->app = NULL;
4004507Smax.romanov@nginx.com 
4005507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4006507Smax.romanov@nginx.com 
4007507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4008507Smax.romanov@nginx.com                   &app->name, port->pid);
4009507Smax.romanov@nginx.com 
4010507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4011507Smax.romanov@nginx.com 
4012507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4013507Smax.romanov@nginx.com 
4014507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4015507Smax.romanov@nginx.com     }
4016507Smax.romanov@nginx.com 
4017507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4018507Smax.romanov@nginx.com 
4019507Smax.romanov@nginx.com     if (timeout > threshold) {
4020753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4021507Smax.romanov@nginx.com 
4022507Smax.romanov@nginx.com     } else {
4023753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4024507Smax.romanov@nginx.com     }
4025507Smax.romanov@nginx.com 
4026507Smax.romanov@nginx.com     if (queued) {
4027507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4028507Smax.romanov@nginx.com     }
4029507Smax.romanov@nginx.com }
4030507Smax.romanov@nginx.com 
4031507Smax.romanov@nginx.com 
4032507Smax.romanov@nginx.com static void
4033507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4034507Smax.romanov@nginx.com {
4035753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4036753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4037507Smax.romanov@nginx.com 
4038507Smax.romanov@nginx.com     timer = obj;
4039753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4040753Smax.romanov@nginx.com 
4041753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4042753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4043753Smax.romanov@nginx.com     }
4044753Smax.romanov@nginx.com }
4045753Smax.romanov@nginx.com 
4046753Smax.romanov@nginx.com 
4047753Smax.romanov@nginx.com static void
4048753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4049753Smax.romanov@nginx.com {
4050753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4051753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4052753Smax.romanov@nginx.com 
4053753Smax.romanov@nginx.com     timer = obj;
4054753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4055753Smax.romanov@nginx.com 
4056753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4057507Smax.romanov@nginx.com }
4058507Smax.romanov@nginx.com 
4059507Smax.romanov@nginx.com 
4060507Smax.romanov@nginx.com static void
4061753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4062507Smax.romanov@nginx.com {
4063753Smax.romanov@nginx.com     nxt_app_t        *app;
4064753Smax.romanov@nginx.com     nxt_port_t       *port;
4065753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4066753Smax.romanov@nginx.com 
4067753Smax.romanov@nginx.com     app_joint = obj;
4068753Smax.romanov@nginx.com     app = app_joint->app;
4069753Smax.romanov@nginx.com 
4070753Smax.romanov@nginx.com     for ( ;; ) {
4071753Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
4072753Smax.romanov@nginx.com         if (port == NULL) {
4073753Smax.romanov@nginx.com             break;
4074753Smax.romanov@nginx.com         }
4075753Smax.romanov@nginx.com 
4076753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4077753Smax.romanov@nginx.com 
4078753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4079753Smax.romanov@nginx.com 
4080753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4081753Smax.romanov@nginx.com     }
4082753Smax.romanov@nginx.com 
4083753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
4084753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4085753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->requests));
4086753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4087753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4088753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4089753Smax.romanov@nginx.com 
4090753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
4091753Smax.romanov@nginx.com     nxt_free(app);
4092753Smax.romanov@nginx.com 
4093753Smax.romanov@nginx.com     app_joint->app = NULL;
4094753Smax.romanov@nginx.com 
4095753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4096753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4097753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4098753Smax.romanov@nginx.com 
4099753Smax.romanov@nginx.com     } else {
4100753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4101753Smax.romanov@nginx.com     }
4102141Smax.romanov@nginx.com }
4103141Smax.romanov@nginx.com 
4104141Smax.romanov@nginx.com 
4105427Smax.romanov@nginx.com static void
4106427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
4107141Smax.romanov@nginx.com {
4108427Smax.romanov@nginx.com     nxt_app_t           *app;
4109507Smax.romanov@nginx.com     nxt_bool_t          can_start_process;
4110427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4111427Smax.romanov@nginx.com 
4112427Smax.romanov@nginx.com     ra = state->ra;
4113427Smax.romanov@nginx.com     app = state->app;
4114427Smax.romanov@nginx.com 
4115427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
4116343Smax.romanov@nginx.com 
4117425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_app_requests))
4118425Smax.romanov@nginx.com     {
4119425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4120425Smax.romanov@nginx.com     }
4121425Smax.romanov@nginx.com 
4122425Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&ra->link_port_pending))
4123425Smax.romanov@nginx.com     {
4124427Smax.romanov@nginx.com         nxt_assert(ra->link_app_pending.next != NULL);
4125427Smax.romanov@nginx.com 
4126427Smax.romanov@nginx.com         nxt_queue_remove(&ra->link_app_pending);
4127427Smax.romanov@nginx.com         ra->link_app_pending.next = NULL;
4128427Smax.romanov@nginx.com 
4129425Smax.romanov@nginx.com         nxt_router_ra_dec_use(ra);
4130425Smax.romanov@nginx.com     }
4131425Smax.romanov@nginx.com 
4132427Smax.romanov@nginx.com     state->failed_port = ra->app_port;
4133427Smax.romanov@nginx.com 
4134425Smax.romanov@nginx.com     if (ra->app_port != NULL) {
4135427Smax.romanov@nginx.com         state->failed_port_use_delta--;
4136427Smax.romanov@nginx.com 
4137427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
4138427Smax.romanov@nginx.com 
4139427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
4140427Smax.romanov@nginx.com             state->failed_port_use_delta--;
4141427Smax.romanov@nginx.com         }
4142427Smax.romanov@nginx.com 
4143427Smax.romanov@nginx.com         ra->app_port = NULL;
4144427Smax.romanov@nginx.com     }
4145427Smax.romanov@nginx.com 
4146507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
4147507Smax.romanov@nginx.com 
4148427Smax.romanov@nginx.com     state->port = NULL;
4149507Smax.romanov@nginx.com     state->start_process = 0;
4150427Smax.romanov@nginx.com 
4151427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
4152507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
4153427Smax.romanov@nginx.com     {
4154427Smax.romanov@nginx.com         ra = nxt_router_ra_create(task, ra);
4155427Smax.romanov@nginx.com 
4156427Smax.romanov@nginx.com         if (nxt_slow_path(ra == NULL)) {
4157427Smax.romanov@nginx.com             goto fail;
4158427Smax.romanov@nginx.com         }
4159427Smax.romanov@nginx.com 
4160427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
4161427Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests, &ra->link_app_requests);
4162427Smax.romanov@nginx.com 
4163427Smax.romanov@nginx.com         } else {
4164427Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests, &ra->link_app_requests);
4165427Smax.romanov@nginx.com         }
4166427Smax.romanov@nginx.com 
4167427Smax.romanov@nginx.com         nxt_router_ra_inc_use(ra);
4168427Smax.romanov@nginx.com 
4169427Smax.romanov@nginx.com         nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream);
4170427Smax.romanov@nginx.com 
4171507Smax.romanov@nginx.com         if (can_start_process) {
4172507Smax.romanov@nginx.com             app->pending_processes++;
4173507Smax.romanov@nginx.com             state->start_process = 1;
4174425Smax.romanov@nginx.com         }
4175425Smax.romanov@nginx.com 
4176425Smax.romanov@nginx.com     } else {
4177427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
4178427Smax.romanov@nginx.com 
4179427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
4180427Smax.romanov@nginx.com             ra = nxt_router_ra_create(task, ra);
4181427Smax.romanov@nginx.com 
4182427Smax.romanov@nginx.com             if (nxt_slow_path(ra == NULL)) {
4183427Smax.romanov@nginx.com                 goto fail;
4184351Smax.romanov@nginx.com             }
4185427Smax.romanov@nginx.com 
4186427Smax.romanov@nginx.com             ra->app_port = state->port;
4187427Smax.romanov@nginx.com 
4188427Smax.romanov@nginx.com             nxt_router_ra_pending(task, app, ra);
4189425Smax.romanov@nginx.com         }
4190507Smax.romanov@nginx.com 
4191507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
4192507Smax.romanov@nginx.com             app->pending_processes++;
4193507Smax.romanov@nginx.com             state->start_process = 1;
4194507Smax.romanov@nginx.com         }
4195343Smax.romanov@nginx.com     }
4196343Smax.romanov@nginx.com 
4197427Smax.romanov@nginx.com fail:
4198427Smax.romanov@nginx.com 
4199427Smax.romanov@nginx.com     state->shared_ra = ra;
4200427Smax.romanov@nginx.com }
4201427Smax.romanov@nginx.com 
4202427Smax.romanov@nginx.com 
4203427Smax.romanov@nginx.com static nxt_int_t
4204427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
4205427Smax.romanov@nginx.com {
4206427Smax.romanov@nginx.com     nxt_int_t           res;
4207427Smax.romanov@nginx.com     nxt_app_t           *app;
4208427Smax.romanov@nginx.com     nxt_req_app_link_t  *ra;
4209427Smax.romanov@nginx.com 
4210427Smax.romanov@nginx.com     ra = state->shared_ra;
4211427Smax.romanov@nginx.com     app = state->app;
4212427Smax.romanov@nginx.com 
4213427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
4214427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
4215425Smax.romanov@nginx.com     }
4216425Smax.romanov@nginx.com 
4217351Smax.romanov@nginx.com     if (nxt_slow_path(ra == NULL)) {
4218427Smax.romanov@nginx.com         if (state->port != NULL) {
4219427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
4220425Smax.romanov@nginx.com         }
4221425Smax.romanov@nginx.com 
4222427Smax.romanov@nginx.com         nxt_router_ra_error(state->ra, 500,
4223427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
4224427Smax.romanov@nginx.com         nxt_router_ra_use(task, state->ra, -1);
4225427Smax.romanov@nginx.com 
4226351Smax.romanov@nginx.com         return NXT_ERROR;
4227351Smax.romanov@nginx.com     }
4228351Smax.romanov@nginx.com 
4229427Smax.romanov@nginx.com     if (state->port != NULL) {
4230343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
4231163Smax.romanov@nginx.com 
4232427Smax.romanov@nginx.com         ra->app_port = state->port;
4233343Smax.romanov@nginx.com 
4234507Smax.romanov@nginx.com         if (state->start_process) {
4235507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
4236507Smax.romanov@nginx.com         }
4237507Smax.romanov@nginx.com 
4238141Smax.romanov@nginx.com         return NXT_OK;
4239141Smax.romanov@nginx.com     }
4240141Smax.romanov@nginx.com 
4241507Smax.romanov@nginx.com     if (!state->start_process) {
4242507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
4243343Smax.romanov@nginx.com                   &app->name, app);
4244343Smax.romanov@nginx.com 
4245343Smax.romanov@nginx.com         return NXT_AGAIN;
4246343Smax.romanov@nginx.com     }
4247343Smax.romanov@nginx.com 
4248507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
4249343Smax.romanov@nginx.com 
4250343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4251507Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500, "Failed to start app process");
4252427Smax.romanov@nginx.com         nxt_router_ra_use(task, ra, -1);
4253343Smax.romanov@nginx.com 
4254141Smax.romanov@nginx.com         return NXT_ERROR;
4255141Smax.romanov@nginx.com     }
4256141Smax.romanov@nginx.com 
4257141Smax.romanov@nginx.com     return NXT_AGAIN;
425888Smax.romanov@nginx.com }
425988Smax.romanov@nginx.com 
426088Smax.romanov@nginx.com 
4261427Smax.romanov@nginx.com static nxt_int_t
4262427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
4263427Smax.romanov@nginx.com {
4264427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4265427Smax.romanov@nginx.com 
4266427Smax.romanov@nginx.com     state.ra = ra;
4267427Smax.romanov@nginx.com     state.app = app;
4268427Smax.romanov@nginx.com 
4269427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4270427Smax.romanov@nginx.com 
4271427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
4272427Smax.romanov@nginx.com 
4273427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4274427Smax.romanov@nginx.com 
4275427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
4276427Smax.romanov@nginx.com }
4277427Smax.romanov@nginx.com 
4278427Smax.romanov@nginx.com 
4279431Sigor@sysoev.ru void
4280431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar)
428153Sigor@sysoev.ru {
4282431Sigor@sysoev.ru     nxt_int_t            res;
4283431Sigor@sysoev.ru     nxt_app_t            *app;
4284431Sigor@sysoev.ru     nxt_port_t           *port;
4285431Sigor@sysoev.ru     nxt_event_engine_t   *engine;
4286431Sigor@sysoev.ru     nxt_http_request_t   *r;
4287431Sigor@sysoev.ru     nxt_req_app_link_t   ra_local, *ra;
4288431Sigor@sysoev.ru     nxt_req_conn_link_t  *rc;
4289431Sigor@sysoev.ru 
4290431Sigor@sysoev.ru     r = ar->request;
4291683Sigor@sysoev.ru     app = r->conf->socket_conf->application;
4292425Smax.romanov@nginx.com 
4293425Smax.romanov@nginx.com     if (app == NULL) {
4294431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4295425Smax.romanov@nginx.com         return;
4296425Smax.romanov@nginx.com     }
429788Smax.romanov@nginx.com 
429888Smax.romanov@nginx.com     engine = task->thread->engine;
429988Smax.romanov@nginx.com 
4300318Smax.romanov@nginx.com     rc = nxt_port_rpc_register_handler_ex(task, engine->port,
4301318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4302318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
4303318Smax.romanov@nginx.com                                           sizeof(nxt_req_conn_link_t));
4304122Smax.romanov@nginx.com 
430588Smax.romanov@nginx.com     if (nxt_slow_path(rc == NULL)) {
4306431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4307141Smax.romanov@nginx.com         return;
430888Smax.romanov@nginx.com     }
430988Smax.romanov@nginx.com 
4310318Smax.romanov@nginx.com     rc->stream = nxt_port_rpc_ex_stream(rc);
4311425Smax.romanov@nginx.com     rc->app = app;
4312425Smax.romanov@nginx.com 
4313425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4314425Smax.romanov@nginx.com 
4315431Sigor@sysoev.ru     rc->ap = ar;
4316346Smax.romanov@nginx.com 
4317351Smax.romanov@nginx.com     ra = &ra_local;
4318351Smax.romanov@nginx.com     nxt_router_ra_init(task, ra, rc);
4319167Smax.romanov@nginx.com 
4320427Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, ra);
4321141Smax.romanov@nginx.com 
4322141Smax.romanov@nginx.com     if (res != NXT_OK) {
4323141Smax.romanov@nginx.com         return;
4324141Smax.romanov@nginx.com     }
4325141Smax.romanov@nginx.com 
4326425Smax.romanov@nginx.com     ra = rc->ra;
4327167Smax.romanov@nginx.com     port = ra->app_port;
4328141Smax.romanov@nginx.com 
4329425Smax.romanov@nginx.com     nxt_assert(port != NULL);
4330141Smax.romanov@nginx.com 
4331318Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid);
4332318Smax.romanov@nginx.com 
4333425Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, ra);
4334167Smax.romanov@nginx.com }
4335167Smax.romanov@nginx.com 
4336167Smax.romanov@nginx.com 
4337167Smax.romanov@nginx.com static void
4338423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4339423Smax.romanov@nginx.com {
4340423Smax.romanov@nginx.com }
4341423Smax.romanov@nginx.com 
4342423Smax.romanov@nginx.com 
4343423Smax.romanov@nginx.com static void
4344425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
4345167Smax.romanov@nginx.com {
4346343Smax.romanov@nginx.com     uint32_t             request_failed;
4347743Smax.romanov@nginx.com     nxt_buf_t            *buf;
4348167Smax.romanov@nginx.com     nxt_int_t            res;
4349343Smax.romanov@nginx.com     nxt_port_t           *port, *c_port, *reply_port;
4350167Smax.romanov@nginx.com     nxt_app_parse_ctx_t  *ap;
4351167Smax.romanov@nginx.com 
4352343Smax.romanov@nginx.com     nxt_assert(ra->app_port != NULL);
4353343Smax.romanov@nginx.com 
4354343Smax.romanov@nginx.com     port = ra->app_port;
4355167Smax.romanov@nginx.com     reply_port = ra->reply_port;
4356167Smax.romanov@nginx.com     ap = ra->ap;
4357141Smax.romanov@nginx.com 
4358343Smax.romanov@nginx.com     request_failed = 1;
4359343Smax.romanov@nginx.com 
4360141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
4361141Smax.romanov@nginx.com                                              reply_port->id);
4362141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
4363141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
4364122Smax.romanov@nginx.com 
4365122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
4366423Smax.romanov@nginx.com             nxt_router_ra_error(ra, 500,
4367345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
4368343Smax.romanov@nginx.com             goto release_port;
4369122Smax.romanov@nginx.com         }
4370122Smax.romanov@nginx.com 
4371141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
437288Smax.romanov@nginx.com     }
437388Smax.romanov@nginx.com 
4374743Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, &ap->r, port,
4375743Smax.romanov@nginx.com                                  nxt_app_msg_prefix[port->app->type]);
4376743Smax.romanov@nginx.com 
4377743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
4378423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4379345Smax.romanov@nginx.com                             "Failed to prepare message for application");
4380343Smax.romanov@nginx.com         goto release_port;
4381122Smax.romanov@nginx.com     }
438288Smax.romanov@nginx.com 
4383507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4384743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4385743Smax.romanov@nginx.com                     port->socket.fd);
438688Smax.romanov@nginx.com 
4387343Smax.romanov@nginx.com     request_failed = 0;
4388343Smax.romanov@nginx.com 
4389743Smax.romanov@nginx.com     ra->msg_info.buf = buf;
4390743Smax.romanov@nginx.com     ra->msg_info.completion_handler = buf->completion_handler;
4391743Smax.romanov@nginx.com 
4392743Smax.romanov@nginx.com     for (; buf; buf = buf->next) {
4393743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
4394423Smax.romanov@nginx.com     }
4395423Smax.romanov@nginx.com 
4396743Smax.romanov@nginx.com     buf = ra->msg_info.buf;
4397743Smax.romanov@nginx.com 
4398423Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking,
4399423Smax.romanov@nginx.com                                      ra->stream);
4400423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4401423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4402423Smax.romanov@nginx.com                             "Failed to get tracking area");
4403423Smax.romanov@nginx.com         goto release_port;
4404423Smax.romanov@nginx.com     }
4405423Smax.romanov@nginx.com 
4406743Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA,
4407743Smax.romanov@nginx.com                                  -1, ra->stream, reply_port->id, buf,
4408423Smax.romanov@nginx.com                                  &ra->msg_info.tracking);
4409122Smax.romanov@nginx.com 
4410122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
4411423Smax.romanov@nginx.com         nxt_router_ra_error(ra, 500,
4412345Smax.romanov@nginx.com                             "Failed to send message to application");
4413343Smax.romanov@nginx.com         goto release_port;
4414122Smax.romanov@nginx.com     }
4415343Smax.romanov@nginx.com 
4416343Smax.romanov@nginx.com release_port:
4417343Smax.romanov@nginx.com 
4418345Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, request_failed, 0);
4419345Smax.romanov@nginx.com 
4420425Smax.romanov@nginx.com     nxt_router_ra_update_peer(task, ra);
442153Sigor@sysoev.ru }
442253Sigor@sysoev.ru 
442353Sigor@sysoev.ru 
4424743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4425743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4426743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4427743Smax.romanov@nginx.com };
4428743Smax.romanov@nginx.com 
4429743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4430743Smax.romanov@nginx.com 
4431743Smax.romanov@nginx.com 
4432743Smax.romanov@nginx.com static nxt_http_field_t *
4433743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4434216Sigor@sysoev.ru {
4435743Smax.romanov@nginx.com     if (part == NULL) {
4436743Smax.romanov@nginx.com         return NULL;
4437216Sigor@sysoev.ru     }
4438216Sigor@sysoev.ru 
4439743Smax.romanov@nginx.com     while (part->nelts == 0) {
4440743Smax.romanov@nginx.com         part = part->next;
4441743Smax.romanov@nginx.com         if (part == NULL) {
4442743Smax.romanov@nginx.com             return NULL;
4443743Smax.romanov@nginx.com         }
4444216Sigor@sysoev.ru     }
4445216Sigor@sysoev.ru 
4446743Smax.romanov@nginx.com     i->part = part;
4447743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4448743Smax.romanov@nginx.com 
4449743Smax.romanov@nginx.com     return i->field;
4450743Smax.romanov@nginx.com }
4451743Smax.romanov@nginx.com 
4452743Smax.romanov@nginx.com 
4453743Smax.romanov@nginx.com static nxt_http_field_t *
4454743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4455743Smax.romanov@nginx.com {
4456743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4457743Smax.romanov@nginx.com }
4458743Smax.romanov@nginx.com 
4459743Smax.romanov@nginx.com 
4460743Smax.romanov@nginx.com static nxt_http_field_t *
4461743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4462743Smax.romanov@nginx.com {
4463743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4464743Smax.romanov@nginx.com 
4465743Smax.romanov@nginx.com     end += i->part->nelts;
4466743Smax.romanov@nginx.com     i->field++;
4467743Smax.romanov@nginx.com 
4468743Smax.romanov@nginx.com     if (i->field < end) {
4469743Smax.romanov@nginx.com         return i->field;
4470216Sigor@sysoev.ru     }
4471216Sigor@sysoev.ru 
4472743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4473216Sigor@sysoev.ru }
4474216Sigor@sysoev.ru 
4475216Sigor@sysoev.ru 
4476743Smax.romanov@nginx.com static nxt_buf_t *
4477743Smax.romanov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
4478743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix)
4479216Sigor@sysoev.ru {
4480743Smax.romanov@nginx.com     void                      *target_pos, *query_pos;
4481743Smax.romanov@nginx.com     u_char                    *pos, *end, *p, c;
4482743Smax.romanov@nginx.com     size_t                    fields_count, req_size, size, free_size;
4483743Smax.romanov@nginx.com     size_t                    copy_size;
4484743Smax.romanov@nginx.com     nxt_buf_t                 *b, *buf, *out, **tail;
4485743Smax.romanov@nginx.com     nxt_http_field_t          *field, *dup;
4486743Smax.romanov@nginx.com     nxt_unit_field_t          *dst_field;
4487743Smax.romanov@nginx.com     nxt_fields_iter_t         iter, dup_iter;
4488743Smax.romanov@nginx.com     nxt_unit_request_t        *req;
4489216Sigor@sysoev.ru     nxt_app_request_header_t  *h;
4490216Sigor@sysoev.ru 
4491216Sigor@sysoev.ru     h = &r->header;
4492216Sigor@sysoev.ru 
4493743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
4494743Smax.romanov@nginx.com                 + h->method.length + 1
4495743Smax.romanov@nginx.com                 + h->version.length + 1
4496743Smax.romanov@nginx.com                 + r->remote.length + 1
4497743Smax.romanov@nginx.com                 + r->local.length + 1
4498743Smax.romanov@nginx.com                 + h->target.length + 1
4499743Smax.romanov@nginx.com                 + (h->path.start != h->target.start ? h->path.length + 1 : 0);
4500743Smax.romanov@nginx.com 
4501743Smax.romanov@nginx.com     fields_count = 0;
4502743Smax.romanov@nginx.com 
4503743Smax.romanov@nginx.com     nxt_list_each(field, h->fields) {
4504743Smax.romanov@nginx.com         fields_count++;
4505743Smax.romanov@nginx.com 
4506743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4507743Smax.romanov@nginx.com                     + field->value_length + 1;
4508743Smax.romanov@nginx.com     } nxt_list_loop;
4509743Smax.romanov@nginx.com 
4510743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4511743Smax.romanov@nginx.com 
4512743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4513743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4514743Smax.romanov@nginx.com                   (int) req_size);
4515743Smax.romanov@nginx.com 
4516743Smax.romanov@nginx.com         return NULL;
4517743Smax.romanov@nginx.com     }
4518743Smax.romanov@nginx.com 
4519743Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, port,
4520743Smax.romanov@nginx.com               nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE));
4521743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4522743Smax.romanov@nginx.com         return NULL;
4523743Smax.romanov@nginx.com     }
4524743Smax.romanov@nginx.com 
4525743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4526743Smax.romanov@nginx.com     out->mem.free += req_size;
4527743Smax.romanov@nginx.com 
4528743Smax.romanov@nginx.com     req->content_length = h->parsed_content_length;
4529743Smax.romanov@nginx.com 
4530743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4531743Smax.romanov@nginx.com 
4532743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4533743Smax.romanov@nginx.com 
4534743Smax.romanov@nginx.com     req->method_length = h->method.length;
4535743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
4536743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->method.start, h->method.length);
4537743Smax.romanov@nginx.com     *p++ = '\0';
4538743Smax.romanov@nginx.com 
4539743Smax.romanov@nginx.com     req->version_length = h->version.length;
4540743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
4541743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->version.start, h->version.length);
4542743Smax.romanov@nginx.com     *p++ = '\0';
4543743Smax.romanov@nginx.com 
4544743Smax.romanov@nginx.com     req->remote_length = r->remote.length;
4545743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
4546743Smax.romanov@nginx.com     p = nxt_cpymem(p, r->remote.start, r->remote.length);
4547743Smax.romanov@nginx.com     *p++ = '\0';
4548743Smax.romanov@nginx.com 
4549743Smax.romanov@nginx.com     req->local_length = r->local.length;
4550743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
4551743Smax.romanov@nginx.com     p = nxt_cpymem(p, r->local.start, r->local.length);
4552743Smax.romanov@nginx.com     *p++ = '\0';
4553743Smax.romanov@nginx.com 
4554743Smax.romanov@nginx.com     target_pos = p;
4555743Smax.romanov@nginx.com     req->target_length = h->target.length;
4556743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
4557743Smax.romanov@nginx.com     p = nxt_cpymem(p, h->target.start, h->target.length);
4558743Smax.romanov@nginx.com     *p++ = '\0';
4559743Smax.romanov@nginx.com 
4560743Smax.romanov@nginx.com     req->path_length = h->path.length;
4561216Sigor@sysoev.ru     if (h->path.start == h->target.start) {
4562743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
4563277Sigor@sysoev.ru 
4564216Sigor@sysoev.ru     } else {
4565743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
4566743Smax.romanov@nginx.com         p = nxt_cpymem(p, h->path.start, h->path.length);
4567743Smax.romanov@nginx.com         *p++ = '\0';
4568305Smax.romanov@nginx.com     }
4569216Sigor@sysoev.ru 
4570743Smax.romanov@nginx.com     req->query_length = h->query.length;
4571743Smax.romanov@nginx.com     if (h->query.start != NULL) {
4572743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
4573743Smax.romanov@nginx.com                                    h->query.start - h->target.start);
4574743Smax.romanov@nginx.com 
4575743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
4576277Sigor@sysoev.ru 
4577216Sigor@sysoev.ru     } else {
4578743Smax.romanov@nginx.com         req->query.offset = 0;
4579216Sigor@sysoev.ru     }
4580216Sigor@sysoev.ru 
4581743Smax.romanov@nginx.com     req->host_field           = NXT_UNIT_NONE_FIELD;
4582743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
4583743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
4584743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
4585743Smax.romanov@nginx.com 
4586743Smax.romanov@nginx.com     dst_field = req->fields;
4587743Smax.romanov@nginx.com 
4588743Smax.romanov@nginx.com     for (field = nxt_fields_first(h->fields, &iter);
4589743Smax.romanov@nginx.com          field != NULL;
4590743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
4591743Smax.romanov@nginx.com     {
4592743Smax.romanov@nginx.com         if (field->skip) {
4593743Smax.romanov@nginx.com             continue;
4594743Smax.romanov@nginx.com         }
4595743Smax.romanov@nginx.com 
4596743Smax.romanov@nginx.com         dst_field->hash = field->hash;
4597743Smax.romanov@nginx.com         dst_field->skip = 0;
4598743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
4599743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
4600743Smax.romanov@nginx.com 
4601743Smax.romanov@nginx.com         if (field->value == h->host.start) {
4602743Smax.romanov@nginx.com             req->host_field = dst_field - req->fields;
4603743Smax.romanov@nginx.com 
4604743Smax.romanov@nginx.com         } else if (field->value == h->content_length.start) {
4605743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
4606743Smax.romanov@nginx.com 
4607743Smax.romanov@nginx.com         } else if (field->value == h->content_type.start) {
4608743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
4609743Smax.romanov@nginx.com 
4610743Smax.romanov@nginx.com         } else if (field->value == h->cookie.start) {
4611743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
4612743Smax.romanov@nginx.com         }
4613743Smax.romanov@nginx.com 
4614743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
4615743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
4616743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
4617743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
4618743Smax.romanov@nginx.com 
4619743Smax.romanov@nginx.com         if (prefix->length != 0) {
4620743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4621743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
4622743Smax.romanov@nginx.com 
4623743Smax.romanov@nginx.com             end = field->name + field->name_length;
4624743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
4625743Smax.romanov@nginx.com                 c = *pos;
4626743Smax.romanov@nginx.com 
4627743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
4628743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
4629743Smax.romanov@nginx.com                     continue;
4630743Smax.romanov@nginx.com                 }
4631743Smax.romanov@nginx.com 
4632743Smax.romanov@nginx.com                 if (c == '-') {
4633743Smax.romanov@nginx.com                     *p++ = '_';
4634743Smax.romanov@nginx.com                     continue;
4635743Smax.romanov@nginx.com                 }
4636743Smax.romanov@nginx.com 
4637743Smax.romanov@nginx.com                 *p++ = c;
4638743Smax.romanov@nginx.com             }
4639743Smax.romanov@nginx.com 
4640743Smax.romanov@nginx.com         } else {
4641743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4642743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
4643743Smax.romanov@nginx.com         }
4644743Smax.romanov@nginx.com 
4645743Smax.romanov@nginx.com         *p++ = '\0';
4646743Smax.romanov@nginx.com 
4647743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
4648743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
4649743Smax.romanov@nginx.com 
4650743Smax.romanov@nginx.com         if (prefix->length != 0) {
4651743Smax.romanov@nginx.com             dup_iter = iter;
4652743Smax.romanov@nginx.com 
4653743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
4654743Smax.romanov@nginx.com                  dup != NULL;
4655743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
4656743Smax.romanov@nginx.com             {
4657743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
4658743Smax.romanov@nginx.com                     || dup->skip
4659743Smax.romanov@nginx.com                     || dup->hash != field->hash
4660743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
4661743Smax.romanov@nginx.com                 {
4662743Smax.romanov@nginx.com                     continue;
4663743Smax.romanov@nginx.com                 }
4664743Smax.romanov@nginx.com 
4665743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
4666743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
4667743Smax.romanov@nginx.com 
4668743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
4669743Smax.romanov@nginx.com 
4670743Smax.romanov@nginx.com                 dup->skip = 1;
4671743Smax.romanov@nginx.com             }
4672743Smax.romanov@nginx.com         }
4673743Smax.romanov@nginx.com 
4674743Smax.romanov@nginx.com         *p++ = '\0';
4675743Smax.romanov@nginx.com 
4676743Smax.romanov@nginx.com         dst_field++;
4677743Smax.romanov@nginx.com     }
4678743Smax.romanov@nginx.com 
4679743Smax.romanov@nginx.com     req->fields_count = dst_field - req->fields;
4680743Smax.romanov@nginx.com 
4681743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
4682743Smax.romanov@nginx.com 
4683743Smax.romanov@nginx.com     buf = out;
4684743Smax.romanov@nginx.com     tail = &buf->next;
4685216Sigor@sysoev.ru 
4686510Salexander.borisov@nginx.com     for (b = r->body.buf; b != NULL; b = b->next) {
4687743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
4688743Smax.romanov@nginx.com         pos = b->mem.pos;
4689743Smax.romanov@nginx.com 
4690743Smax.romanov@nginx.com         while (size > 0) {
4691743Smax.romanov@nginx.com             if (buf == NULL) {
4692743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
4693743Smax.romanov@nginx.com 
4694743Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, port, free_size);
4695743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
4696743Smax.romanov@nginx.com                     while (out != NULL) {
4697743Smax.romanov@nginx.com                         buf = out->next;
4698743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
4699743Smax.romanov@nginx.com                         out = buf;
4700743Smax.romanov@nginx.com                     }
4701743Smax.romanov@nginx.com                     return NULL;
4702743Smax.romanov@nginx.com                 }
4703743Smax.romanov@nginx.com 
4704743Smax.romanov@nginx.com                 *tail = buf;
4705743Smax.romanov@nginx.com                 tail = &buf->next;
4706743Smax.romanov@nginx.com 
4707743Smax.romanov@nginx.com             } else {
4708743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
4709743Smax.romanov@nginx.com                 if (free_size < size
4710743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
4711743Smax.romanov@nginx.com                        == NXT_OK)
4712743Smax.romanov@nginx.com                 {
4713743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
4714743Smax.romanov@nginx.com                 }
4715743Smax.romanov@nginx.com             }
4716743Smax.romanov@nginx.com 
4717743Smax.romanov@nginx.com             if (free_size > 0) {
4718743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
4719743Smax.romanov@nginx.com 
4720743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
4721743Smax.romanov@nginx.com 
4722743Smax.romanov@nginx.com                 size -= copy_size;
4723743Smax.romanov@nginx.com                 pos += copy_size;
4724743Smax.romanov@nginx.com 
4725743Smax.romanov@nginx.com                 if (size == 0) {
4726743Smax.romanov@nginx.com                     break;
4727743Smax.romanov@nginx.com                 }
4728743Smax.romanov@nginx.com             }
4729743Smax.romanov@nginx.com 
4730743Smax.romanov@nginx.com             buf = NULL;
4731743Smax.romanov@nginx.com         }
4732216Sigor@sysoev.ru     }
4733216Sigor@sysoev.ru 
4734743Smax.romanov@nginx.com     return out;
4735584Salexander.borisov@nginx.com }
4736584Salexander.borisov@nginx.com 
4737584Salexander.borisov@nginx.com 
473853Sigor@sysoev.ru static void
4739318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
4740318Smax.romanov@nginx.com {
4741615Smax.romanov@nginx.com     nxt_app_t                *app;
4742615Smax.romanov@nginx.com     nxt_bool_t               cancelled, unlinked;
4743615Smax.romanov@nginx.com     nxt_port_t               *port;
4744615Smax.romanov@nginx.com     nxt_timer_t              *timer;
4745615Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
4746615Smax.romanov@nginx.com     nxt_req_app_link_t       *pending_ra;
4747615Smax.romanov@nginx.com     nxt_app_parse_ctx_t      *ar;
4748615Smax.romanov@nginx.com     nxt_req_conn_link_t      *rc;
4749615Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4750318Smax.romanov@nginx.com 
4751318Smax.romanov@nginx.com     timer = obj;
4752318Smax.romanov@nginx.com 
4753318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
4754318Smax.romanov@nginx.com 
4755431Sigor@sysoev.ru     ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
4756615Smax.romanov@nginx.com     rc = ar->timer_data;
4757615Smax.romanov@nginx.com     app = rc->app;
4758615Smax.romanov@nginx.com 
4759615Smax.romanov@nginx.com     if (app == NULL) {
4760615Smax.romanov@nginx.com         goto generate_error;
4761615Smax.romanov@nginx.com     }
4762615Smax.romanov@nginx.com 
4763615Smax.romanov@nginx.com     port = NULL;
4764615Smax.romanov@nginx.com     pending_ra = NULL;
4765615Smax.romanov@nginx.com 
4766615Smax.romanov@nginx.com     if (rc->app_port != NULL) {
4767615Smax.romanov@nginx.com         port = rc->app_port;
4768615Smax.romanov@nginx.com         rc->app_port = NULL;
4769615Smax.romanov@nginx.com     }
4770615Smax.romanov@nginx.com 
4771615Smax.romanov@nginx.com     if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) {
4772615Smax.romanov@nginx.com         port = rc->ra->app_port;
4773615Smax.romanov@nginx.com         rc->ra->app_port = NULL;
4774615Smax.romanov@nginx.com     }
4775615Smax.romanov@nginx.com 
4776615Smax.romanov@nginx.com     if (port == NULL) {
4777615Smax.romanov@nginx.com         goto generate_error;
4778431Sigor@sysoev.ru     }
4779615Smax.romanov@nginx.com 
4780615Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4781615Smax.romanov@nginx.com 
4782615Smax.romanov@nginx.com     unlinked = nxt_queue_chk_remove(&port->app_link);
4783615Smax.romanov@nginx.com 
4784615Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&port->pending_requests)) {
4785615Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
4786615Smax.romanov@nginx.com 
4787615Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t,
4788615Smax.romanov@nginx.com                                          link_port_pending);
4789615Smax.romanov@nginx.com 
4790615Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
4791615Smax.romanov@nginx.com 
4792615Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pending request #%uD found",
4793615Smax.romanov@nginx.com                   &app->name, pending_ra->stream);
4794615Smax.romanov@nginx.com 
4795615Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info,
4796615Smax.romanov@nginx.com                                           pending_ra->stream);
4797615Smax.romanov@nginx.com 
4798615Smax.romanov@nginx.com         if (cancelled) {
4799615Smax.romanov@nginx.com             nxt_router_ra_inc_use(pending_ra);
4800615Smax.romanov@nginx.com 
4801615Smax.romanov@nginx.com             state.ra = pending_ra;
4802615Smax.romanov@nginx.com             state.app = app;
4803615Smax.romanov@nginx.com 
4804615Smax.romanov@nginx.com             nxt_router_port_select(task, &state);
4805615Smax.romanov@nginx.com 
4806615Smax.romanov@nginx.com         } else {
4807615Smax.romanov@nginx.com             pending_ra = NULL;
4808615Smax.romanov@nginx.com         }
4809615Smax.romanov@nginx.com     }
4810615Smax.romanov@nginx.com 
4811615Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4812615Smax.romanov@nginx.com 
4813615Smax.romanov@nginx.com     if (pending_ra != NULL
4814615Smax.romanov@nginx.com         && nxt_router_port_post_select(task, &state) == NXT_OK)
4815615Smax.romanov@nginx.com     {
4816615Smax.romanov@nginx.com         nxt_router_app_prepare_request(task, pending_ra);
4817615Smax.romanov@nginx.com     }
4818615Smax.romanov@nginx.com 
4819615Smax.romanov@nginx.com     nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid);
4820615Smax.romanov@nginx.com 
4821615Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4822615Smax.romanov@nginx.com 
4823615Smax.romanov@nginx.com     nxt_port_use(task, port, unlinked ? -2 : -1);
4824615Smax.romanov@nginx.com 
4825615Smax.romanov@nginx.com generate_error:
4826615Smax.romanov@nginx.com 
4827615Smax.romanov@nginx.com     nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE);
4828615Smax.romanov@nginx.com 
4829615Smax.romanov@nginx.com     nxt_router_rc_unlink(task, rc);
4830318Smax.romanov@nginx.com }
4831