xref: /unit/src/nxt_router.c (revision 1459)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
853Sigor@sysoev.ru #include <nxt_router.h>
9115Sigor@sysoev.ru #include <nxt_conf.h>
10774Svbart@nginx.com #if (NXT_TLS)
11774Svbart@nginx.com #include <nxt_cert.h>
12774Svbart@nginx.com #endif
13431Sigor@sysoev.ru #include <nxt_http.h>
14743Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
15743Smax.romanov@nginx.com #include <nxt_unit_request.h>
16743Smax.romanov@nginx.com #include <nxt_unit_response.h>
171131Smax.romanov@nginx.com #include <nxt_router_request.h>
1820Sigor@sysoev.ru 
19115Sigor@sysoev.ru typedef struct {
20318Smax.romanov@nginx.com     nxt_str_t         type;
21507Smax.romanov@nginx.com     uint32_t          processes;
22507Smax.romanov@nginx.com     uint32_t          max_processes;
23507Smax.romanov@nginx.com     uint32_t          spare_processes;
24318Smax.romanov@nginx.com     nxt_msec_t        timeout;
25427Smax.romanov@nginx.com     nxt_msec_t        res_timeout;
26507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
27318Smax.romanov@nginx.com     uint32_t          requests;
28318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
29507Smax.romanov@nginx.com     nxt_conf_value_t  *processes_value;
30133Sigor@sysoev.ru } nxt_router_app_conf_t;
31133Sigor@sysoev.ru 
32133Sigor@sysoev.ru 
33133Sigor@sysoev.ru typedef struct {
34964Sigor@sysoev.ru     nxt_str_t         pass;
35964Sigor@sysoev.ru     nxt_str_t         application;
36115Sigor@sysoev.ru } nxt_router_listener_conf_t;
37115Sigor@sysoev.ru 
38115Sigor@sysoev.ru 
39774Svbart@nginx.com #if (NXT_TLS)
40774Svbart@nginx.com 
41774Svbart@nginx.com typedef struct {
42774Svbart@nginx.com     nxt_str_t          name;
43774Svbart@nginx.com     nxt_socket_conf_t  *conf;
44774Svbart@nginx.com 
45774Svbart@nginx.com     nxt_queue_link_t   link;  /* for nxt_socket_conf_t.tls */
46774Svbart@nginx.com } nxt_router_tlssock_t;
47774Svbart@nginx.com 
48774Svbart@nginx.com #endif
49774Svbart@nginx.com 
50774Svbart@nginx.com 
51198Sigor@sysoev.ru typedef struct {
52198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
53198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
54198Sigor@sysoev.ru } nxt_socket_rpc_t;
55198Sigor@sysoev.ru 
56198Sigor@sysoev.ru 
57507Smax.romanov@nginx.com typedef struct {
58507Smax.romanov@nginx.com     nxt_app_t               *app;
59507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
60507Smax.romanov@nginx.com } nxt_app_rpc_t;
61507Smax.romanov@nginx.com 
62507Smax.romanov@nginx.com 
63427Smax.romanov@nginx.com struct nxt_port_select_state_s {
641123Smax.romanov@nginx.com     nxt_app_t               *app;
651123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
661123Smax.romanov@nginx.com 
671123Smax.romanov@nginx.com     nxt_port_t              *failed_port;
681123Smax.romanov@nginx.com     int                     failed_port_use_delta;
691123Smax.romanov@nginx.com 
701123Smax.romanov@nginx.com     uint8_t                 start_process;    /* 1 bit */
711123Smax.romanov@nginx.com     nxt_request_app_link_t  *shared_ra;
721123Smax.romanov@nginx.com     nxt_port_t              *port;
73427Smax.romanov@nginx.com };
74427Smax.romanov@nginx.com 
75427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t;
76427Smax.romanov@nginx.com 
77662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task,
78662Smax.romanov@nginx.com     nxt_port_t *controller_port);
79662Smax.romanov@nginx.com 
80427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task,
81427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
82427Smax.romanov@nginx.com 
83427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task,
84427Smax.romanov@nginx.com     nxt_port_select_state_t *state);
85427Smax.romanov@nginx.com 
86507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
871123Smax.romanov@nginx.com static void nxt_request_app_link_update_peer(nxt_task_t *task,
881123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link);
891123Smax.romanov@nginx.com 
90343Smax.romanov@nginx.com 
91425Smax.romanov@nginx.com nxt_inline void
921123Smax.romanov@nginx.com nxt_request_app_link_inc_use(nxt_request_app_link_t *req_app_link)
93425Smax.romanov@nginx.com {
941123Smax.romanov@nginx.com     nxt_atomic_fetch_add(&req_app_link->use_count, 1);
95425Smax.romanov@nginx.com }
96425Smax.romanov@nginx.com 
97425Smax.romanov@nginx.com nxt_inline void
981294Smax.romanov@nginx.com nxt_request_app_link_chk_use(nxt_request_app_link_t *req_app_link, int i)
99425Smax.romanov@nginx.com {
100538Svbart@nginx.com #if (NXT_DEBUG)
101425Smax.romanov@nginx.com     int  c;
102425Smax.romanov@nginx.com 
1031294Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&req_app_link->use_count, i);
1041294Smax.romanov@nginx.com 
1051294Smax.romanov@nginx.com     nxt_assert((c + i) > 0);
106538Svbart@nginx.com #else
1071294Smax.romanov@nginx.com     (void) nxt_atomic_fetch_add(&req_app_link->use_count, i);
108538Svbart@nginx.com #endif
109425Smax.romanov@nginx.com }
110425Smax.romanov@nginx.com 
1111123Smax.romanov@nginx.com static void nxt_request_app_link_use(nxt_task_t *task,
1121123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link, int i);
113425Smax.romanov@nginx.com 
114139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
115198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
116198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
117139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
118139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
119139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
120139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
121193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
12253Sigor@sysoev.ru 
123115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
124115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
1251183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
1261183Svbart@nginx.com     nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
127133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
128198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
129198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
130198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
131198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
132198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
133198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
134774Svbart@nginx.com #if (NXT_TLS)
135774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task,
136774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls);
137774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task,
138774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
139774Svbart@nginx.com #endif
140507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
141507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
142507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
143507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
144507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
145507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
146359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
147359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
148359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
149359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
15053Sigor@sysoev.ru 
15153Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
15253Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
15353Sigor@sysoev.ru     const nxt_event_interface_t *interface);
154115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
155115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
156115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
157115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
158115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
159115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
160154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
161154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
162154Sigor@sysoev.ru     nxt_work_handler_t handler);
163313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
164313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
165139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
166139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
16753Sigor@sysoev.ru 
16853Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
16953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
17053Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
17153Sigor@sysoev.ru     nxt_event_engine_t *engine);
172343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
173133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
17453Sigor@sysoev.ru 
175315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
176315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
177315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
178315Sigor@sysoev.ru     nxt_work_t *jobs);
17953Sigor@sysoev.ru 
18053Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
18153Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
18253Sigor@sysoev.ru     void *data);
18353Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
18453Sigor@sysoev.ru     void *data);
18553Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
18653Sigor@sysoev.ru     void *data);
187313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
188313Sigor@sysoev.ru     void *data);
18953Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
19053Sigor@sysoev.ru     void *data);
19153Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
19253Sigor@sysoev.ru     void *data);
193359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
194359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
19553Sigor@sysoev.ru 
196630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task,
197630Svbart@nginx.com     nxt_http_request_t *r, nxt_router_access_log_t *access_log);
198630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
199630Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
200630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task,
201630Svbart@nginx.com     nxt_router_temp_conf_t *tmcf);
202630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task,
203630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
204630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task,
205630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
206630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task,
207630Svbart@nginx.com     nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
208651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
209651Svbart@nginx.com     void *data);
210631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
211631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
212631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task,
213631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
214630Svbart@nginx.com 
215343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
216343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
217343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
218343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
219343Smax.romanov@nginx.com 
220753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
2211123Smax.romanov@nginx.com 
222343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
2231123Smax.romanov@nginx.com     nxt_apr_action_t action);
224427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
2251123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link);
226141Smax.romanov@nginx.com 
227425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
2281123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link);
2291007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
2301007Salexander.borisov@nginx.com     nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix);
231510Salexander.borisov@nginx.com 
232318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
233507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
234507Smax.romanov@nginx.com     void *data);
235507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
236507Smax.romanov@nginx.com     void *data);
237753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
238507Smax.romanov@nginx.com     void *data);
239753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
240431Sigor@sysoev.ru 
241431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
242431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
243141Smax.romanov@nginx.com 
244753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task,
245753Smax.romanov@nginx.com     nxt_app_joint_t *app_joint, int i);
246753Smax.romanov@nginx.com 
2471007Salexander.borisov@nginx.com static nxt_int_t nxt_router_http_request_done(nxt_task_t *task,
2481007Salexander.borisov@nginx.com     nxt_http_request_t *r);
2491007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
2501007Salexander.borisov@nginx.com     void *data);
2511321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
2521007Salexander.borisov@nginx.com 
2531149Smax.romanov@nginx.com extern const nxt_http_request_state_t  nxt_http_websocket;
2541131Smax.romanov@nginx.com 
255119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
25620Sigor@sysoev.ru 
257743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
258743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
259743Smax.romanov@nginx.com 
260743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
261804Svbart@nginx.com     &empty_prefix,
262743Smax.romanov@nginx.com     &http_prefix,
263743Smax.romanov@nginx.com     &http_prefix,
264743Smax.romanov@nginx.com     &http_prefix,
265743Smax.romanov@nginx.com     &http_prefix,
266977Smax.romanov@gmail.com     &empty_prefix,
267216Sigor@sysoev.ru };
268216Sigor@sysoev.ru 
269216Sigor@sysoev.ru 
270662Smax.romanov@nginx.com nxt_port_handlers_t  nxt_router_process_port_handlers = {
271662Smax.romanov@nginx.com     .quit         = nxt_worker_process_quit_handler,
272662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
273662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
274662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
275662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
276662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
277662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
278662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
279662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
2801321Smax.romanov@nginx.com     .oosm         = nxt_router_oosm_handler,
281662Smax.romanov@nginx.com };
282662Smax.romanov@nginx.com 
283662Smax.romanov@nginx.com 
28420Sigor@sysoev.ru nxt_int_t
285141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
28620Sigor@sysoev.ru {
287141Smax.romanov@nginx.com     nxt_int_t      ret;
288662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
289141Smax.romanov@nginx.com     nxt_router_t   *router;
290141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
291141Smax.romanov@nginx.com 
292141Smax.romanov@nginx.com     rt = task->thread->runtime;
29353Sigor@sysoev.ru 
294771Sigor@sysoev.ru #if (NXT_TLS)
295771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
296771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
297771Sigor@sysoev.ru         return NXT_ERROR;
298771Sigor@sysoev.ru     }
299771Sigor@sysoev.ru 
300771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
301771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
302771Sigor@sysoev.ru         return ret;
303771Sigor@sysoev.ru     }
304771Sigor@sysoev.ru #endif
305771Sigor@sysoev.ru 
306*1459Smax.romanov@nginx.com     ret = nxt_http_init(task);
30788Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
30888Smax.romanov@nginx.com         return ret;
30988Smax.romanov@nginx.com     }
31088Smax.romanov@nginx.com 
31153Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
31253Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
31353Sigor@sysoev.ru         return NXT_ERROR;
31453Sigor@sysoev.ru     }
31553Sigor@sysoev.ru 
31653Sigor@sysoev.ru     nxt_queue_init(&router->engines);
31753Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
318133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
31953Sigor@sysoev.ru 
320119Smax.romanov@nginx.com     nxt_router = router;
321119Smax.romanov@nginx.com 
322662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
323662Smax.romanov@nginx.com     if (controller_port != NULL) {
324662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
325662Smax.romanov@nginx.com     }
326662Smax.romanov@nginx.com 
327115Sigor@sysoev.ru     return NXT_OK;
328115Sigor@sysoev.ru }
329115Sigor@sysoev.ru 
330115Sigor@sysoev.ru 
331343Smax.romanov@nginx.com static void
332662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
333662Smax.romanov@nginx.com {
334662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
335662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
336662Smax.romanov@nginx.com }
337662Smax.romanov@nginx.com 
338662Smax.romanov@nginx.com 
339662Smax.romanov@nginx.com static void
340507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
341507Smax.romanov@nginx.com     void *data)
342167Smax.romanov@nginx.com {
343343Smax.romanov@nginx.com     size_t         size;
344343Smax.romanov@nginx.com     uint32_t       stream;
345430Sigor@sysoev.ru     nxt_mp_t       *mp;
346648Svbart@nginx.com     nxt_int_t      ret;
347343Smax.romanov@nginx.com     nxt_app_t      *app;
348343Smax.romanov@nginx.com     nxt_buf_t      *b;
349343Smax.romanov@nginx.com     nxt_port_t     *main_port;
350343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
351343Smax.romanov@nginx.com 
352343Smax.romanov@nginx.com     app = data;
353167Smax.romanov@nginx.com 
354167Smax.romanov@nginx.com     rt = task->thread->runtime;
355240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
356167Smax.romanov@nginx.com 
357507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
358343Smax.romanov@nginx.com 
359343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
360343Smax.romanov@nginx.com 
361343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
362343Smax.romanov@nginx.com 
363343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
364343Smax.romanov@nginx.com         goto failed;
365167Smax.romanov@nginx.com     }
366167Smax.romanov@nginx.com 
367343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
368343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
369343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
370343Smax.romanov@nginx.com 
371753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
372753Smax.romanov@nginx.com 
373343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
374343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
375343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
376753Smax.romanov@nginx.com                                            -1, app->joint);
377343Smax.romanov@nginx.com 
378343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
379753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
380753Smax.romanov@nginx.com 
381343Smax.romanov@nginx.com         goto failed;
382343Smax.romanov@nginx.com     }
383343Smax.romanov@nginx.com 
384648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
385648Svbart@nginx.com                                 stream, port->id, b);
386648Svbart@nginx.com 
387648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
388648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
389753Smax.romanov@nginx.com 
390753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
391753Smax.romanov@nginx.com 
392648Svbart@nginx.com         goto failed;
393648Svbart@nginx.com     }
394343Smax.romanov@nginx.com 
395753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
396753Smax.romanov@nginx.com 
397343Smax.romanov@nginx.com     return;
398343Smax.romanov@nginx.com 
399343Smax.romanov@nginx.com failed:
400343Smax.romanov@nginx.com 
401648Svbart@nginx.com     if (b != NULL) {
402648Svbart@nginx.com         mp = b->data;
403648Svbart@nginx.com         nxt_mp_free(mp, b);
404648Svbart@nginx.com         nxt_mp_release(mp);
405648Svbart@nginx.com     }
406648Svbart@nginx.com 
407343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
408343Smax.romanov@nginx.com 
409507Smax.romanov@nginx.com     app->pending_processes--;
410343Smax.romanov@nginx.com 
411343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
412343Smax.romanov@nginx.com 
413343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
414167Smax.romanov@nginx.com }
415167Smax.romanov@nginx.com 
416167Smax.romanov@nginx.com 
417753Smax.romanov@nginx.com static void
418753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
419753Smax.romanov@nginx.com {
420753Smax.romanov@nginx.com     app_joint->use_count += i;
421753Smax.romanov@nginx.com 
422753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
423753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
424753Smax.romanov@nginx.com 
425753Smax.romanov@nginx.com         nxt_free(app_joint);
426753Smax.romanov@nginx.com     }
427753Smax.romanov@nginx.com }
428753Smax.romanov@nginx.com 
429753Smax.romanov@nginx.com 
430343Smax.romanov@nginx.com static nxt_int_t
431507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
432141Smax.romanov@nginx.com {
433343Smax.romanov@nginx.com     nxt_int_t      res;
434343Smax.romanov@nginx.com     nxt_port_t     *router_port;
435343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
436343Smax.romanov@nginx.com 
437343Smax.romanov@nginx.com     rt = task->thread->runtime;
438343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
439343Smax.romanov@nginx.com 
440343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
441343Smax.romanov@nginx.com 
442507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
443343Smax.romanov@nginx.com                         app);
444343Smax.romanov@nginx.com 
445343Smax.romanov@nginx.com     if (res == NXT_OK) {
446343Smax.romanov@nginx.com         return res;
447318Smax.romanov@nginx.com     }
448318Smax.romanov@nginx.com 
449343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
450343Smax.romanov@nginx.com 
451507Smax.romanov@nginx.com     app->pending_processes--;
452343Smax.romanov@nginx.com 
453343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
454343Smax.romanov@nginx.com 
455343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
456343Smax.romanov@nginx.com 
457343Smax.romanov@nginx.com     return NXT_ERROR;
458318Smax.romanov@nginx.com }
459318Smax.romanov@nginx.com 
460318Smax.romanov@nginx.com 
461351Smax.romanov@nginx.com nxt_inline void
4621123Smax.romanov@nginx.com nxt_request_app_link_init(nxt_task_t *task,
4631123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link, nxt_request_rpc_data_t *req_rpc_data)
464167Smax.romanov@nginx.com {
4651414Smax.romanov@nginx.com     nxt_buf_t           *body;
466318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
467351Smax.romanov@nginx.com 
468318Smax.romanov@nginx.com     engine = task->thread->engine;
469167Smax.romanov@nginx.com 
4701123Smax.romanov@nginx.com     nxt_memzero(req_app_link, sizeof(nxt_request_app_link_t));
4711123Smax.romanov@nginx.com 
4721123Smax.romanov@nginx.com     req_app_link->stream = req_rpc_data->stream;
4731123Smax.romanov@nginx.com     req_app_link->use_count = 1;
4741123Smax.romanov@nginx.com     req_app_link->req_rpc_data = req_rpc_data;
4751123Smax.romanov@nginx.com     req_rpc_data->req_app_link = req_app_link;
4761123Smax.romanov@nginx.com     req_app_link->reply_port = engine->port;
4771123Smax.romanov@nginx.com     req_app_link->request = req_rpc_data->request;
4781123Smax.romanov@nginx.com     req_app_link->apr_action = NXT_APR_GOT_RESPONSE;
4791123Smax.romanov@nginx.com 
4801123Smax.romanov@nginx.com     req_app_link->work.handler = NULL;
4811123Smax.romanov@nginx.com     req_app_link->work.task = &engine->task;
4821123Smax.romanov@nginx.com     req_app_link->work.obj = req_app_link;
4831123Smax.romanov@nginx.com     req_app_link->work.data = engine;
4841414Smax.romanov@nginx.com 
4851414Smax.romanov@nginx.com     body = req_rpc_data->request->body;
4861414Smax.romanov@nginx.com 
4871414Smax.romanov@nginx.com     if (body != NULL && nxt_buf_is_file(body)) {
4881414Smax.romanov@nginx.com         req_app_link->body_fd = body->file->fd;
4891414Smax.romanov@nginx.com 
4901414Smax.romanov@nginx.com         body->file->fd = -1;
4911414Smax.romanov@nginx.com 
4921414Smax.romanov@nginx.com     } else {
4931414Smax.romanov@nginx.com         req_app_link->body_fd = -1;
4941414Smax.romanov@nginx.com     }
495351Smax.romanov@nginx.com }
496351Smax.romanov@nginx.com 
497351Smax.romanov@nginx.com 
4981123Smax.romanov@nginx.com nxt_inline nxt_request_app_link_t *
4991123Smax.romanov@nginx.com nxt_request_app_link_alloc(nxt_task_t *task,
5001123Smax.romanov@nginx.com     nxt_request_app_link_t *ra_src, nxt_request_rpc_data_t *req_rpc_data)
501351Smax.romanov@nginx.com {
5021123Smax.romanov@nginx.com     nxt_mp_t                *mp;
5031123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
5041123Smax.romanov@nginx.com 
5051123Smax.romanov@nginx.com     if (ra_src != NULL && ra_src->mem_pool != NULL) {
506425Smax.romanov@nginx.com         return ra_src;
507425Smax.romanov@nginx.com     }
508425Smax.romanov@nginx.com 
5091123Smax.romanov@nginx.com     mp = req_rpc_data->request->mem_pool;
5101123Smax.romanov@nginx.com 
5111123Smax.romanov@nginx.com     req_app_link = nxt_mp_alloc(mp, sizeof(nxt_request_app_link_t));
5121123Smax.romanov@nginx.com 
5131123Smax.romanov@nginx.com     if (nxt_slow_path(req_app_link == NULL)) {
5141123Smax.romanov@nginx.com 
5151123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
5161123Smax.romanov@nginx.com 
5171123Smax.romanov@nginx.com         if (ra_src != NULL) {
5181123Smax.romanov@nginx.com             ra_src->req_rpc_data = NULL;
5191123Smax.romanov@nginx.com         }
520351Smax.romanov@nginx.com 
521351Smax.romanov@nginx.com         return NULL;
522351Smax.romanov@nginx.com     }
523351Smax.romanov@nginx.com 
524430Sigor@sysoev.ru     nxt_mp_retain(mp);
525430Sigor@sysoev.ru 
5261123Smax.romanov@nginx.com     nxt_request_app_link_init(task, req_app_link, req_rpc_data);
5271123Smax.romanov@nginx.com 
5281414Smax.romanov@nginx.com     if (ra_src != NULL) {
5291414Smax.romanov@nginx.com         req_app_link->body_fd = ra_src->body_fd;
5301414Smax.romanov@nginx.com     }
5311414Smax.romanov@nginx.com 
5321123Smax.romanov@nginx.com     req_app_link->mem_pool = mp;
5331123Smax.romanov@nginx.com 
5341123Smax.romanov@nginx.com     return req_app_link;
535167Smax.romanov@nginx.com }
536167Smax.romanov@nginx.com 
537167Smax.romanov@nginx.com 
538423Smax.romanov@nginx.com nxt_inline nxt_bool_t
539423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
540423Smax.romanov@nginx.com     uint32_t stream)
541423Smax.romanov@nginx.com {
542423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
543423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
544423Smax.romanov@nginx.com 
545423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
546423Smax.romanov@nginx.com         return 0;
547423Smax.romanov@nginx.com     }
548423Smax.romanov@nginx.com 
549423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
550423Smax.romanov@nginx.com                                               stream);
551423Smax.romanov@nginx.com 
552423Smax.romanov@nginx.com     if (cancelled) {
553423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
554423Smax.romanov@nginx.com     }
555423Smax.romanov@nginx.com 
556423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
557423Smax.romanov@nginx.com         next = b->next;
5581269Sigor@sysoev.ru         b->next = NULL;
559423Smax.romanov@nginx.com 
560423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
561423Smax.romanov@nginx.com 
562423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
563423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
564423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
565423Smax.romanov@nginx.com         }
566423Smax.romanov@nginx.com     }
567423Smax.romanov@nginx.com 
568423Smax.romanov@nginx.com     msg_info->buf = NULL;
569423Smax.romanov@nginx.com 
570423Smax.romanov@nginx.com     return cancelled;
571423Smax.romanov@nginx.com }
572423Smax.romanov@nginx.com 
573423Smax.romanov@nginx.com 
574167Smax.romanov@nginx.com static void
5751123Smax.romanov@nginx.com nxt_request_app_link_update_peer_handler(nxt_task_t *task, void *obj,
5761123Smax.romanov@nginx.com     void *data)
5771123Smax.romanov@nginx.com {
5781123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
5791123Smax.romanov@nginx.com 
5801123Smax.romanov@nginx.com     req_app_link = obj;
5811123Smax.romanov@nginx.com 
5821123Smax.romanov@nginx.com     nxt_request_app_link_update_peer(task, req_app_link);
5831123Smax.romanov@nginx.com 
5841123Smax.romanov@nginx.com     nxt_request_app_link_use(task, req_app_link, -1);
5851123Smax.romanov@nginx.com }
586425Smax.romanov@nginx.com 
587425Smax.romanov@nginx.com 
588425Smax.romanov@nginx.com static void
5891123Smax.romanov@nginx.com nxt_request_app_link_update_peer(nxt_task_t *task,
5901123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
591167Smax.romanov@nginx.com {
5921123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
5931123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
5941123Smax.romanov@nginx.com 
5951123Smax.romanov@nginx.com     engine = req_app_link->work.data;
5961123Smax.romanov@nginx.com 
5971123Smax.romanov@nginx.com     if (task->thread->engine != engine) {
5981123Smax.romanov@nginx.com         nxt_request_app_link_inc_use(req_app_link);
5991123Smax.romanov@nginx.com 
6001123Smax.romanov@nginx.com         req_app_link->work.handler = nxt_request_app_link_update_peer_handler;
6011123Smax.romanov@nginx.com         req_app_link->work.task = &engine->task;
6021123Smax.romanov@nginx.com         req_app_link->work.next = NULL;
6031123Smax.romanov@nginx.com 
6041123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD post update peer to %p",
6051123Smax.romanov@nginx.com                   req_app_link->stream, engine);
6061123Smax.romanov@nginx.com 
6071123Smax.romanov@nginx.com         nxt_event_engine_post(engine, &req_app_link->work);
6081123Smax.romanov@nginx.com 
6091123Smax.romanov@nginx.com         return;
6101123Smax.romanov@nginx.com     }
6111123Smax.romanov@nginx.com 
6121123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD update peer",
6131123Smax.romanov@nginx.com               req_app_link->stream);
6141123Smax.romanov@nginx.com 
6151123Smax.romanov@nginx.com     req_rpc_data = req_app_link->req_rpc_data;
6161123Smax.romanov@nginx.com 
6171123Smax.romanov@nginx.com     if (req_rpc_data != NULL && req_app_link->app_port != NULL) {
6181123Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data,
6191123Smax.romanov@nginx.com                                  req_app_link->app_port->pid);
6201123Smax.romanov@nginx.com     }
621425Smax.romanov@nginx.com }
622425Smax.romanov@nginx.com 
623425Smax.romanov@nginx.com 
624425Smax.romanov@nginx.com static void
6251123Smax.romanov@nginx.com nxt_request_app_link_release(nxt_task_t *task,
6261123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
627425Smax.romanov@nginx.com {
628431Sigor@sysoev.ru     nxt_mp_t                *mp;
6291131Smax.romanov@nginx.com     nxt_http_request_t      *r;
6301123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
6311123Smax.romanov@nginx.com 
6321123Smax.romanov@nginx.com     nxt_assert(task->thread->engine == req_app_link->work.data);
6331123Smax.romanov@nginx.com     nxt_assert(req_app_link->use_count == 0);
6341123Smax.romanov@nginx.com 
6351123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD release", req_app_link->stream);
6361123Smax.romanov@nginx.com 
6371123Smax.romanov@nginx.com     req_rpc_data = req_app_link->req_rpc_data;
6381123Smax.romanov@nginx.com 
6391123Smax.romanov@nginx.com     if (req_rpc_data != NULL) {
6401123Smax.romanov@nginx.com         if (nxt_slow_path(req_app_link->err_code != 0)) {
6411123Smax.romanov@nginx.com             nxt_http_request_error(task, req_rpc_data->request,
6421123Smax.romanov@nginx.com                                    req_app_link->err_code);
643423Smax.romanov@nginx.com 
644423Smax.romanov@nginx.com         } else {
6451123Smax.romanov@nginx.com             req_rpc_data->app_port = req_app_link->app_port;
6461123Smax.romanov@nginx.com             req_rpc_data->apr_action = req_app_link->apr_action;
6471123Smax.romanov@nginx.com             req_rpc_data->msg_info = req_app_link->msg_info;
6481123Smax.romanov@nginx.com 
6491123Smax.romanov@nginx.com             if (req_rpc_data->app->timeout != 0) {
6501131Smax.romanov@nginx.com                 r = req_rpc_data->request;
6511131Smax.romanov@nginx.com 
6521131Smax.romanov@nginx.com                 r->timer.handler = nxt_router_app_timeout;
6531131Smax.romanov@nginx.com                 r->timer_data = req_rpc_data;
6541131Smax.romanov@nginx.com                 nxt_timer_add(task->thread->engine, &r->timer,
6551123Smax.romanov@nginx.com                               req_rpc_data->app->timeout);
656425Smax.romanov@nginx.com             }
657425Smax.romanov@nginx.com 
6581123Smax.romanov@nginx.com             req_app_link->app_port = NULL;
6591123Smax.romanov@nginx.com             req_app_link->msg_info.buf = NULL;
660423Smax.romanov@nginx.com         }
661343Smax.romanov@nginx.com 
6621123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
6631123Smax.romanov@nginx.com         req_app_link->req_rpc_data = NULL;
6641123Smax.romanov@nginx.com     }
6651123Smax.romanov@nginx.com 
6661123Smax.romanov@nginx.com     if (req_app_link->app_port != NULL) {
6671123Smax.romanov@nginx.com         nxt_router_app_port_release(task, req_app_link->app_port,
6681123Smax.romanov@nginx.com                                     req_app_link->apr_action);
6691123Smax.romanov@nginx.com 
6701123Smax.romanov@nginx.com         req_app_link->app_port = NULL;
6711123Smax.romanov@nginx.com     }
6721123Smax.romanov@nginx.com 
6731414Smax.romanov@nginx.com     if (req_app_link->body_fd != -1) {
6741414Smax.romanov@nginx.com         nxt_fd_close(req_app_link->body_fd);
6751414Smax.romanov@nginx.com 
6761414Smax.romanov@nginx.com         req_app_link->body_fd = -1;
6771414Smax.romanov@nginx.com     }
6781414Smax.romanov@nginx.com 
6791123Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &req_app_link->msg_info, req_app_link->stream);
6801123Smax.romanov@nginx.com 
6811123Smax.romanov@nginx.com     mp = req_app_link->mem_pool;
682430Sigor@sysoev.ru 
683430Sigor@sysoev.ru     if (mp != NULL) {
6841123Smax.romanov@nginx.com         nxt_mp_free(mp, req_app_link);
685430Sigor@sysoev.ru         nxt_mp_release(mp);
686351Smax.romanov@nginx.com     }
687167Smax.romanov@nginx.com }
688167Smax.romanov@nginx.com 
689167Smax.romanov@nginx.com 
690425Smax.romanov@nginx.com static void
6911123Smax.romanov@nginx.com nxt_request_app_link_release_handler(nxt_task_t *task, void *obj, void *data)
692425Smax.romanov@nginx.com {
6931123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
6941123Smax.romanov@nginx.com 
6951123Smax.romanov@nginx.com     req_app_link = obj;
6961123Smax.romanov@nginx.com 
6971123Smax.romanov@nginx.com     nxt_assert(req_app_link->work.data == data);
6981123Smax.romanov@nginx.com 
6991123Smax.romanov@nginx.com     nxt_atomic_fetch_add(&req_app_link->use_count, -1);
7001123Smax.romanov@nginx.com 
7011123Smax.romanov@nginx.com     nxt_request_app_link_release(task, req_app_link);
702425Smax.romanov@nginx.com }
703425Smax.romanov@nginx.com 
704425Smax.romanov@nginx.com 
705425Smax.romanov@nginx.com static void
7061123Smax.romanov@nginx.com nxt_request_app_link_use(nxt_task_t *task, nxt_request_app_link_t *req_app_link,
7071123Smax.romanov@nginx.com     int i)
708425Smax.romanov@nginx.com {
709425Smax.romanov@nginx.com     int                 c;
710425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
711425Smax.romanov@nginx.com 
7121123Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&req_app_link->use_count, i);
713425Smax.romanov@nginx.com 
714425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
7151123Smax.romanov@nginx.com         engine = req_app_link->work.data;
716425Smax.romanov@nginx.com 
717425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
7181123Smax.romanov@nginx.com             nxt_request_app_link_release(task, req_app_link);
719425Smax.romanov@nginx.com 
720425Smax.romanov@nginx.com             return;
721425Smax.romanov@nginx.com         }
722425Smax.romanov@nginx.com 
7231123Smax.romanov@nginx.com         nxt_request_app_link_inc_use(req_app_link);
7241123Smax.romanov@nginx.com 
7251123Smax.romanov@nginx.com         req_app_link->work.handler = nxt_request_app_link_release_handler;
7261123Smax.romanov@nginx.com         req_app_link->work.task = &engine->task;
7271123Smax.romanov@nginx.com         req_app_link->work.next = NULL;
7281123Smax.romanov@nginx.com 
7291123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD post release to %p",
7301123Smax.romanov@nginx.com                   req_app_link->stream, engine);
7311123Smax.romanov@nginx.com 
7321123Smax.romanov@nginx.com         nxt_event_engine_post(engine, &req_app_link->work);
733425Smax.romanov@nginx.com     }
734425Smax.romanov@nginx.com }
735425Smax.romanov@nginx.com 
736425Smax.romanov@nginx.com 
737423Smax.romanov@nginx.com nxt_inline void
7381446Smax.romanov@nginx.com nxt_request_app_link_error(nxt_task_t *task, nxt_app_t *app,
7391446Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link, const char *str)
740345Smax.romanov@nginx.com {
7411123Smax.romanov@nginx.com     req_app_link->app_port = NULL;
7421446Smax.romanov@nginx.com     req_app_link->err_code = 500;
7431123Smax.romanov@nginx.com     req_app_link->err_str = str;
7441446Smax.romanov@nginx.com 
7451446Smax.romanov@nginx.com     nxt_alert(task, "app \"%V\" internal error: %s on #%uD",
7461446Smax.romanov@nginx.com               &app->name, str, req_app_link->stream);
747345Smax.romanov@nginx.com }
748345Smax.romanov@nginx.com 
749345Smax.romanov@nginx.com 
750427Smax.romanov@nginx.com nxt_inline void
7511123Smax.romanov@nginx.com nxt_request_app_link_pending(nxt_task_t *task, nxt_app_t *app,
7521123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
753427Smax.romanov@nginx.com {
7541123Smax.romanov@nginx.com     nxt_queue_insert_tail(&req_app_link->app_port->pending_requests,
7551123Smax.romanov@nginx.com                           &req_app_link->link_port_pending);
7561123Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &req_app_link->link_app_pending);
7571123Smax.romanov@nginx.com 
7581123Smax.romanov@nginx.com     nxt_request_app_link_inc_use(req_app_link);
7591123Smax.romanov@nginx.com 
7601123Smax.romanov@nginx.com     req_app_link->res_time = nxt_thread_monotonic_time(task->thread)
7611123Smax.romanov@nginx.com                              + app->res_timeout;
7621123Smax.romanov@nginx.com 
7631123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD enqueue to pending_requests",
7641123Smax.romanov@nginx.com               req_app_link->stream);
765427Smax.romanov@nginx.com }
766427Smax.romanov@nginx.com 
767427Smax.romanov@nginx.com 
768425Smax.romanov@nginx.com nxt_inline nxt_bool_t
769425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
770425Smax.romanov@nginx.com {
771425Smax.romanov@nginx.com     if (lnk->next != NULL) {
772425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
773425Smax.romanov@nginx.com 
774425Smax.romanov@nginx.com         lnk->next = NULL;
775425Smax.romanov@nginx.com 
776425Smax.romanov@nginx.com         return 1;
777425Smax.romanov@nginx.com     }
778425Smax.romanov@nginx.com 
779425Smax.romanov@nginx.com     return 0;
780425Smax.romanov@nginx.com }
781425Smax.romanov@nginx.com 
782425Smax.romanov@nginx.com 
783343Smax.romanov@nginx.com nxt_inline void
7841123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task,
7851123Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
786343Smax.romanov@nginx.com {
7871123Smax.romanov@nginx.com     int                     ra_use_delta;
7881123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
7891123Smax.romanov@nginx.com 
7901123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
7911123Smax.romanov@nginx.com         nxt_router_app_port_release(task, req_rpc_data->app_port,
7921123Smax.romanov@nginx.com                                     req_rpc_data->apr_action);
7931123Smax.romanov@nginx.com 
7941123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
7951123Smax.romanov@nginx.com     }
7961123Smax.romanov@nginx.com 
7971123Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
7981123Smax.romanov@nginx.com 
7991123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
8001123Smax.romanov@nginx.com     if (req_app_link != NULL) {
8011123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
8021123Smax.romanov@nginx.com         req_app_link->req_rpc_data = NULL;
803343Smax.romanov@nginx.com 
804425Smax.romanov@nginx.com         ra_use_delta = 0;
805425Smax.romanov@nginx.com 
8061123Smax.romanov@nginx.com         nxt_thread_mutex_lock(&req_rpc_data->app->mutex);
8071123Smax.romanov@nginx.com 
8081123Smax.romanov@nginx.com         if (req_app_link->link_app_requests.next == NULL
8091123Smax.romanov@nginx.com             && req_app_link->link_port_pending.next == NULL
8101131Smax.romanov@nginx.com             && req_app_link->link_app_pending.next == NULL
8111131Smax.romanov@nginx.com             && req_app_link->link_port_websockets.next == NULL)
812425Smax.romanov@nginx.com         {
8131123Smax.romanov@nginx.com             req_app_link = NULL;
814343Smax.romanov@nginx.com 
815343Smax.romanov@nginx.com         } else {
8161123Smax.romanov@nginx.com             ra_use_delta -=
8171123Smax.romanov@nginx.com                 nxt_queue_chk_remove(&req_app_link->link_app_requests)
8181131Smax.romanov@nginx.com                 + nxt_queue_chk_remove(&req_app_link->link_port_pending)
8191131Smax.romanov@nginx.com                 + nxt_queue_chk_remove(&req_app_link->link_port_websockets);
8201123Smax.romanov@nginx.com 
8211123Smax.romanov@nginx.com             nxt_queue_chk_remove(&req_app_link->link_app_pending);
822343Smax.romanov@nginx.com         }
823343Smax.romanov@nginx.com 
8241123Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&req_rpc_data->app->mutex);
8251123Smax.romanov@nginx.com 
8261123Smax.romanov@nginx.com         if (req_app_link != NULL) {
8271123Smax.romanov@nginx.com             nxt_request_app_link_use(task, req_app_link, ra_use_delta);
828425Smax.romanov@nginx.com         }
829343Smax.romanov@nginx.com     }
830343Smax.romanov@nginx.com 
8311123Smax.romanov@nginx.com     if (req_rpc_data->app != NULL) {
8321123Smax.romanov@nginx.com         nxt_router_app_use(task, req_rpc_data->app, -1);
8331123Smax.romanov@nginx.com 
8341123Smax.romanov@nginx.com         req_rpc_data->app = NULL;
8351123Smax.romanov@nginx.com     }
8361123Smax.romanov@nginx.com 
8371123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
8381123Smax.romanov@nginx.com         req_rpc_data->request->timer_data = NULL;
8391123Smax.romanov@nginx.com 
8401123Smax.romanov@nginx.com         nxt_router_http_request_done(task, req_rpc_data->request);
8411123Smax.romanov@nginx.com 
8421131Smax.romanov@nginx.com         req_rpc_data->request->req_rpc_data = NULL;
8431123Smax.romanov@nginx.com         req_rpc_data->request = NULL;
844346Smax.romanov@nginx.com     }
845343Smax.romanov@nginx.com }
846343Smax.romanov@nginx.com 
847343Smax.romanov@nginx.com 
848141Smax.romanov@nginx.com void
849141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
850141Smax.romanov@nginx.com {
851141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
852141Smax.romanov@nginx.com 
853670Smax.romanov@nginx.com     if (msg->u.new_port != NULL
854670Smax.romanov@nginx.com         && msg->u.new_port->type == NXT_PROCESS_CONTROLLER)
855670Smax.romanov@nginx.com     {
856662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
857662Smax.romanov@nginx.com     }
858662Smax.romanov@nginx.com 
859192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
860141Smax.romanov@nginx.com         return;
861141Smax.romanov@nginx.com     }
862141Smax.romanov@nginx.com 
863426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
864426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
865347Smax.romanov@nginx.com     {
866192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
867141Smax.romanov@nginx.com     }
868192Smax.romanov@nginx.com 
869192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
870141Smax.romanov@nginx.com }
871141Smax.romanov@nginx.com 
872141Smax.romanov@nginx.com 
873139Sigor@sysoev.ru void
874139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
875115Sigor@sysoev.ru {
876198Sigor@sysoev.ru     nxt_int_t               ret;
877139Sigor@sysoev.ru     nxt_buf_t               *b;
878139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
879139Sigor@sysoev.ru 
880139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
881139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
882139Sigor@sysoev.ru         return;
88353Sigor@sysoev.ru     }
88453Sigor@sysoev.ru 
885494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
886423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
887493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
888423Smax.romanov@nginx.com 
889591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
890139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
891139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
892198Sigor@sysoev.ru                                        msg->port_msg.pid,
893198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
894198Sigor@sysoev.ru 
895779Smax.romanov@nginx.com     if (nxt_slow_path(tmcf->port == NULL)) {
896779Smax.romanov@nginx.com         nxt_alert(task, "reply port not found");
897779Smax.romanov@nginx.com 
898779Smax.romanov@nginx.com         return;
899779Smax.romanov@nginx.com     }
900779Smax.romanov@nginx.com 
901779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
902779Smax.romanov@nginx.com 
903591Sigor@sysoev.ru     b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool,
904591Sigor@sysoev.ru                                msg->buf, msg->size);
905551Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
906551Smax.romanov@nginx.com         nxt_router_conf_error(task, tmcf);
907551Smax.romanov@nginx.com 
908551Smax.romanov@nginx.com         return;
909551Smax.romanov@nginx.com     }
910551Smax.romanov@nginx.com 
911198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
912198Sigor@sysoev.ru 
913198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
914198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
915198Sigor@sysoev.ru 
916198Sigor@sysoev.ru     } else {
917198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
918139Sigor@sysoev.ru     }
91953Sigor@sysoev.ru }
92053Sigor@sysoev.ru 
92153Sigor@sysoev.ru 
922347Smax.romanov@nginx.com static void
923507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
924507Smax.romanov@nginx.com     void *data)
925347Smax.romanov@nginx.com {
926347Smax.romanov@nginx.com     union {
927347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
928347Smax.romanov@nginx.com         void       *data;
929347Smax.romanov@nginx.com     } u;
930347Smax.romanov@nginx.com 
931347Smax.romanov@nginx.com     u.data = data;
932347Smax.romanov@nginx.com 
933347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
934347Smax.romanov@nginx.com }
935347Smax.romanov@nginx.com 
936347Smax.romanov@nginx.com 
937192Smax.romanov@nginx.com void
938192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
939192Smax.romanov@nginx.com {
940347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
941318Smax.romanov@nginx.com 
942192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
943192Smax.romanov@nginx.com 
944318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
945318Smax.romanov@nginx.com     {
946507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
947347Smax.romanov@nginx.com                       msg->u.data);
948318Smax.romanov@nginx.com     }
949318Smax.romanov@nginx.com     nxt_queue_loop;
950318Smax.romanov@nginx.com 
9511085Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
9521085Smax.romanov@nginx.com         return;
9531085Smax.romanov@nginx.com     }
9541085Smax.romanov@nginx.com 
955192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
956192Smax.romanov@nginx.com 
957192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
958192Smax.romanov@nginx.com }
959192Smax.romanov@nginx.com 
960192Smax.romanov@nginx.com 
96153Sigor@sysoev.ru static nxt_router_temp_conf_t *
962139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
96353Sigor@sysoev.ru {
96465Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
96553Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
96653Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
96753Sigor@sysoev.ru 
96865Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
96953Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
97053Sigor@sysoev.ru         return NULL;
97153Sigor@sysoev.ru     }
97253Sigor@sysoev.ru 
97365Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
97453Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
97553Sigor@sysoev.ru         goto fail;
97653Sigor@sysoev.ru     }
97753Sigor@sysoev.ru 
97853Sigor@sysoev.ru     rtcf->mem_pool = mp;
97953Sigor@sysoev.ru 
98065Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
98153Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
98253Sigor@sysoev.ru         goto fail;
98353Sigor@sysoev.ru     }
98453Sigor@sysoev.ru 
98565Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
98653Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
98753Sigor@sysoev.ru         goto temp_fail;
98853Sigor@sysoev.ru     }
98953Sigor@sysoev.ru 
99053Sigor@sysoev.ru     tmcf->mem_pool = tmp;
991591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
992139Sigor@sysoev.ru     tmcf->count = 1;
993139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
99453Sigor@sysoev.ru 
99553Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
99653Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
99753Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
99853Sigor@sysoev.ru         goto temp_fail;
99953Sigor@sysoev.ru     }
100053Sigor@sysoev.ru 
100153Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
100253Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
100353Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
100453Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
100553Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
1006416Smax.romanov@nginx.com 
1007774Svbart@nginx.com #if (NXT_TLS)
1008774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
1009774Svbart@nginx.com #endif
1010774Svbart@nginx.com 
1011133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
1012133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
101353Sigor@sysoev.ru 
101453Sigor@sysoev.ru     return tmcf;
101553Sigor@sysoev.ru 
101653Sigor@sysoev.ru temp_fail:
101753Sigor@sysoev.ru 
101865Sigor@sysoev.ru     nxt_mp_destroy(tmp);
101953Sigor@sysoev.ru 
102053Sigor@sysoev.ru fail:
102153Sigor@sysoev.ru 
102265Sigor@sysoev.ru     nxt_mp_destroy(mp);
102353Sigor@sysoev.ru 
102453Sigor@sysoev.ru     return NULL;
102553Sigor@sysoev.ru }
102653Sigor@sysoev.ru 
102753Sigor@sysoev.ru 
1028507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1029507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
1030507Smax.romanov@nginx.com {
1031507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
1032507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
1033507Smax.romanov@nginx.com }
1034507Smax.romanov@nginx.com 
1035507Smax.romanov@nginx.com 
1036507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1037507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
1038507Smax.romanov@nginx.com {
1039507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
1040507Smax.romanov@nginx.com             < app->spare_processes;
1041507Smax.romanov@nginx.com }
1042507Smax.romanov@nginx.com 
1043507Smax.romanov@nginx.com 
1044198Sigor@sysoev.ru static void
1045198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1046139Sigor@sysoev.ru {
1047139Sigor@sysoev.ru     nxt_int_t                    ret;
1048507Smax.romanov@nginx.com     nxt_app_t                    *app;
1049139Sigor@sysoev.ru     nxt_router_t                 *router;
1050139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1051198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1052198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1053630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1054198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1055139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1056774Svbart@nginx.com #if (NXT_TLS)
1057774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
1058774Svbart@nginx.com #endif
1059139Sigor@sysoev.ru 
1060198Sigor@sysoev.ru     tmcf = obj;
1061198Sigor@sysoev.ru 
1062198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
1063198Sigor@sysoev.ru 
1064198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
1065198Sigor@sysoev.ru         nxt_queue_remove(qlk);
1066198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
1067198Sigor@sysoev.ru 
1068198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1069198Sigor@sysoev.ru 
1070198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1071198Sigor@sysoev.ru 
1072198Sigor@sysoev.ru         return;
1073139Sigor@sysoev.ru     }
1074139Sigor@sysoev.ru 
1075774Svbart@nginx.com #if (NXT_TLS)
1076774Svbart@nginx.com     qlk = nxt_queue_first(&tmcf->tls);
1077774Svbart@nginx.com 
1078774Svbart@nginx.com     if (qlk != nxt_queue_tail(&tmcf->tls)) {
1079774Svbart@nginx.com         nxt_queue_remove(qlk);
1080774Svbart@nginx.com 
1081774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1082774Svbart@nginx.com 
1083774Svbart@nginx.com         nxt_router_tls_rpc_create(task, tmcf, tls);
1084774Svbart@nginx.com         return;
1085774Svbart@nginx.com     }
1086774Svbart@nginx.com #endif
1087774Svbart@nginx.com 
1088507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1089507Smax.romanov@nginx.com 
1090507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1091507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1092507Smax.romanov@nginx.com             return;
1093507Smax.romanov@nginx.com         }
1094507Smax.romanov@nginx.com 
1095507Smax.romanov@nginx.com     } nxt_queue_loop;
1096507Smax.romanov@nginx.com 
1097630Svbart@nginx.com     rtcf = tmcf->router_conf;
1098630Svbart@nginx.com 
1099630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1100630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1101630Svbart@nginx.com         return;
1102630Svbart@nginx.com     }
1103630Svbart@nginx.com 
1104139Sigor@sysoev.ru     rt = task->thread->runtime;
1105139Sigor@sysoev.ru 
1106139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1107139Sigor@sysoev.ru 
1108630Svbart@nginx.com     router = rtcf->router;
1109198Sigor@sysoev.ru 
1110139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1111139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1112198Sigor@sysoev.ru         goto fail;
1113139Sigor@sysoev.ru     }
1114139Sigor@sysoev.ru 
1115139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1116139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1117198Sigor@sysoev.ru         goto fail;
1118139Sigor@sysoev.ru     }
1119139Sigor@sysoev.ru 
1120343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1121139Sigor@sysoev.ru 
1122315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1123139Sigor@sysoev.ru 
1124139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
1125139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
1126139Sigor@sysoev.ru 
1127630Svbart@nginx.com     router->access_log = rtcf->access_log;
1128630Svbart@nginx.com 
1129198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1130198Sigor@sysoev.ru 
1131198Sigor@sysoev.ru     return;
1132198Sigor@sysoev.ru 
1133198Sigor@sysoev.ru fail:
1134198Sigor@sysoev.ru 
1135198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1136198Sigor@sysoev.ru 
1137198Sigor@sysoev.ru     return;
1138139Sigor@sysoev.ru }
1139139Sigor@sysoev.ru 
1140139Sigor@sysoev.ru 
1141139Sigor@sysoev.ru static void
1142139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1143139Sigor@sysoev.ru {
1144153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1145153Sigor@sysoev.ru 
1146153Sigor@sysoev.ru     job = obj;
1147153Sigor@sysoev.ru 
1148198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1149139Sigor@sysoev.ru }
1150139Sigor@sysoev.ru 
1151139Sigor@sysoev.ru 
1152139Sigor@sysoev.ru static void
1153198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1154139Sigor@sysoev.ru {
1155139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
1156139Sigor@sysoev.ru 
1157139Sigor@sysoev.ru     if (--tmcf->count == 0) {
1158193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1159139Sigor@sysoev.ru     }
1160139Sigor@sysoev.ru }
1161139Sigor@sysoev.ru 
1162139Sigor@sysoev.ru 
1163139Sigor@sysoev.ru static void
1164139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1165139Sigor@sysoev.ru {
1166507Smax.romanov@nginx.com     nxt_app_t          *app;
1167568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1168148Sigor@sysoev.ru     nxt_socket_t       s;
1169149Sigor@sysoev.ru     nxt_router_t       *router;
1170148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1171148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1172630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1173148Sigor@sysoev.ru 
1174564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1175198Sigor@sysoev.ru 
1176148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
1177148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
1178148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1179148Sigor@sysoev.ru     {
1180148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1181359Sigor@sysoev.ru         s = skcf->listen->socket;
1182148Sigor@sysoev.ru 
1183148Sigor@sysoev.ru         if (s != -1) {
1184148Sigor@sysoev.ru             nxt_socket_close(task, s);
1185148Sigor@sysoev.ru         }
1186148Sigor@sysoev.ru 
1187359Sigor@sysoev.ru         nxt_free(skcf->listen);
1188148Sigor@sysoev.ru     }
1189148Sigor@sysoev.ru 
1190568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
1191568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->updating);
1192568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->pending);
1193568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->creating);
1194568Smax.romanov@nginx.com 
1195964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1196964Sigor@sysoev.ru 
1197964Sigor@sysoev.ru     nxt_http_routes_cleanup(task, rtcf->routes);
1198964Sigor@sysoev.ru 
1199568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1200568Smax.romanov@nginx.com 
12011264Sigor@sysoev.ru         if (skcf->action != NULL) {
12021264Sigor@sysoev.ru             nxt_http_action_cleanup(task, skcf->action);
1203568Smax.romanov@nginx.com         }
1204568Smax.romanov@nginx.com 
1205568Smax.romanov@nginx.com     } nxt_queue_loop;
1206568Smax.romanov@nginx.com 
1207507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1208507Smax.romanov@nginx.com 
1209753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1210507Smax.romanov@nginx.com 
1211507Smax.romanov@nginx.com     } nxt_queue_loop;
1212507Smax.romanov@nginx.com 
1213630Svbart@nginx.com     router = rtcf->router;
1214149Sigor@sysoev.ru 
1215149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1216149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1217149Sigor@sysoev.ru 
1218416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1219416Smax.romanov@nginx.com 
1220148Sigor@sysoev.ru     // TODO: new engines and threads
1221148Sigor@sysoev.ru 
1222630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1223630Svbart@nginx.com 
1224630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1225139Sigor@sysoev.ru 
1226193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1227139Sigor@sysoev.ru }
1228139Sigor@sysoev.ru 
1229139Sigor@sysoev.ru 
1230139Sigor@sysoev.ru static void
1231139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1232193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1233139Sigor@sysoev.ru {
1234193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1235779Smax.romanov@nginx.com 
1236779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1237779Smax.romanov@nginx.com 
1238779Smax.romanov@nginx.com     tmcf->port = NULL;
1239139Sigor@sysoev.ru }
1240139Sigor@sysoev.ru 
1241139Sigor@sysoev.ru 
1242115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1243115Sigor@sysoev.ru     {
1244133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1245115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1246115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1247115Sigor@sysoev.ru     },
1248115Sigor@sysoev.ru };
1249115Sigor@sysoev.ru 
1250115Sigor@sysoev.ru 
1251133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1252115Sigor@sysoev.ru     {
1253133Sigor@sysoev.ru         nxt_string("type"),
1254115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1255133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1256115Sigor@sysoev.ru     },
1257115Sigor@sysoev.ru 
1258115Sigor@sysoev.ru     {
1259507Smax.romanov@nginx.com         nxt_string("limits"),
1260507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1261507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1262133Sigor@sysoev.ru     },
1263318Smax.romanov@nginx.com 
1264318Smax.romanov@nginx.com     {
1265507Smax.romanov@nginx.com         nxt_string("processes"),
1266507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1267507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1268507Smax.romanov@nginx.com     },
1269507Smax.romanov@nginx.com 
1270507Smax.romanov@nginx.com     {
1271507Smax.romanov@nginx.com         nxt_string("processes"),
1272318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1273507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1274318Smax.romanov@nginx.com     },
1275318Smax.romanov@nginx.com };
1276318Smax.romanov@nginx.com 
1277318Smax.romanov@nginx.com 
1278318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1279318Smax.romanov@nginx.com     {
1280318Smax.romanov@nginx.com         nxt_string("timeout"),
1281318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1282318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1283318Smax.romanov@nginx.com     },
1284318Smax.romanov@nginx.com 
1285318Smax.romanov@nginx.com     {
1286427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1287427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1288427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1289427Smax.romanov@nginx.com     },
1290427Smax.romanov@nginx.com 
1291427Smax.romanov@nginx.com     {
1292318Smax.romanov@nginx.com         nxt_string("requests"),
1293318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1294318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1295318Smax.romanov@nginx.com     },
1296133Sigor@sysoev.ru };
1297133Sigor@sysoev.ru 
1298133Sigor@sysoev.ru 
1299507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1300507Smax.romanov@nginx.com     {
1301507Smax.romanov@nginx.com         nxt_string("spare"),
1302507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1303507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1304507Smax.romanov@nginx.com     },
1305507Smax.romanov@nginx.com 
1306507Smax.romanov@nginx.com     {
1307507Smax.romanov@nginx.com         nxt_string("max"),
1308507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1309507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1310507Smax.romanov@nginx.com     },
1311507Smax.romanov@nginx.com 
1312507Smax.romanov@nginx.com     {
1313507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1314507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1315507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1316507Smax.romanov@nginx.com     },
1317507Smax.romanov@nginx.com };
1318507Smax.romanov@nginx.com 
1319507Smax.romanov@nginx.com 
1320133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1321133Sigor@sysoev.ru     {
1322964Sigor@sysoev.ru         nxt_string("pass"),
1323964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1324964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1325964Sigor@sysoev.ru     },
1326964Sigor@sysoev.ru 
1327964Sigor@sysoev.ru     {
1328133Sigor@sysoev.ru         nxt_string("application"),
1329964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1330133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1331115Sigor@sysoev.ru     },
1332115Sigor@sysoev.ru };
1333115Sigor@sysoev.ru 
1334115Sigor@sysoev.ru 
1335115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1336115Sigor@sysoev.ru     {
1337115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1338115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1339115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1340115Sigor@sysoev.ru     },
1341115Sigor@sysoev.ru 
1342115Sigor@sysoev.ru     {
1343115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1344115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1345115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1346115Sigor@sysoev.ru     },
1347115Sigor@sysoev.ru 
1348115Sigor@sysoev.ru     {
1349206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1350206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1351206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1352206Smax.romanov@nginx.com     },
1353206Smax.romanov@nginx.com 
1354206Smax.romanov@nginx.com     {
1355206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1356206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1357206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1358206Smax.romanov@nginx.com     },
1359206Smax.romanov@nginx.com 
1360206Smax.romanov@nginx.com     {
1361206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1362206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1363206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1364206Smax.romanov@nginx.com     },
1365206Smax.romanov@nginx.com 
1366206Smax.romanov@nginx.com     {
1367431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1368431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1369431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1370431Sigor@sysoev.ru     },
1371431Sigor@sysoev.ru 
1372431Sigor@sysoev.ru     {
1373115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1374115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1375115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1376115Sigor@sysoev.ru     },
1377206Smax.romanov@nginx.com 
1378206Smax.romanov@nginx.com     {
1379206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1380206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1381206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1382206Smax.romanov@nginx.com     },
1383431Sigor@sysoev.ru 
1384431Sigor@sysoev.ru     {
1385431Sigor@sysoev.ru         nxt_string("send_timeout"),
1386431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1387431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1388431Sigor@sysoev.ru     },
13891403Smax.romanov@nginx.com 
13901403Smax.romanov@nginx.com     {
13911403Smax.romanov@nginx.com         nxt_string("body_temp_path"),
13921403Smax.romanov@nginx.com         NXT_CONF_MAP_STR,
13931403Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_temp_path),
13941403Smax.romanov@nginx.com     },
1395115Sigor@sysoev.ru };
1396115Sigor@sysoev.ru 
1397115Sigor@sysoev.ru 
13981131Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_websocket_conf[] = {
13991131Smax.romanov@nginx.com     {
14001131Smax.romanov@nginx.com         nxt_string("max_frame_size"),
14011131Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
14021131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, max_frame_size),
14031131Smax.romanov@nginx.com     },
14041131Smax.romanov@nginx.com 
14051131Smax.romanov@nginx.com     {
14061131Smax.romanov@nginx.com         nxt_string("read_timeout"),
14071131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
14081131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, read_timeout),
14091131Smax.romanov@nginx.com     },
14101131Smax.romanov@nginx.com 
14111131Smax.romanov@nginx.com     {
14121131Smax.romanov@nginx.com         nxt_string("keepalive_interval"),
14131131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
14141131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, keepalive_interval),
14151131Smax.romanov@nginx.com     },
14161131Smax.romanov@nginx.com 
14171131Smax.romanov@nginx.com };
14181131Smax.romanov@nginx.com 
14191131Smax.romanov@nginx.com 
142053Sigor@sysoev.ru static nxt_int_t
1421115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1422115Sigor@sysoev.ru     u_char *start, u_char *end)
142353Sigor@sysoev.ru {
1424133Sigor@sysoev.ru     u_char                      *p;
1425133Sigor@sysoev.ru     size_t                      size;
1426115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1427115Sigor@sysoev.ru     uint32_t                    next;
1428115Sigor@sysoev.ru     nxt_int_t                   ret;
1429630Svbart@nginx.com     nxt_str_t                   name, path;
1430133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
14311403Smax.romanov@nginx.com     nxt_str_t                   *t;
1432359Sigor@sysoev.ru     nxt_router_t                *router;
1433753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
14341131Smax.romanov@nginx.com     nxt_conf_value_t            *conf, *http, *value, *websocket;
1435133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1436133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
14371183Svbart@nginx.com     nxt_conf_value_t            *routes_conf, *static_conf;
1438115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1439964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1440507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1441216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1442133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1443630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1444115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1445774Svbart@nginx.com #if (NXT_TLS)
1446774Svbart@nginx.com     nxt_router_tlssock_t        *tls;
1447774Svbart@nginx.com #endif
1448115Sigor@sysoev.ru 
1449716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1450133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1451115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1452964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1453630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1454774Svbart@nginx.com #if (NXT_TLS)
1455774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1456774Svbart@nginx.com #endif
14571183Svbart@nginx.com     static nxt_str_t  static_path = nxt_string("/settings/http/static");
14581131Smax.romanov@nginx.com     static nxt_str_t  websocket_path = nxt_string("/settings/http/websocket");
1459115Sigor@sysoev.ru 
1460208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1461115Sigor@sysoev.ru     if (conf == NULL) {
1462564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1463115Sigor@sysoev.ru         return NXT_ERROR;
1464115Sigor@sysoev.ru     }
1465115Sigor@sysoev.ru 
1466591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1467213Svbart@nginx.com 
1468213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1469591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1470115Sigor@sysoev.ru     if (ret != NXT_OK) {
1471564Svbart@nginx.com         nxt_alert(task, "root map error");
1472115Sigor@sysoev.ru         return NXT_ERROR;
1473115Sigor@sysoev.ru     }
1474115Sigor@sysoev.ru 
1475591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1476591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1477117Sigor@sysoev.ru     }
1478117Sigor@sysoev.ru 
14791183Svbart@nginx.com     static_conf = nxt_conf_get_path(conf, &static_path);
14801183Svbart@nginx.com 
14811183Svbart@nginx.com     ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
14821183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
14831183Svbart@nginx.com         return NXT_ERROR;
14841183Svbart@nginx.com     }
14851183Svbart@nginx.com 
14861115Svbart@nginx.com     router = tmcf->router_conf->router;
14871115Svbart@nginx.com 
1488133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
14891115Svbart@nginx.com 
14901115Svbart@nginx.com     if (applications != NULL) {
14911115Svbart@nginx.com         next = 0;
14921115Svbart@nginx.com 
14931115Svbart@nginx.com         for ( ;; ) {
14941235Sigor@sysoev.ru             application = nxt_conf_next_object_member(applications,
14951235Sigor@sysoev.ru                                                       &name, &next);
14961115Svbart@nginx.com             if (application == NULL) {
14971115Svbart@nginx.com                 break;
14981115Svbart@nginx.com             }
14991115Svbart@nginx.com 
15001115Svbart@nginx.com             nxt_debug(task, "application \"%V\"", &name);
15011115Svbart@nginx.com 
15021115Svbart@nginx.com             size = nxt_conf_json_length(application, NULL);
15031115Svbart@nginx.com 
15041115Svbart@nginx.com             app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
15051115Svbart@nginx.com             if (app == NULL) {
15061115Svbart@nginx.com                 goto fail;
15071115Svbart@nginx.com             }
15081115Svbart@nginx.com 
15091115Svbart@nginx.com             nxt_memzero(app, sizeof(nxt_app_t));
15101115Svbart@nginx.com 
15111115Svbart@nginx.com             app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
15121115Svbart@nginx.com             app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
15131115Svbart@nginx.com                                                   + name.length);
15141115Svbart@nginx.com 
15151115Svbart@nginx.com             p = nxt_conf_json_print(app->conf.start, application, NULL);
15161115Svbart@nginx.com             app->conf.length = p - app->conf.start;
15171115Svbart@nginx.com 
15181115Svbart@nginx.com             nxt_assert(app->conf.length <= size);
15191115Svbart@nginx.com 
15201115Svbart@nginx.com             nxt_debug(task, "application conf \"%V\"", &app->conf);
15211115Svbart@nginx.com 
15221115Svbart@nginx.com             prev = nxt_router_app_find(&router->apps, &name);
15231115Svbart@nginx.com 
15241115Svbart@nginx.com             if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
15251115Svbart@nginx.com                 nxt_free(app);
15261115Svbart@nginx.com 
15271115Svbart@nginx.com                 nxt_queue_remove(&prev->link);
15281115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
15291115Svbart@nginx.com                 continue;
15301115Svbart@nginx.com             }
15311115Svbart@nginx.com 
15321115Svbart@nginx.com             apcf.processes = 1;
15331115Svbart@nginx.com             apcf.max_processes = 1;
15341115Svbart@nginx.com             apcf.spare_processes = 0;
15351115Svbart@nginx.com             apcf.timeout = 0;
15361115Svbart@nginx.com             apcf.res_timeout = 1000;
15371115Svbart@nginx.com             apcf.idle_timeout = 15000;
15381115Svbart@nginx.com             apcf.requests = 0;
15391115Svbart@nginx.com             apcf.limits_value = NULL;
15401115Svbart@nginx.com             apcf.processes_value = NULL;
15411115Svbart@nginx.com 
15421115Svbart@nginx.com             app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
15431115Svbart@nginx.com             if (nxt_slow_path(app_joint == NULL)) {
1544318Smax.romanov@nginx.com                 goto app_fail;
1545318Smax.romanov@nginx.com             }
1546318Smax.romanov@nginx.com 
15471115Svbart@nginx.com             nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
15481115Svbart@nginx.com 
15491115Svbart@nginx.com             ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
15501115Svbart@nginx.com                                       nxt_nitems(nxt_router_app_conf), &apcf);
1551318Smax.romanov@nginx.com             if (ret != NXT_OK) {
15521115Svbart@nginx.com                 nxt_alert(task, "application map error");
1553318Smax.romanov@nginx.com                 goto app_fail;
1554318Smax.romanov@nginx.com             }
15551115Svbart@nginx.com 
15561115Svbart@nginx.com             if (apcf.limits_value != NULL) {
15571115Svbart@nginx.com 
15581115Svbart@nginx.com                 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
15591115Svbart@nginx.com                     nxt_alert(task, "application limits is not object");
15601115Svbart@nginx.com                     goto app_fail;
15611115Svbart@nginx.com                 }
15621115Svbart@nginx.com 
15631115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.limits_value,
15641115Svbart@nginx.com                                         nxt_router_app_limits_conf,
15651115Svbart@nginx.com                                         nxt_nitems(nxt_router_app_limits_conf),
15661115Svbart@nginx.com                                         &apcf);
15671115Svbart@nginx.com                 if (ret != NXT_OK) {
15681115Svbart@nginx.com                     nxt_alert(task, "application limits map error");
15691115Svbart@nginx.com                     goto app_fail;
15701115Svbart@nginx.com                 }
15711115Svbart@nginx.com             }
15721115Svbart@nginx.com 
15731115Svbart@nginx.com             if (apcf.processes_value != NULL
15741115Svbart@nginx.com                 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
15751115Svbart@nginx.com             {
15761115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.processes_value,
15771115Svbart@nginx.com                                      nxt_router_app_processes_conf,
15781115Svbart@nginx.com                                      nxt_nitems(nxt_router_app_processes_conf),
15791115Svbart@nginx.com                                      &apcf);
15801115Svbart@nginx.com                 if (ret != NXT_OK) {
15811115Svbart@nginx.com                     nxt_alert(task, "application processes map error");
15821115Svbart@nginx.com                     goto app_fail;
15831115Svbart@nginx.com                 }
15841115Svbart@nginx.com 
15851115Svbart@nginx.com             } else {
15861115Svbart@nginx.com                 apcf.max_processes = apcf.processes;
15871115Svbart@nginx.com                 apcf.spare_processes = apcf.processes;
15881115Svbart@nginx.com             }
15891115Svbart@nginx.com 
15901115Svbart@nginx.com             nxt_debug(task, "application type: %V", &apcf.type);
15911115Svbart@nginx.com             nxt_debug(task, "application processes: %D", apcf.processes);
15921115Svbart@nginx.com             nxt_debug(task, "application request timeout: %M", apcf.timeout);
15931115Svbart@nginx.com             nxt_debug(task, "application reschedule timeout: %M",
15941115Svbart@nginx.com                       apcf.res_timeout);
15951115Svbart@nginx.com             nxt_debug(task, "application requests: %D", apcf.requests);
15961115Svbart@nginx.com 
15971115Svbart@nginx.com             lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
15981115Svbart@nginx.com 
15991115Svbart@nginx.com             if (lang == NULL) {
16001115Svbart@nginx.com                 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1601507Smax.romanov@nginx.com                 goto app_fail;
1602507Smax.romanov@nginx.com             }
1603507Smax.romanov@nginx.com 
16041115Svbart@nginx.com             nxt_debug(task, "application language module: \"%s\"", lang->file);
16051115Svbart@nginx.com 
16061115Svbart@nginx.com             ret = nxt_thread_mutex_create(&app->mutex);
16071115Svbart@nginx.com             if (ret != NXT_OK) {
16081115Svbart@nginx.com                 goto app_fail;
16091115Svbart@nginx.com             }
16101115Svbart@nginx.com 
16111115Svbart@nginx.com             nxt_queue_init(&app->ports);
16121115Svbart@nginx.com             nxt_queue_init(&app->spare_ports);
16131115Svbart@nginx.com             nxt_queue_init(&app->idle_ports);
16141115Svbart@nginx.com             nxt_queue_init(&app->requests);
16151115Svbart@nginx.com             nxt_queue_init(&app->pending);
16161115Svbart@nginx.com 
16171115Svbart@nginx.com             app->name.length = name.length;
16181115Svbart@nginx.com             nxt_memcpy(app->name.start, name.start, name.length);
16191115Svbart@nginx.com 
16201115Svbart@nginx.com             app->type = lang->type;
16211115Svbart@nginx.com             app->max_processes = apcf.max_processes;
16221115Svbart@nginx.com             app->spare_processes = apcf.spare_processes;
16231115Svbart@nginx.com             app->max_pending_processes = apcf.spare_processes
16241115Svbart@nginx.com                                          ? apcf.spare_processes : 1;
16251115Svbart@nginx.com             app->timeout = apcf.timeout;
16261115Svbart@nginx.com             app->res_timeout = apcf.res_timeout * 1000000;
16271115Svbart@nginx.com             app->idle_timeout = apcf.idle_timeout;
16281115Svbart@nginx.com             app->max_pending_responses = 2;
16291115Svbart@nginx.com             app->max_requests = apcf.requests;
16301115Svbart@nginx.com 
16311115Svbart@nginx.com             engine = task->thread->engine;
16321115Svbart@nginx.com 
16331115Svbart@nginx.com             app->engine = engine;
16341115Svbart@nginx.com 
16351115Svbart@nginx.com             app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
16361115Svbart@nginx.com             app->adjust_idle_work.task = &engine->task;
16371115Svbart@nginx.com             app->adjust_idle_work.obj = app;
16381115Svbart@nginx.com 
16391115Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->apps, &app->link);
16401115Svbart@nginx.com 
16411115Svbart@nginx.com             nxt_router_app_use(task, app, 1);
16421115Svbart@nginx.com 
16431115Svbart@nginx.com             app->joint = app_joint;
16441115Svbart@nginx.com 
16451115Svbart@nginx.com             app_joint->use_count = 1;
16461115Svbart@nginx.com             app_joint->app = app;
16471115Svbart@nginx.com 
16481115Svbart@nginx.com             app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
16491115Svbart@nginx.com             app_joint->idle_timer.work_queue = &engine->fast_work_queue;
16501115Svbart@nginx.com             app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
16511115Svbart@nginx.com             app_joint->idle_timer.task = &engine->task;
16521115Svbart@nginx.com             app_joint->idle_timer.log = app_joint->idle_timer.task->log;
16531115Svbart@nginx.com 
16541115Svbart@nginx.com             app_joint->free_app_work.handler = nxt_router_free_app;
16551115Svbart@nginx.com             app_joint->free_app_work.task = &engine->task;
16561115Svbart@nginx.com             app_joint->free_app_work.obj = app_joint;
1657133Sigor@sysoev.ru         }
1658133Sigor@sysoev.ru     }
1659133Sigor@sysoev.ru 
1660964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1661964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1662964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1663964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1664964Sigor@sysoev.ru             return NXT_ERROR;
1665964Sigor@sysoev.ru         }
1666964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1667964Sigor@sysoev.ru     }
1668964Sigor@sysoev.ru 
16691394Sigor@sysoev.ru     ret = nxt_upstreams_create(task, tmcf, conf);
16701394Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
16711394Sigor@sysoev.ru         return ret;
16721394Sigor@sysoev.ru     }
16731394Sigor@sysoev.ru 
1674133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1675133Sigor@sysoev.ru #if 0
1676133Sigor@sysoev.ru     if (http == NULL) {
1677564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1678133Sigor@sysoev.ru         return NXT_ERROR;
1679133Sigor@sysoev.ru     }
1680133Sigor@sysoev.ru #endif
1681133Sigor@sysoev.ru 
16821131Smax.romanov@nginx.com     websocket = nxt_conf_get_path(conf, &websocket_path);
16831131Smax.romanov@nginx.com 
1684133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
16851115Svbart@nginx.com 
16861115Svbart@nginx.com     if (listeners != NULL) {
16871115Svbart@nginx.com         next = 0;
16881115Svbart@nginx.com 
16891115Svbart@nginx.com         for ( ;; ) {
16901115Svbart@nginx.com             listener = nxt_conf_next_object_member(listeners, &name, &next);
16911115Svbart@nginx.com             if (listener == NULL) {
16921115Svbart@nginx.com                 break;
16931115Svbart@nginx.com             }
16941115Svbart@nginx.com 
16951115Svbart@nginx.com             skcf = nxt_router_socket_conf(task, tmcf, &name);
16961115Svbart@nginx.com             if (skcf == NULL) {
16971115Svbart@nginx.com                 goto fail;
16981115Svbart@nginx.com             }
16991115Svbart@nginx.com 
17001115Svbart@nginx.com             nxt_memzero(&lscf, sizeof(lscf));
17011115Svbart@nginx.com 
17021115Svbart@nginx.com             ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
17031115Svbart@nginx.com                                       nxt_nitems(nxt_router_listener_conf),
17041115Svbart@nginx.com                                       &lscf);
1705133Sigor@sysoev.ru             if (ret != NXT_OK) {
17061115Svbart@nginx.com                 nxt_alert(task, "listener map error");
1707133Sigor@sysoev.ru                 goto fail;
1708133Sigor@sysoev.ru             }
17091115Svbart@nginx.com 
17101115Svbart@nginx.com             nxt_debug(task, "application: %V", &lscf.application);
17111115Svbart@nginx.com 
17121115Svbart@nginx.com             // STUB, default values if http block is not defined.
17131115Svbart@nginx.com             skcf->header_buffer_size = 2048;
17141115Svbart@nginx.com             skcf->large_header_buffer_size = 8192;
17151115Svbart@nginx.com             skcf->large_header_buffers = 4;
17161115Svbart@nginx.com             skcf->body_buffer_size = 16 * 1024;
17171115Svbart@nginx.com             skcf->max_body_size = 8 * 1024 * 1024;
17181270Sigor@sysoev.ru             skcf->proxy_header_buffer_size = 64 * 1024;
17191270Sigor@sysoev.ru             skcf->proxy_buffer_size = 4096;
17201270Sigor@sysoev.ru             skcf->proxy_buffers = 256;
17211115Svbart@nginx.com             skcf->idle_timeout = 180 * 1000;
17221115Svbart@nginx.com             skcf->header_read_timeout = 30 * 1000;
17231115Svbart@nginx.com             skcf->body_read_timeout = 30 * 1000;
17241115Svbart@nginx.com             skcf->send_timeout = 30 * 1000;
17251270Sigor@sysoev.ru             skcf->proxy_timeout = 60 * 1000;
17261270Sigor@sysoev.ru             skcf->proxy_send_timeout = 30 * 1000;
17271270Sigor@sysoev.ru             skcf->proxy_read_timeout = 30 * 1000;
17281115Svbart@nginx.com 
17291131Smax.romanov@nginx.com             skcf->websocket_conf.max_frame_size = 1024 * 1024;
17301131Smax.romanov@nginx.com             skcf->websocket_conf.read_timeout = 60 * 1000;
17311131Smax.romanov@nginx.com             skcf->websocket_conf.keepalive_interval = 30 * 1000;
17321131Smax.romanov@nginx.com 
17331403Smax.romanov@nginx.com             nxt_str_null(&skcf->body_temp_path);
17341403Smax.romanov@nginx.com 
17351115Svbart@nginx.com             if (http != NULL) {
17361115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
17371115Svbart@nginx.com                                           nxt_nitems(nxt_router_http_conf),
17381115Svbart@nginx.com                                           skcf);
17391115Svbart@nginx.com                 if (ret != NXT_OK) {
17401115Svbart@nginx.com                     nxt_alert(task, "http map error");
17411115Svbart@nginx.com                     goto fail;
17421115Svbart@nginx.com                 }
17431115Svbart@nginx.com             }
1744115Sigor@sysoev.ru 
17451131Smax.romanov@nginx.com             if (websocket != NULL) {
17461131Smax.romanov@nginx.com                 ret = nxt_conf_map_object(mp, websocket,
17471131Smax.romanov@nginx.com                                           nxt_router_websocket_conf,
17481131Smax.romanov@nginx.com                                           nxt_nitems(nxt_router_websocket_conf),
17491131Smax.romanov@nginx.com                                           &skcf->websocket_conf);
17501131Smax.romanov@nginx.com                 if (ret != NXT_OK) {
17511131Smax.romanov@nginx.com                     nxt_alert(task, "websocket map error");
17521131Smax.romanov@nginx.com                     goto fail;
17531131Smax.romanov@nginx.com                 }
17541131Smax.romanov@nginx.com             }
17551131Smax.romanov@nginx.com 
17561403Smax.romanov@nginx.com             t = &skcf->body_temp_path;
17571403Smax.romanov@nginx.com 
17581403Smax.romanov@nginx.com             if (t->length == 0) {
17591403Smax.romanov@nginx.com                 t->start = (u_char *) task->thread->runtime->tmp;
17601403Smax.romanov@nginx.com                 t->length = nxt_strlen(t->start);
17611403Smax.romanov@nginx.com             }
17621403Smax.romanov@nginx.com 
1763774Svbart@nginx.com #if (NXT_TLS)
17641115Svbart@nginx.com             value = nxt_conf_get_path(listener, &certificate_path);
17651115Svbart@nginx.com 
17661115Svbart@nginx.com             if (value != NULL) {
17671115Svbart@nginx.com                 nxt_conf_get_string(value, &name);
17681115Svbart@nginx.com 
17691115Svbart@nginx.com                 tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
17701115Svbart@nginx.com                 if (nxt_slow_path(tls == NULL)) {
17711115Svbart@nginx.com                     goto fail;
17721115Svbart@nginx.com                 }
17731115Svbart@nginx.com 
17741115Svbart@nginx.com                 tls->name = name;
17751115Svbart@nginx.com                 tls->conf = skcf;
17761115Svbart@nginx.com 
17771115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1778774Svbart@nginx.com             }
1779774Svbart@nginx.com #endif
1780774Svbart@nginx.com 
17811115Svbart@nginx.com             skcf->listen->handler = nxt_http_conn_init;
17821115Svbart@nginx.com             skcf->router_conf = tmcf->router_conf;
17831115Svbart@nginx.com             skcf->router_conf->count++;
17841115Svbart@nginx.com 
17851115Svbart@nginx.com             if (lscf.pass.length != 0) {
17861264Sigor@sysoev.ru                 skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass);
17871115Svbart@nginx.com 
17881115Svbart@nginx.com             /* COMPATIBILITY: listener application. */
17891115Svbart@nginx.com             } else if (lscf.application.length > 0) {
17901264Sigor@sysoev.ru                 skcf->action = nxt_http_pass_application(task, tmcf,
17911264Sigor@sysoev.ru                                                          &lscf.application);
17921115Svbart@nginx.com             }
1793770Smax.romanov@nginx.com         }
1794115Sigor@sysoev.ru     }
179553Sigor@sysoev.ru 
1796630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1797630Svbart@nginx.com 
1798630Svbart@nginx.com     if (value != NULL) {
1799630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1800630Svbart@nginx.com 
1801630Svbart@nginx.com         access_log = router->access_log;
1802630Svbart@nginx.com 
1803630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1804630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1805630Svbart@nginx.com             access_log->count++;
1806630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1807630Svbart@nginx.com 
1808630Svbart@nginx.com         } else {
1809630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1810630Svbart@nginx.com                                     + path.length);
1811630Svbart@nginx.com             if (access_log == NULL) {
1812630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1813630Svbart@nginx.com                 goto fail;
1814630Svbart@nginx.com             }
1815630Svbart@nginx.com 
1816630Svbart@nginx.com             access_log->fd = -1;
1817630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1818630Svbart@nginx.com             access_log->count = 1;
1819630Svbart@nginx.com 
1820630Svbart@nginx.com             access_log->path.length = path.length;
1821630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1822630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1823630Svbart@nginx.com 
1824630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1825630Svbart@nginx.com         }
1826630Svbart@nginx.com 
1827630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1828630Svbart@nginx.com     }
1829630Svbart@nginx.com 
1830964Sigor@sysoev.ru     nxt_http_routes_resolve(task, tmcf);
1831964Sigor@sysoev.ru 
1832359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1833359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1834198Sigor@sysoev.ru 
183553Sigor@sysoev.ru     return NXT_OK;
1836133Sigor@sysoev.ru 
1837133Sigor@sysoev.ru app_fail:
1838133Sigor@sysoev.ru 
1839133Sigor@sysoev.ru     nxt_free(app);
1840133Sigor@sysoev.ru 
1841133Sigor@sysoev.ru fail:
1842133Sigor@sysoev.ru 
1843141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1844141Smax.romanov@nginx.com 
1845141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1846133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1847133Sigor@sysoev.ru         nxt_free(app);
1848141Smax.romanov@nginx.com 
1849141Smax.romanov@nginx.com     } nxt_queue_loop;
1850133Sigor@sysoev.ru 
1851133Sigor@sysoev.ru     return NXT_ERROR;
1852133Sigor@sysoev.ru }
1853133Sigor@sysoev.ru 
1854133Sigor@sysoev.ru 
18551183Svbart@nginx.com static nxt_int_t
18561183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
18571183Svbart@nginx.com     nxt_conf_value_t *conf)
18581183Svbart@nginx.com {
18591183Svbart@nginx.com     uint32_t          next, i;
18601183Svbart@nginx.com     nxt_mp_t          *mp;
18611183Svbart@nginx.com     nxt_str_t         *type, extension, str;
18621183Svbart@nginx.com     nxt_int_t         ret;
18631183Svbart@nginx.com     nxt_uint_t        exts;
18641183Svbart@nginx.com     nxt_conf_value_t  *mtypes_conf, *ext_conf, *value;
18651183Svbart@nginx.com 
18661183Svbart@nginx.com     static nxt_str_t  mtypes_path = nxt_string("/mime_types");
18671183Svbart@nginx.com 
18681183Svbart@nginx.com     mp = rtcf->mem_pool;
18691183Svbart@nginx.com 
18701183Svbart@nginx.com     ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
18711183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
18721183Svbart@nginx.com         return NXT_ERROR;
18731183Svbart@nginx.com     }
18741183Svbart@nginx.com 
18751183Svbart@nginx.com     if (conf == NULL) {
18761183Svbart@nginx.com         return NXT_OK;
18771183Svbart@nginx.com     }
18781183Svbart@nginx.com 
18791183Svbart@nginx.com     mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
18801183Svbart@nginx.com 
18811183Svbart@nginx.com     if (mtypes_conf != NULL) {
18821183Svbart@nginx.com         next = 0;
18831183Svbart@nginx.com 
18841183Svbart@nginx.com         for ( ;; ) {
18851183Svbart@nginx.com             ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
18861183Svbart@nginx.com 
18871183Svbart@nginx.com             if (ext_conf == NULL) {
18881183Svbart@nginx.com                 break;
18891183Svbart@nginx.com             }
18901183Svbart@nginx.com 
18911183Svbart@nginx.com             type = nxt_str_dup(mp, NULL, &str);
18921183Svbart@nginx.com             if (nxt_slow_path(type == NULL)) {
18931183Svbart@nginx.com                 return NXT_ERROR;
18941183Svbart@nginx.com             }
18951183Svbart@nginx.com 
18961183Svbart@nginx.com             if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
18971183Svbart@nginx.com                 nxt_conf_get_string(ext_conf, &str);
18981183Svbart@nginx.com 
18991183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
19001183Svbart@nginx.com                     return NXT_ERROR;
19011183Svbart@nginx.com                 }
19021183Svbart@nginx.com 
19031183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
19041183Svbart@nginx.com                                                       &extension, type);
19051183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
19061183Svbart@nginx.com                     return NXT_ERROR;
19071183Svbart@nginx.com                 }
19081183Svbart@nginx.com 
19091183Svbart@nginx.com                 continue;
19101183Svbart@nginx.com             }
19111183Svbart@nginx.com 
19121183Svbart@nginx.com             exts = nxt_conf_array_elements_count(ext_conf);
19131183Svbart@nginx.com 
19141183Svbart@nginx.com             for (i = 0; i < exts; i++) {
19151183Svbart@nginx.com                 value = nxt_conf_get_array_element(ext_conf, i);
19161183Svbart@nginx.com 
19171183Svbart@nginx.com                 nxt_conf_get_string(value, &str);
19181183Svbart@nginx.com 
19191183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
19201183Svbart@nginx.com                     return NXT_ERROR;
19211183Svbart@nginx.com                 }
19221183Svbart@nginx.com 
19231183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
19241183Svbart@nginx.com                                                       &extension, type);
19251183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
19261183Svbart@nginx.com                     return NXT_ERROR;
19271183Svbart@nginx.com                 }
19281183Svbart@nginx.com             }
19291183Svbart@nginx.com         }
19301183Svbart@nginx.com     }
19311183Svbart@nginx.com 
19321183Svbart@nginx.com     return NXT_OK;
19331183Svbart@nginx.com }
19341183Svbart@nginx.com 
19351183Svbart@nginx.com 
1936133Sigor@sysoev.ru static nxt_app_t *
1937133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1938133Sigor@sysoev.ru {
1939141Smax.romanov@nginx.com     nxt_app_t  *app;
1940141Smax.romanov@nginx.com 
1941141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1942133Sigor@sysoev.ru 
1943133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1944133Sigor@sysoev.ru             return app;
1945133Sigor@sysoev.ru         }
1946141Smax.romanov@nginx.com 
1947141Smax.romanov@nginx.com     } nxt_queue_loop;
1948133Sigor@sysoev.ru 
1949133Sigor@sysoev.ru     return NULL;
1950133Sigor@sysoev.ru }
1951133Sigor@sysoev.ru 
1952133Sigor@sysoev.ru 
19531392Sigor@sysoev.ru void
19541392Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name,
19551392Sigor@sysoev.ru     nxt_http_action_t *action)
1956133Sigor@sysoev.ru {
1957133Sigor@sysoev.ru     nxt_app_t  *app;
1958133Sigor@sysoev.ru 
1959133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1960133Sigor@sysoev.ru 
1961133Sigor@sysoev.ru     if (app == NULL) {
1962134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1963133Sigor@sysoev.ru     }
1964133Sigor@sysoev.ru 
19651392Sigor@sysoev.ru     action->u.application = app;
19661392Sigor@sysoev.ru     action->handler = nxt_http_application_handler;
196753Sigor@sysoev.ru }
196853Sigor@sysoev.ru 
196953Sigor@sysoev.ru 
197053Sigor@sysoev.ru static nxt_socket_conf_t *
1971359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1972359Sigor@sysoev.ru     nxt_str_t *name)
197353Sigor@sysoev.ru {
1974359Sigor@sysoev.ru     size_t               size;
1975359Sigor@sysoev.ru     nxt_int_t            ret;
1976359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1977359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1978359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1979359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1980359Sigor@sysoev.ru 
1981359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1982359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1983564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1984359Sigor@sysoev.ru         return NULL;
1985359Sigor@sysoev.ru     }
1986359Sigor@sysoev.ru 
1987359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1988359Sigor@sysoev.ru 
1989359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1990493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1991359Sigor@sysoev.ru 
1992591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1993163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
199453Sigor@sysoev.ru         return NULL;
199553Sigor@sysoev.ru     }
199653Sigor@sysoev.ru 
1997359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1998359Sigor@sysoev.ru 
1999359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
2000359Sigor@sysoev.ru 
2001359Sigor@sysoev.ru     if (ret != NXT_OK) {
2002359Sigor@sysoev.ru 
2003359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
2004359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
2005359Sigor@sysoev.ru             return NULL;
2006359Sigor@sysoev.ru         }
2007359Sigor@sysoev.ru 
2008359Sigor@sysoev.ru         skcf->listen = ls;
2009359Sigor@sysoev.ru 
2010359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
2011359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
2012359Sigor@sysoev.ru 
2013359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
2014359Sigor@sysoev.ru 
2015359Sigor@sysoev.ru         ls->socket = -1;
2016359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
2017359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
2018359Sigor@sysoev.ru         ls->read_after_accept = 1;
2019359Sigor@sysoev.ru     }
2020359Sigor@sysoev.ru 
2021359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
2022359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
2023359Sigor@sysoev.ru     case AF_UNIX:
2024359Sigor@sysoev.ru         wildcard = 0;
2025359Sigor@sysoev.ru         break;
2026359Sigor@sysoev.ru #endif
2027359Sigor@sysoev.ru #if (NXT_INET6)
2028359Sigor@sysoev.ru     case AF_INET6:
2029359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
2030359Sigor@sysoev.ru         break;
2031359Sigor@sysoev.ru #endif
2032359Sigor@sysoev.ru     case AF_INET:
2033359Sigor@sysoev.ru     default:
2034359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
2035359Sigor@sysoev.ru         break;
2036359Sigor@sysoev.ru     }
2037359Sigor@sysoev.ru 
2038359Sigor@sysoev.ru     if (!wildcard) {
2039591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
2040359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
2041359Sigor@sysoev.ru             return NULL;
2042359Sigor@sysoev.ru         }
2043359Sigor@sysoev.ru 
2044359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
2045359Sigor@sysoev.ru     }
2046163Smax.romanov@nginx.com 
2047163Smax.romanov@nginx.com     return skcf;
204853Sigor@sysoev.ru }
204953Sigor@sysoev.ru 
205053Sigor@sysoev.ru 
2051359Sigor@sysoev.ru static nxt_int_t
2052359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
2053359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
205453Sigor@sysoev.ru {
2055359Sigor@sysoev.ru     nxt_router_t       *router;
2056359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
2057359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
2058359Sigor@sysoev.ru 
2059591Sigor@sysoev.ru     router = tmcf->router_conf->router;
2060359Sigor@sysoev.ru 
2061359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
2062359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
2063359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
206453Sigor@sysoev.ru     {
2065359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2066359Sigor@sysoev.ru 
2067359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2068359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
2069359Sigor@sysoev.ru 
2070359Sigor@sysoev.ru             nxt_queue_remove(qlk);
2071359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
2072359Sigor@sysoev.ru 
2073359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
2074359Sigor@sysoev.ru 
2075359Sigor@sysoev.ru             return NXT_OK;
207653Sigor@sysoev.ru         }
207753Sigor@sysoev.ru     }
207853Sigor@sysoev.ru 
2079359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
2080359Sigor@sysoev.ru 
2081359Sigor@sysoev.ru     return NXT_DECLINED;
208253Sigor@sysoev.ru }
208353Sigor@sysoev.ru 
208453Sigor@sysoev.ru 
2085198Sigor@sysoev.ru static void
2086198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2087198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2088198Sigor@sysoev.ru {
2089358Sigor@sysoev.ru     size_t            size;
2090198Sigor@sysoev.ru     uint32_t          stream;
2091648Svbart@nginx.com     nxt_int_t         ret;
2092198Sigor@sysoev.ru     nxt_buf_t         *b;
2093198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
2094198Sigor@sysoev.ru     nxt_runtime_t     *rt;
2095198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
2096198Sigor@sysoev.ru 
2097198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2098198Sigor@sysoev.ru     if (rpc == NULL) {
2099198Sigor@sysoev.ru         goto fail;
2100198Sigor@sysoev.ru     }
2101198Sigor@sysoev.ru 
2102198Sigor@sysoev.ru     rpc->socket_conf = skcf;
2103198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
2104198Sigor@sysoev.ru 
2105359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
2106358Sigor@sysoev.ru 
2107358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2108198Sigor@sysoev.ru     if (b == NULL) {
2109198Sigor@sysoev.ru         goto fail;
2110198Sigor@sysoev.ru     }
2111198Sigor@sysoev.ru 
2112359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2113198Sigor@sysoev.ru 
2114198Sigor@sysoev.ru     rt = task->thread->runtime;
2115240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2116198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2117198Sigor@sysoev.ru 
2118198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
2119198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
2120198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
2121198Sigor@sysoev.ru                                            main_port->pid, rpc);
2122645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
2123198Sigor@sysoev.ru         goto fail;
2124198Sigor@sysoev.ru     }
2125198Sigor@sysoev.ru 
2126648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2127648Svbart@nginx.com                                 stream, router_port->id, b);
2128648Svbart@nginx.com 
2129648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2130648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2131648Svbart@nginx.com         goto fail;
2132648Svbart@nginx.com     }
2133198Sigor@sysoev.ru 
2134198Sigor@sysoev.ru     return;
2135198Sigor@sysoev.ru 
2136198Sigor@sysoev.ru fail:
2137198Sigor@sysoev.ru 
2138198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
2139198Sigor@sysoev.ru }
2140198Sigor@sysoev.ru 
2141198Sigor@sysoev.ru 
2142198Sigor@sysoev.ru static void
2143198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2144198Sigor@sysoev.ru     void *data)
214553Sigor@sysoev.ru {
2146359Sigor@sysoev.ru     nxt_int_t         ret;
2147359Sigor@sysoev.ru     nxt_socket_t      s;
2148359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
214953Sigor@sysoev.ru 
2150198Sigor@sysoev.ru     rpc = data;
2151198Sigor@sysoev.ru 
2152198Sigor@sysoev.ru     s = msg->fd;
2153198Sigor@sysoev.ru 
2154198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
2155198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2156198Sigor@sysoev.ru         goto fail;
215753Sigor@sysoev.ru     }
215853Sigor@sysoev.ru 
2159359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2160198Sigor@sysoev.ru 
2161198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2162198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2163198Sigor@sysoev.ru         goto fail;
2164198Sigor@sysoev.ru     }
2165198Sigor@sysoev.ru 
2166359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
2167198Sigor@sysoev.ru 
2168198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2169198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2170198Sigor@sysoev.ru 
2171198Sigor@sysoev.ru     return;
2172148Sigor@sysoev.ru 
2173148Sigor@sysoev.ru fail:
2174148Sigor@sysoev.ru 
2175148Sigor@sysoev.ru     nxt_socket_close(task, s);
2176148Sigor@sysoev.ru 
2177198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2178198Sigor@sysoev.ru }
2179198Sigor@sysoev.ru 
2180198Sigor@sysoev.ru 
2181198Sigor@sysoev.ru static void
2182198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2183198Sigor@sysoev.ru     void *data)
2184198Sigor@sysoev.ru {
2185955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2186955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2187955Svbart@nginx.com 
2188955Svbart@nginx.com     rpc = data;
2189955Svbart@nginx.com     tmcf = rpc->temp_conf;
2190955Svbart@nginx.com 
2191955Svbart@nginx.com #if 0
2192198Sigor@sysoev.ru     u_char                  *p;
2193198Sigor@sysoev.ru     size_t                  size;
2194198Sigor@sysoev.ru     uint8_t                 error;
2195198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2196198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2197198Sigor@sysoev.ru 
2198198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2199198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2200198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2201198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2202198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2203198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2204198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2205198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2206198Sigor@sysoev.ru     };
2207198Sigor@sysoev.ru 
2208359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2209352Smax.romanov@nginx.com 
2210352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2211352Smax.romanov@nginx.com 
2212551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2213551Smax.romanov@nginx.com         return;
2214551Smax.romanov@nginx.com     }
2215352Smax.romanov@nginx.com 
2216198Sigor@sysoev.ru     p = in->mem.pos;
2217198Sigor@sysoev.ru 
2218198Sigor@sysoev.ru     error = *p++;
2219198Sigor@sysoev.ru 
2220703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2221703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2222198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2223198Sigor@sysoev.ru 
2224198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2225198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2226198Sigor@sysoev.ru         return;
2227198Sigor@sysoev.ru     }
2228198Sigor@sysoev.ru 
2229198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2230198Sigor@sysoev.ru                         "listen socket error: "
2231198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2232493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2233198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2234198Sigor@sysoev.ru 
2235198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2236955Svbart@nginx.com #endif
2237198Sigor@sysoev.ru 
2238198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
223953Sigor@sysoev.ru }
224053Sigor@sysoev.ru 
224153Sigor@sysoev.ru 
2242774Svbart@nginx.com #if (NXT_TLS)
2243774Svbart@nginx.com 
2244774Svbart@nginx.com static void
2245774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2246774Svbart@nginx.com     nxt_router_tlssock_t *tls)
2247774Svbart@nginx.com {
2248774Svbart@nginx.com     nxt_socket_rpc_t  *rpc;
2249774Svbart@nginx.com 
2250774Svbart@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2251774Svbart@nginx.com     if (rpc == NULL) {
2252774Svbart@nginx.com         nxt_router_conf_error(task, tmcf);
2253774Svbart@nginx.com         return;
2254774Svbart@nginx.com     }
2255774Svbart@nginx.com 
2256774Svbart@nginx.com     rpc->socket_conf = tls->conf;
2257774Svbart@nginx.com     rpc->temp_conf = tmcf;
2258774Svbart@nginx.com 
2259774Svbart@nginx.com     nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
2260774Svbart@nginx.com                        nxt_router_tls_rpc_handler, rpc);
2261774Svbart@nginx.com }
2262774Svbart@nginx.com 
2263774Svbart@nginx.com 
2264774Svbart@nginx.com static void
2265774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2266774Svbart@nginx.com     void *data)
2267774Svbart@nginx.com {
2268774Svbart@nginx.com     nxt_mp_t               *mp;
2269774Svbart@nginx.com     nxt_int_t              ret;
2270774Svbart@nginx.com     nxt_tls_conf_t         *tlscf;
2271774Svbart@nginx.com     nxt_socket_rpc_t       *rpc;
2272774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf;
2273774Svbart@nginx.com 
2274774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2275774Svbart@nginx.com 
2276774Svbart@nginx.com     rpc = data;
2277774Svbart@nginx.com     tmcf = rpc->temp_conf;
2278774Svbart@nginx.com 
2279774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2280774Svbart@nginx.com         goto fail;
2281774Svbart@nginx.com     }
2282774Svbart@nginx.com 
2283774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2284774Svbart@nginx.com 
2285774Svbart@nginx.com     tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2286774Svbart@nginx.com     if (nxt_slow_path(tlscf == NULL)) {
2287774Svbart@nginx.com         goto fail;
2288774Svbart@nginx.com     }
2289774Svbart@nginx.com 
2290774Svbart@nginx.com     tlscf->chain_file = msg->fd;
2291774Svbart@nginx.com 
2292774Svbart@nginx.com     ret = task->thread->runtime->tls->server_init(task, tlscf);
2293774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2294774Svbart@nginx.com         goto fail;
2295774Svbart@nginx.com     }
2296774Svbart@nginx.com 
2297774Svbart@nginx.com     rpc->socket_conf->tls = tlscf;
2298774Svbart@nginx.com 
2299774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2300774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2301774Svbart@nginx.com     return;
2302774Svbart@nginx.com 
2303774Svbart@nginx.com fail:
2304774Svbart@nginx.com 
2305774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2306774Svbart@nginx.com }
2307774Svbart@nginx.com 
2308774Svbart@nginx.com #endif
2309774Svbart@nginx.com 
2310774Svbart@nginx.com 
2311507Smax.romanov@nginx.com static void
2312507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2313507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2314507Smax.romanov@nginx.com {
2315507Smax.romanov@nginx.com     size_t         size;
2316507Smax.romanov@nginx.com     uint32_t       stream;
2317648Svbart@nginx.com     nxt_int_t      ret;
2318507Smax.romanov@nginx.com     nxt_buf_t      *b;
2319507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
2320507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2321507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2322507Smax.romanov@nginx.com 
2323507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2324507Smax.romanov@nginx.com     if (rpc == NULL) {
2325507Smax.romanov@nginx.com         goto fail;
2326507Smax.romanov@nginx.com     }
2327507Smax.romanov@nginx.com 
2328507Smax.romanov@nginx.com     rpc->app = app;
2329507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2330507Smax.romanov@nginx.com 
2331507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
2332507Smax.romanov@nginx.com 
2333507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
2334507Smax.romanov@nginx.com 
2335507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2336507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2337507Smax.romanov@nginx.com         goto fail;
2338507Smax.romanov@nginx.com     }
2339507Smax.romanov@nginx.com 
2340507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
2341507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
2342507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2343507Smax.romanov@nginx.com 
2344507Smax.romanov@nginx.com     rt = task->thread->runtime;
2345507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2346507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2347507Smax.romanov@nginx.com 
2348507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2349507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
2350507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
2351507Smax.romanov@nginx.com                                            -1, rpc);
2352507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2353507Smax.romanov@nginx.com         goto fail;
2354507Smax.romanov@nginx.com     }
2355507Smax.romanov@nginx.com 
2356648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2357648Svbart@nginx.com                                 stream, router_port->id, b);
2358648Svbart@nginx.com 
2359648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2360648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2361648Svbart@nginx.com         goto fail;
2362648Svbart@nginx.com     }
2363648Svbart@nginx.com 
2364507Smax.romanov@nginx.com     app->pending_processes++;
2365507Smax.romanov@nginx.com 
2366507Smax.romanov@nginx.com     return;
2367507Smax.romanov@nginx.com 
2368507Smax.romanov@nginx.com fail:
2369507Smax.romanov@nginx.com 
2370507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2371507Smax.romanov@nginx.com }
2372507Smax.romanov@nginx.com 
2373507Smax.romanov@nginx.com 
2374507Smax.romanov@nginx.com static void
2375507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2376507Smax.romanov@nginx.com     void *data)
2377507Smax.romanov@nginx.com {
2378507Smax.romanov@nginx.com     nxt_app_t           *app;
2379507Smax.romanov@nginx.com     nxt_port_t          *port;
2380507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2381507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2382507Smax.romanov@nginx.com 
2383507Smax.romanov@nginx.com     rpc = data;
2384507Smax.romanov@nginx.com     app = rpc->app;
2385507Smax.romanov@nginx.com 
2386507Smax.romanov@nginx.com     port = msg->u.new_port;
2387507Smax.romanov@nginx.com     port->app = app;
2388507Smax.romanov@nginx.com 
2389507Smax.romanov@nginx.com     app->pending_processes--;
2390507Smax.romanov@nginx.com     app->processes++;
2391507Smax.romanov@nginx.com     app->idle_processes++;
2392507Smax.romanov@nginx.com 
2393507Smax.romanov@nginx.com     engine = task->thread->engine;
2394507Smax.romanov@nginx.com 
2395507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2396507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2397507Smax.romanov@nginx.com 
2398507Smax.romanov@nginx.com     port->idle_start = 0;
2399507Smax.romanov@nginx.com 
2400507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2401507Smax.romanov@nginx.com 
2402507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2403507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2404507Smax.romanov@nginx.com }
2405507Smax.romanov@nginx.com 
2406507Smax.romanov@nginx.com 
2407507Smax.romanov@nginx.com static void
2408507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2409507Smax.romanov@nginx.com     void *data)
2410507Smax.romanov@nginx.com {
2411507Smax.romanov@nginx.com     nxt_app_t               *app;
2412507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2413507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2414507Smax.romanov@nginx.com 
2415507Smax.romanov@nginx.com     rpc = data;
2416507Smax.romanov@nginx.com     app = rpc->app;
2417507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2418507Smax.romanov@nginx.com 
2419507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2420507Smax.romanov@nginx.com             &app->name);
2421507Smax.romanov@nginx.com 
2422507Smax.romanov@nginx.com     app->pending_processes--;
2423507Smax.romanov@nginx.com 
2424507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2425507Smax.romanov@nginx.com }
2426507Smax.romanov@nginx.com 
2427507Smax.romanov@nginx.com 
242853Sigor@sysoev.ru static nxt_int_t
242953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
243053Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
243153Sigor@sysoev.ru {
243253Sigor@sysoev.ru     nxt_int_t                 ret;
243353Sigor@sysoev.ru     nxt_uint_t                n, threads;
243453Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
243553Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
243653Sigor@sysoev.ru 
2437591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
243853Sigor@sysoev.ru 
243953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
244053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
244153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
244253Sigor@sysoev.ru         return NXT_ERROR;
244353Sigor@sysoev.ru     }
244453Sigor@sysoev.ru 
244553Sigor@sysoev.ru     n = 0;
244653Sigor@sysoev.ru 
244753Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
244853Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
244953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
245053Sigor@sysoev.ru     {
245153Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
245253Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
245353Sigor@sysoev.ru             return NXT_ERROR;
245453Sigor@sysoev.ru         }
245553Sigor@sysoev.ru 
2456115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
245753Sigor@sysoev.ru 
245853Sigor@sysoev.ru         if (n < threads) {
2459315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2460115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
246153Sigor@sysoev.ru 
246253Sigor@sysoev.ru         } else {
2463315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2464115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
246553Sigor@sysoev.ru         }
246653Sigor@sysoev.ru 
246753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
246853Sigor@sysoev.ru             return ret;
246953Sigor@sysoev.ru         }
247053Sigor@sysoev.ru 
247153Sigor@sysoev.ru         n++;
247253Sigor@sysoev.ru     }
247353Sigor@sysoev.ru 
247453Sigor@sysoev.ru     tmcf->new_threads = n;
247553Sigor@sysoev.ru 
247653Sigor@sysoev.ru     while (n < threads) {
247753Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
247853Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
247953Sigor@sysoev.ru             return NXT_ERROR;
248053Sigor@sysoev.ru         }
248153Sigor@sysoev.ru 
2482315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2483315Sigor@sysoev.ru 
248453Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
248553Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
248653Sigor@sysoev.ru             return NXT_ERROR;
248753Sigor@sysoev.ru         }
248853Sigor@sysoev.ru 
2489115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
249053Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
249153Sigor@sysoev.ru             return ret;
249253Sigor@sysoev.ru         }
249353Sigor@sysoev.ru 
249453Sigor@sysoev.ru         n++;
249553Sigor@sysoev.ru     }
249653Sigor@sysoev.ru 
249753Sigor@sysoev.ru     return NXT_OK;
249853Sigor@sysoev.ru }
249953Sigor@sysoev.ru 
250053Sigor@sysoev.ru 
250153Sigor@sysoev.ru static nxt_int_t
2502115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2503115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
250453Sigor@sysoev.ru {
2505359Sigor@sysoev.ru     nxt_int_t  ret;
250653Sigor@sysoev.ru 
2507154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2508154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2509115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2510115Sigor@sysoev.ru         return ret;
2511115Sigor@sysoev.ru     }
2512115Sigor@sysoev.ru 
2513154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2514154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
251553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
251653Sigor@sysoev.ru         return ret;
251753Sigor@sysoev.ru     }
251853Sigor@sysoev.ru 
2519115Sigor@sysoev.ru     return ret;
252053Sigor@sysoev.ru }
252153Sigor@sysoev.ru 
252253Sigor@sysoev.ru 
252353Sigor@sysoev.ru static nxt_int_t
2524115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2525115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
252653Sigor@sysoev.ru {
2527359Sigor@sysoev.ru     nxt_int_t  ret;
252853Sigor@sysoev.ru 
2529154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2530154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
253153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
253253Sigor@sysoev.ru         return ret;
253353Sigor@sysoev.ru     }
253453Sigor@sysoev.ru 
2535154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2536154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
253753Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
253853Sigor@sysoev.ru         return ret;
253953Sigor@sysoev.ru     }
254053Sigor@sysoev.ru 
2541139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
2542115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2543115Sigor@sysoev.ru         return ret;
2544115Sigor@sysoev.ru     }
2545115Sigor@sysoev.ru 
2546115Sigor@sysoev.ru     return ret;
254753Sigor@sysoev.ru }
254853Sigor@sysoev.ru 
254953Sigor@sysoev.ru 
255053Sigor@sysoev.ru static nxt_int_t
2551115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2552115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
255353Sigor@sysoev.ru {
255453Sigor@sysoev.ru     nxt_int_t  ret;
255553Sigor@sysoev.ru 
2556313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2557313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2558313Sigor@sysoev.ru         return ret;
2559313Sigor@sysoev.ru     }
2560313Sigor@sysoev.ru 
2561139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
256253Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
256353Sigor@sysoev.ru         return ret;
256453Sigor@sysoev.ru     }
256553Sigor@sysoev.ru 
2566139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
256753Sigor@sysoev.ru }
256853Sigor@sysoev.ru 
256953Sigor@sysoev.ru 
257053Sigor@sysoev.ru static nxt_int_t
2571154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2572154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
257353Sigor@sysoev.ru     nxt_work_handler_t handler)
257453Sigor@sysoev.ru {
25751394Sigor@sysoev.ru     nxt_int_t                ret;
2576153Sigor@sysoev.ru     nxt_joint_job_t          *job;
257753Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2578155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
257953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
258053Sigor@sysoev.ru 
258153Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
258253Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
258353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
258453Sigor@sysoev.ru     {
2585154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2586153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2587139Sigor@sysoev.ru             return NXT_ERROR;
2588139Sigor@sysoev.ru         }
2589139Sigor@sysoev.ru 
2590154Sigor@sysoev.ru         job->work.next = recf->jobs;
2591154Sigor@sysoev.ru         recf->jobs = &job->work;
2592154Sigor@sysoev.ru 
2593153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2594153Sigor@sysoev.ru         job->work.handler = handler;
2595153Sigor@sysoev.ru         job->work.task = &job->task;
2596153Sigor@sysoev.ru         job->work.obj = job;
2597153Sigor@sysoev.ru         job->tmcf = tmcf;
259853Sigor@sysoev.ru 
2599154Sigor@sysoev.ru         tmcf->count++;
2600154Sigor@sysoev.ru 
2601591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2602154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
260353Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
260453Sigor@sysoev.ru             return NXT_ERROR;
260553Sigor@sysoev.ru         }
260653Sigor@sysoev.ru 
2607153Sigor@sysoev.ru         job->work.data = joint;
260853Sigor@sysoev.ru 
26091394Sigor@sysoev.ru         ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams);
26101394Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
26111394Sigor@sysoev.ru             return ret;
26121394Sigor@sysoev.ru         }
26131394Sigor@sysoev.ru 
261453Sigor@sysoev.ru         joint->count = 1;
2615155Sigor@sysoev.ru 
2616155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2617155Sigor@sysoev.ru         skcf->count++;
2618155Sigor@sysoev.ru         joint->socket_conf = skcf;
2619155Sigor@sysoev.ru 
262088Smax.romanov@nginx.com         joint->engine = recf->engine;
262153Sigor@sysoev.ru     }
262253Sigor@sysoev.ru 
262320Sigor@sysoev.ru     return NXT_OK;
262420Sigor@sysoev.ru }
262520Sigor@sysoev.ru 
262620Sigor@sysoev.ru 
262720Sigor@sysoev.ru static nxt_int_t
2628313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2629313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2630313Sigor@sysoev.ru {
2631313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2632313Sigor@sysoev.ru 
2633313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2634313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2635313Sigor@sysoev.ru         return NXT_ERROR;
2636313Sigor@sysoev.ru     }
2637313Sigor@sysoev.ru 
2638313Sigor@sysoev.ru     job->work.next = recf->jobs;
2639313Sigor@sysoev.ru     recf->jobs = &job->work;
2640313Sigor@sysoev.ru 
2641313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2642313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2643313Sigor@sysoev.ru     job->work.task = &job->task;
2644313Sigor@sysoev.ru     job->work.obj = NULL;
2645313Sigor@sysoev.ru     job->work.data = NULL;
2646313Sigor@sysoev.ru     job->tmcf = NULL;
2647313Sigor@sysoev.ru 
2648313Sigor@sysoev.ru     return NXT_OK;
2649313Sigor@sysoev.ru }
2650313Sigor@sysoev.ru 
2651313Sigor@sysoev.ru 
2652313Sigor@sysoev.ru static nxt_int_t
2653139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2654139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
265520Sigor@sysoev.ru {
2656153Sigor@sysoev.ru     nxt_joint_job_t   *job;
265753Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
265820Sigor@sysoev.ru 
265953Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
266053Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
266153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
266253Sigor@sysoev.ru     {
2663154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2664153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2665139Sigor@sysoev.ru             return NXT_ERROR;
2666139Sigor@sysoev.ru         }
2667139Sigor@sysoev.ru 
2668154Sigor@sysoev.ru         job->work.next = recf->jobs;
2669154Sigor@sysoev.ru         recf->jobs = &job->work;
2670154Sigor@sysoev.ru 
2671153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2672153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2673153Sigor@sysoev.ru         job->work.task = &job->task;
2674153Sigor@sysoev.ru         job->work.obj = job;
2675153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2676153Sigor@sysoev.ru         job->tmcf = tmcf;
2677154Sigor@sysoev.ru 
2678154Sigor@sysoev.ru         tmcf->count++;
267920Sigor@sysoev.ru     }
268020Sigor@sysoev.ru 
268153Sigor@sysoev.ru     return NXT_OK;
268253Sigor@sysoev.ru }
268320Sigor@sysoev.ru 
268420Sigor@sysoev.ru 
268553Sigor@sysoev.ru static nxt_int_t
268653Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
268753Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
268853Sigor@sysoev.ru {
268953Sigor@sysoev.ru     nxt_int_t                 ret;
269053Sigor@sysoev.ru     nxt_uint_t                i, threads;
269153Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
269220Sigor@sysoev.ru 
269353Sigor@sysoev.ru     recf = tmcf->engines->elts;
2694591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
269520Sigor@sysoev.ru 
269653Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
269753Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
269853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
269953Sigor@sysoev.ru             return ret;
270053Sigor@sysoev.ru         }
270120Sigor@sysoev.ru     }
270220Sigor@sysoev.ru 
270320Sigor@sysoev.ru     return NXT_OK;
270420Sigor@sysoev.ru }
270553Sigor@sysoev.ru 
270653Sigor@sysoev.ru 
270753Sigor@sysoev.ru static nxt_int_t
270853Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
270953Sigor@sysoev.ru     nxt_event_engine_t *engine)
271053Sigor@sysoev.ru {
271153Sigor@sysoev.ru     nxt_int_t            ret;
271253Sigor@sysoev.ru     nxt_thread_link_t    *link;
271353Sigor@sysoev.ru     nxt_thread_handle_t  handle;
271453Sigor@sysoev.ru 
271553Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
271653Sigor@sysoev.ru 
271753Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
271853Sigor@sysoev.ru         return NXT_ERROR;
271953Sigor@sysoev.ru     }
272053Sigor@sysoev.ru 
272153Sigor@sysoev.ru     link->start = nxt_router_thread_start;
272253Sigor@sysoev.ru     link->engine = engine;
272353Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
272453Sigor@sysoev.ru     link->work.task = task;
272553Sigor@sysoev.ru     link->work.data = link;
272653Sigor@sysoev.ru 
272753Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
272853Sigor@sysoev.ru 
272953Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
273053Sigor@sysoev.ru 
273153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
273253Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
273353Sigor@sysoev.ru     }
273453Sigor@sysoev.ru 
273553Sigor@sysoev.ru     return ret;
273653Sigor@sysoev.ru }
273753Sigor@sysoev.ru 
273853Sigor@sysoev.ru 
273953Sigor@sysoev.ru static void
2740343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2741343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2742133Sigor@sysoev.ru {
2743507Smax.romanov@nginx.com     nxt_app_t  *app;
2744141Smax.romanov@nginx.com 
2745141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2746133Sigor@sysoev.ru 
2747753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2748343Smax.romanov@nginx.com 
2749141Smax.romanov@nginx.com     } nxt_queue_loop;
2750133Sigor@sysoev.ru 
2751133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2752133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2753133Sigor@sysoev.ru }
2754133Sigor@sysoev.ru 
2755133Sigor@sysoev.ru 
2756133Sigor@sysoev.ru static void
2757315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
275853Sigor@sysoev.ru {
275953Sigor@sysoev.ru     nxt_uint_t                n;
2760315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
276153Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
276253Sigor@sysoev.ru 
276353Sigor@sysoev.ru     recf = tmcf->engines->elts;
276453Sigor@sysoev.ru 
276553Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2766315Sigor@sysoev.ru         engine = recf->engine;
2767315Sigor@sysoev.ru 
2768315Sigor@sysoev.ru         switch (recf->action) {
2769315Sigor@sysoev.ru 
2770315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2771315Sigor@sysoev.ru             break;
2772315Sigor@sysoev.ru 
2773315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2774315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2775315Sigor@sysoev.ru             break;
2776315Sigor@sysoev.ru 
2777315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2778315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2779315Sigor@sysoev.ru             break;
2780315Sigor@sysoev.ru         }
2781315Sigor@sysoev.ru 
2782316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2783316Sigor@sysoev.ru 
278453Sigor@sysoev.ru         recf++;
278553Sigor@sysoev.ru     }
278653Sigor@sysoev.ru }
278753Sigor@sysoev.ru 
278853Sigor@sysoev.ru 
278953Sigor@sysoev.ru static void
2790315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
279153Sigor@sysoev.ru {
2792154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2793154Sigor@sysoev.ru 
2794315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2795154Sigor@sysoev.ru         next = work->next;
2796154Sigor@sysoev.ru         work->next = NULL;
2797154Sigor@sysoev.ru 
2798315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
279953Sigor@sysoev.ru     }
280053Sigor@sysoev.ru }
280153Sigor@sysoev.ru 
280253Sigor@sysoev.ru 
2803320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2804616Smax.romanov@nginx.com     .rpc_error = nxt_port_rpc_handler,
2805616Smax.romanov@nginx.com     .mmap      = nxt_port_mmap_handler,
2806616Smax.romanov@nginx.com     .data      = nxt_port_rpc_handler,
28071321Smax.romanov@nginx.com     .oosm      = nxt_router_oosm_handler,
280888Smax.romanov@nginx.com };
280988Smax.romanov@nginx.com 
281088Smax.romanov@nginx.com 
281188Smax.romanov@nginx.com static void
281253Sigor@sysoev.ru nxt_router_thread_start(void *data)
281353Sigor@sysoev.ru {
2814141Smax.romanov@nginx.com     nxt_int_t           ret;
2815141Smax.romanov@nginx.com     nxt_port_t          *port;
281688Smax.romanov@nginx.com     nxt_task_t          *task;
281753Sigor@sysoev.ru     nxt_thread_t        *thread;
281853Sigor@sysoev.ru     nxt_thread_link_t   *link;
281953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
282053Sigor@sysoev.ru 
282153Sigor@sysoev.ru     link = data;
282253Sigor@sysoev.ru     engine = link->engine;
282388Smax.romanov@nginx.com     task = &engine->task;
282453Sigor@sysoev.ru 
282553Sigor@sysoev.ru     thread = nxt_thread();
282653Sigor@sysoev.ru 
2827165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2828165Smax.romanov@nginx.com 
282953Sigor@sysoev.ru     /* STUB */
283053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
283153Sigor@sysoev.ru 
283253Sigor@sysoev.ru     engine->task.thread = thread;
283353Sigor@sysoev.ru     engine->task.log = thread->log;
283453Sigor@sysoev.ru     thread->engine = engine;
283563Sigor@sysoev.ru     thread->task = &engine->task;
2836326Svbart@nginx.com #if 0
283753Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2838326Svbart@nginx.com #endif
283953Sigor@sysoev.ru 
284063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2841337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2842337Sigor@sysoev.ru         return;
2843337Sigor@sysoev.ru     }
284453Sigor@sysoev.ru 
2845197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2846197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2847141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2848141Smax.romanov@nginx.com         return;
2849141Smax.romanov@nginx.com     }
2850141Smax.romanov@nginx.com 
2851141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2852141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2853343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2854141Smax.romanov@nginx.com         return;
2855141Smax.romanov@nginx.com     }
2856141Smax.romanov@nginx.com 
2857141Smax.romanov@nginx.com     engine->port = port;
2858141Smax.romanov@nginx.com 
2859320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2860141Smax.romanov@nginx.com 
286153Sigor@sysoev.ru     nxt_event_engine_start(engine);
286253Sigor@sysoev.ru }
286353Sigor@sysoev.ru 
286453Sigor@sysoev.ru 
286553Sigor@sysoev.ru static void
286653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
286753Sigor@sysoev.ru {
2868153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2869359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2870359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
287153Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2872359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
287353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
287453Sigor@sysoev.ru 
2875153Sigor@sysoev.ru     job = obj;
287653Sigor@sysoev.ru     joint = data;
287753Sigor@sysoev.ru 
2878159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2879159Sigor@sysoev.ru 
2880359Sigor@sysoev.ru     skcf = joint->socket_conf;
2881359Sigor@sysoev.ru     ls = skcf->listen;
2882359Sigor@sysoev.ru 
2883359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2884359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2885359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
288653Sigor@sysoev.ru         return;
288753Sigor@sysoev.ru     }
288853Sigor@sysoev.ru 
2889359Sigor@sysoev.ru     lev->socket.data = joint;
2890359Sigor@sysoev.ru 
2891359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2892359Sigor@sysoev.ru 
2893359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2894359Sigor@sysoev.ru     ls->count++;
2895359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2896139Sigor@sysoev.ru 
2897153Sigor@sysoev.ru     job->work.next = NULL;
2898153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2899153Sigor@sysoev.ru 
2900153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
290153Sigor@sysoev.ru }
290253Sigor@sysoev.ru 
290353Sigor@sysoev.ru 
290453Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
290553Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
290653Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
290753Sigor@sysoev.ru {
2908115Sigor@sysoev.ru     nxt_socket_t        fd;
2909115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2910359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2911359Sigor@sysoev.ru 
2912359Sigor@sysoev.ru     fd = skcf->listen->socket;
291353Sigor@sysoev.ru 
2914115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2915115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2916115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
291753Sigor@sysoev.ru     {
2918359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2919359Sigor@sysoev.ru 
2920359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2921359Sigor@sysoev.ru             return lev;
292253Sigor@sysoev.ru         }
292353Sigor@sysoev.ru     }
292453Sigor@sysoev.ru 
292553Sigor@sysoev.ru     return NULL;
292653Sigor@sysoev.ru }
292753Sigor@sysoev.ru 
292853Sigor@sysoev.ru 
292953Sigor@sysoev.ru static void
293053Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
293153Sigor@sysoev.ru {
2932153Sigor@sysoev.ru     nxt_joint_job_t          *job;
293353Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2934359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
293553Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
293653Sigor@sysoev.ru 
2937153Sigor@sysoev.ru     job = obj;
293853Sigor@sysoev.ru     joint = data;
293953Sigor@sysoev.ru 
2940139Sigor@sysoev.ru     engine = task->thread->engine;
2941139Sigor@sysoev.ru 
2942159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2943159Sigor@sysoev.ru 
2944359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2945359Sigor@sysoev.ru                                   joint->socket_conf);
2946359Sigor@sysoev.ru 
2947359Sigor@sysoev.ru     old = lev->socket.data;
2948359Sigor@sysoev.ru     lev->socket.data = joint;
2949359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
295053Sigor@sysoev.ru 
2951153Sigor@sysoev.ru     job->work.next = NULL;
2952153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2953153Sigor@sysoev.ru 
2954153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2955139Sigor@sysoev.ru 
2956181Smax.romanov@nginx.com     /*
2957181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2958181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2959181Smax.romanov@nginx.com      */
2960181Smax.romanov@nginx.com 
2961181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
296253Sigor@sysoev.ru }
296353Sigor@sysoev.ru 
296453Sigor@sysoev.ru 
296553Sigor@sysoev.ru static void
296653Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
296753Sigor@sysoev.ru {
2968153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2969153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2970359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2971153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2972153Sigor@sysoev.ru 
2973153Sigor@sysoev.ru     job = obj;
297453Sigor@sysoev.ru     skcf = data;
297553Sigor@sysoev.ru 
2976139Sigor@sysoev.ru     engine = task->thread->engine;
2977139Sigor@sysoev.ru 
2978359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2979359Sigor@sysoev.ru 
2980359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
298153Sigor@sysoev.ru 
2982163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2983359Sigor@sysoev.ru               lev->socket.fd);
2984359Sigor@sysoev.ru 
2985359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2986359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2987359Sigor@sysoev.ru 
2988359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2989139Sigor@sysoev.ru 
2990153Sigor@sysoev.ru     job->work.next = NULL;
2991153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2992153Sigor@sysoev.ru 
2993153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
299453Sigor@sysoev.ru }
299553Sigor@sysoev.ru 
299653Sigor@sysoev.ru 
299753Sigor@sysoev.ru static void
2998313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2999313Sigor@sysoev.ru {
3000313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3001313Sigor@sysoev.ru 
3002313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
3003313Sigor@sysoev.ru 
3004313Sigor@sysoev.ru     engine = task->thread->engine;
3005313Sigor@sysoev.ru 
3006313Sigor@sysoev.ru     engine->shutdown = 1;
3007313Sigor@sysoev.ru 
3008313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
3009313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3010313Sigor@sysoev.ru     }
3011313Sigor@sysoev.ru }
3012313Sigor@sysoev.ru 
3013313Sigor@sysoev.ru 
3014313Sigor@sysoev.ru static void
301553Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
301653Sigor@sysoev.ru {
301753Sigor@sysoev.ru     nxt_timer_t              *timer;
3018359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
301953Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
302053Sigor@sysoev.ru 
302153Sigor@sysoev.ru     timer = obj;
3022359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
302353Sigor@sysoev.ru 
3024163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
3025359Sigor@sysoev.ru               lev->socket.fd);
3026359Sigor@sysoev.ru 
3027359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
3028359Sigor@sysoev.ru 
3029683Sigor@sysoev.ru     joint = lev->socket.data;
3030683Sigor@sysoev.ru     lev->socket.data = NULL;
3031683Sigor@sysoev.ru 
3032359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
3033123Smax.romanov@nginx.com     task = &task->thread->engine->task;
3034123Smax.romanov@nginx.com 
3035359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
3036359Sigor@sysoev.ru 
3037683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
303853Sigor@sysoev.ru }
303953Sigor@sysoev.ru 
304053Sigor@sysoev.ru 
304153Sigor@sysoev.ru static void
3042359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
304353Sigor@sysoev.ru {
3044359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
304553Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
304653Sigor@sysoev.ru 
3047359Sigor@sysoev.ru     ls = skcf->listen;
3048118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
304953Sigor@sysoev.ru 
305053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
305153Sigor@sysoev.ru 
3052359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
3053359Sigor@sysoev.ru               task->thread->engine, ls->count);
3054359Sigor@sysoev.ru 
3055359Sigor@sysoev.ru     if (--ls->count != 0) {
3056359Sigor@sysoev.ru         ls = NULL;
305753Sigor@sysoev.ru     }
305853Sigor@sysoev.ru 
305953Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
306053Sigor@sysoev.ru 
3061359Sigor@sysoev.ru     if (ls != NULL) {
3062359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
3063359Sigor@sysoev.ru         nxt_free(ls);
306453Sigor@sysoev.ru     }
306553Sigor@sysoev.ru }
306653Sigor@sysoev.ru 
306753Sigor@sysoev.ru 
3068683Sigor@sysoev.ru void
3069683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3070683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
3071683Sigor@sysoev.ru {
3072683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3073683Sigor@sysoev.ru 
3074683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
3075683Sigor@sysoev.ru 
3076683Sigor@sysoev.ru     if (--lev->count == 0) {
3077683Sigor@sysoev.ru         nxt_free(lev);
3078683Sigor@sysoev.ru     }
3079683Sigor@sysoev.ru 
3080683Sigor@sysoev.ru     if (joint != NULL) {
3081683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
3082683Sigor@sysoev.ru     }
3083683Sigor@sysoev.ru 
3084683Sigor@sysoev.ru     engine = task->thread->engine;
3085683Sigor@sysoev.ru 
3086683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3087683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3088683Sigor@sysoev.ru     }
3089683Sigor@sysoev.ru }
3090683Sigor@sysoev.ru 
3091683Sigor@sysoev.ru 
3092683Sigor@sysoev.ru void
309353Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
309453Sigor@sysoev.ru {
309553Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
309653Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
309753Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
309853Sigor@sysoev.ru 
3099163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
310053Sigor@sysoev.ru 
310153Sigor@sysoev.ru     if (--joint->count != 0) {
310253Sigor@sysoev.ru         return;
310353Sigor@sysoev.ru     }
310453Sigor@sysoev.ru 
310553Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
310653Sigor@sysoev.ru 
3107530Sigor@sysoev.ru     /*
3108530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
3109530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
3110530Sigor@sysoev.ru      * be already destroyed by another thread.
3111530Sigor@sysoev.ru      */
311253Sigor@sysoev.ru     skcf = joint->socket_conf;
311353Sigor@sysoev.ru     rtcf = skcf->router_conf;
311453Sigor@sysoev.ru     lock = &rtcf->router->lock;
311553Sigor@sysoev.ru 
311653Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
311753Sigor@sysoev.ru 
3118163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3119163Smax.romanov@nginx.com               rtcf, rtcf->count);
3120163Smax.romanov@nginx.com 
312153Sigor@sysoev.ru     if (--skcf->count != 0) {
3122952Sigor@sysoev.ru         skcf = NULL;
312353Sigor@sysoev.ru         rtcf = NULL;
312453Sigor@sysoev.ru 
312553Sigor@sysoev.ru     } else {
312653Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
312753Sigor@sysoev.ru 
312853Sigor@sysoev.ru         if (--rtcf->count != 0) {
312953Sigor@sysoev.ru             rtcf = NULL;
313053Sigor@sysoev.ru         }
313153Sigor@sysoev.ru     }
313253Sigor@sysoev.ru 
313353Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
313453Sigor@sysoev.ru 
3135952Sigor@sysoev.ru     if (skcf != NULL) {
31361264Sigor@sysoev.ru         if (skcf->action != NULL) {
31371264Sigor@sysoev.ru             nxt_http_action_cleanup(task, skcf->action);
3138964Sigor@sysoev.ru         }
3139964Sigor@sysoev.ru 
3140952Sigor@sysoev.ru #if (NXT_TLS)
3141952Sigor@sysoev.ru         if (skcf->tls != NULL) {
3142952Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
3143952Sigor@sysoev.ru         }
3144952Sigor@sysoev.ru #endif
3145952Sigor@sysoev.ru     }
3146952Sigor@sysoev.ru 
3147141Smax.romanov@nginx.com     /* TODO remove engine->port */
3148141Smax.romanov@nginx.com     /* TODO excude from connected ports */
3149141Smax.romanov@nginx.com 
315053Sigor@sysoev.ru     if (rtcf != NULL) {
3151115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
3152131Smax.romanov@nginx.com 
3153964Sigor@sysoev.ru         nxt_http_routes_cleanup(task, rtcf->routes);
3154964Sigor@sysoev.ru 
3155630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
3156630Svbart@nginx.com 
3157131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
3158131Smax.romanov@nginx.com 
315965Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
316053Sigor@sysoev.ru     }
316153Sigor@sysoev.ru }
316253Sigor@sysoev.ru 
316353Sigor@sysoev.ru 
316453Sigor@sysoev.ru static void
3165630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3166630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3167630Svbart@nginx.com {
3168630Svbart@nginx.com     size_t     size;
3169630Svbart@nginx.com     u_char     *buf, *p;
3170630Svbart@nginx.com     nxt_off_t  bytes;
3171630Svbart@nginx.com 
3172630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
3173630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
3174630Svbart@nginx.com         nxt_router_access_log_date,
3175630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3176703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
3177630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
3178630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
3179630Svbart@nginx.com     };
3180630Svbart@nginx.com 
3181630Svbart@nginx.com     size = r->remote->address_length
3182630Svbart@nginx.com            + 6                  /* ' - - [' */
3183630Svbart@nginx.com            + date_cache.size
3184630Svbart@nginx.com            + 3                  /* '] "' */
3185630Svbart@nginx.com            + r->method->length
3186630Svbart@nginx.com            + 1                  /* space */
3187630Svbart@nginx.com            + r->target.length
3188630Svbart@nginx.com            + 1                  /* space */
3189630Svbart@nginx.com            + r->version.length
3190630Svbart@nginx.com            + 2                  /* '" ' */
3191630Svbart@nginx.com            + 3                  /* status */
3192630Svbart@nginx.com            + 1                  /* space */
3193630Svbart@nginx.com            + NXT_OFF_T_LEN
3194630Svbart@nginx.com            + 2                  /* ' "' */
3195630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3196630Svbart@nginx.com            + 3                  /* '" "' */
3197630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3198630Svbart@nginx.com            + 2                  /* '"\n' */
3199630Svbart@nginx.com     ;
3200630Svbart@nginx.com 
3201630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3202630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3203630Svbart@nginx.com         return;
3204630Svbart@nginx.com     }
3205630Svbart@nginx.com 
3206630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3207630Svbart@nginx.com                    r->remote->address_length);
3208630Svbart@nginx.com 
3209630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3210630Svbart@nginx.com 
3211630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3212630Svbart@nginx.com 
3213630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3214630Svbart@nginx.com 
3215630Svbart@nginx.com     if (r->method->length != 0) {
3216630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3217630Svbart@nginx.com 
3218630Svbart@nginx.com         if (r->target.length != 0) {
3219630Svbart@nginx.com             *p++ = ' ';
3220630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3221630Svbart@nginx.com 
3222630Svbart@nginx.com             if (r->version.length != 0) {
3223630Svbart@nginx.com                 *p++ = ' ';
3224630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3225630Svbart@nginx.com             }
3226630Svbart@nginx.com         }
3227630Svbart@nginx.com 
3228630Svbart@nginx.com     } else {
3229630Svbart@nginx.com         *p++ = '-';
3230630Svbart@nginx.com     }
3231630Svbart@nginx.com 
3232630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3233630Svbart@nginx.com 
3234630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3235630Svbart@nginx.com 
3236630Svbart@nginx.com     *p++ = ' ';
3237630Svbart@nginx.com 
32381112Sigor@sysoev.ru     bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3239630Svbart@nginx.com 
3240630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3241630Svbart@nginx.com 
3242630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3243630Svbart@nginx.com 
3244630Svbart@nginx.com     if (r->referer != NULL) {
3245630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3246630Svbart@nginx.com 
3247630Svbart@nginx.com     } else {
3248630Svbart@nginx.com         *p++ = '-';
3249630Svbart@nginx.com     }
3250630Svbart@nginx.com 
3251630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3252630Svbart@nginx.com 
3253630Svbart@nginx.com     if (r->user_agent != NULL) {
3254630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3255630Svbart@nginx.com 
3256630Svbart@nginx.com     } else {
3257630Svbart@nginx.com         *p++ = '-';
3258630Svbart@nginx.com     }
3259630Svbart@nginx.com 
3260630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3261630Svbart@nginx.com 
3262630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3263630Svbart@nginx.com }
3264630Svbart@nginx.com 
3265630Svbart@nginx.com 
3266630Svbart@nginx.com static u_char *
3267630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3268630Svbart@nginx.com     size_t size, const char *format)
3269630Svbart@nginx.com {
3270630Svbart@nginx.com     u_char  sign;
3271630Svbart@nginx.com     time_t  gmtoff;
3272630Svbart@nginx.com 
3273630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3274630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3275630Svbart@nginx.com 
3276630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3277630Svbart@nginx.com 
3278630Svbart@nginx.com     if (gmtoff < 0) {
3279630Svbart@nginx.com         gmtoff = -gmtoff;
3280630Svbart@nginx.com         sign = '-';
3281630Svbart@nginx.com 
3282630Svbart@nginx.com     } else {
3283630Svbart@nginx.com         sign = '+';
3284630Svbart@nginx.com     }
3285630Svbart@nginx.com 
3286630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3287630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3288630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3289630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3290630Svbart@nginx.com }
3291630Svbart@nginx.com 
3292630Svbart@nginx.com 
3293630Svbart@nginx.com static void
3294630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3295630Svbart@nginx.com {
3296630Svbart@nginx.com     uint32_t                 stream;
3297648Svbart@nginx.com     nxt_int_t                ret;
3298630Svbart@nginx.com     nxt_buf_t                *b;
3299630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3300630Svbart@nginx.com     nxt_runtime_t            *rt;
3301630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3302630Svbart@nginx.com 
3303630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3304630Svbart@nginx.com 
3305630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3306630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3307630Svbart@nginx.com         goto fail;
3308630Svbart@nginx.com     }
3309630Svbart@nginx.com 
3310630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3311630Svbart@nginx.com     *b->mem.free++ = '\0';
3312630Svbart@nginx.com 
3313630Svbart@nginx.com     rt = task->thread->runtime;
3314630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3315630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3316630Svbart@nginx.com 
3317630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3318630Svbart@nginx.com                                            nxt_router_access_log_ready,
3319630Svbart@nginx.com                                            nxt_router_access_log_error,
3320630Svbart@nginx.com                                            -1, tmcf);
3321630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3322630Svbart@nginx.com         goto fail;
3323630Svbart@nginx.com     }
3324630Svbart@nginx.com 
3325648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3326648Svbart@nginx.com                                 stream, router_port->id, b);
3327648Svbart@nginx.com 
3328648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3329648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3330648Svbart@nginx.com         goto fail;
3331648Svbart@nginx.com     }
3332630Svbart@nginx.com 
3333630Svbart@nginx.com     return;
3334630Svbart@nginx.com 
3335630Svbart@nginx.com fail:
3336630Svbart@nginx.com 
3337630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3338630Svbart@nginx.com }
3339630Svbart@nginx.com 
3340630Svbart@nginx.com 
3341630Svbart@nginx.com static void
3342630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3343630Svbart@nginx.com     void *data)
3344630Svbart@nginx.com {
3345630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3346630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3347630Svbart@nginx.com 
3348630Svbart@nginx.com     tmcf = data;
3349630Svbart@nginx.com 
3350630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3351630Svbart@nginx.com 
3352630Svbart@nginx.com     access_log->fd = msg->fd;
3353630Svbart@nginx.com 
3354630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3355630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3356630Svbart@nginx.com }
3357630Svbart@nginx.com 
3358630Svbart@nginx.com 
3359630Svbart@nginx.com static void
3360630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3361630Svbart@nginx.com     void *data)
3362630Svbart@nginx.com {
3363630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3364630Svbart@nginx.com 
3365630Svbart@nginx.com     tmcf = data;
3366630Svbart@nginx.com 
3367630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3368630Svbart@nginx.com }
3369630Svbart@nginx.com 
3370630Svbart@nginx.com 
3371630Svbart@nginx.com static void
3372630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3373630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3374630Svbart@nginx.com {
3375630Svbart@nginx.com     if (access_log == NULL) {
3376630Svbart@nginx.com         return;
3377630Svbart@nginx.com     }
3378630Svbart@nginx.com 
3379630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3380630Svbart@nginx.com 
3381630Svbart@nginx.com     if (--access_log->count != 0) {
3382630Svbart@nginx.com         access_log = NULL;
3383630Svbart@nginx.com     }
3384630Svbart@nginx.com 
3385630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3386630Svbart@nginx.com 
3387630Svbart@nginx.com     if (access_log != NULL) {
3388630Svbart@nginx.com 
3389630Svbart@nginx.com         if (access_log->fd != -1) {
3390630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3391630Svbart@nginx.com         }
3392630Svbart@nginx.com 
3393630Svbart@nginx.com         nxt_free(access_log);
3394630Svbart@nginx.com     }
3395630Svbart@nginx.com }
3396630Svbart@nginx.com 
3397630Svbart@nginx.com 
3398631Svbart@nginx.com typedef struct {
3399631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3400631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3401631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3402631Svbart@nginx.com 
3403631Svbart@nginx.com 
3404631Svbart@nginx.com void
3405631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3406631Svbart@nginx.com {
3407631Svbart@nginx.com     nxt_mp_t                        *mp;
3408631Svbart@nginx.com     uint32_t                        stream;
3409631Svbart@nginx.com     nxt_int_t                       ret;
3410631Svbart@nginx.com     nxt_buf_t                       *b;
3411631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3412631Svbart@nginx.com     nxt_runtime_t                   *rt;
3413631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3414631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3415631Svbart@nginx.com 
3416631Svbart@nginx.com     access_log = nxt_router->access_log;
3417631Svbart@nginx.com 
3418631Svbart@nginx.com     if (access_log == NULL) {
3419631Svbart@nginx.com         return;
3420631Svbart@nginx.com     }
3421631Svbart@nginx.com 
3422631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3423631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3424631Svbart@nginx.com         return;
3425631Svbart@nginx.com     }
3426631Svbart@nginx.com 
3427631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3428631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3429631Svbart@nginx.com         goto fail;
3430631Svbart@nginx.com     }
3431631Svbart@nginx.com 
3432631Svbart@nginx.com     reopen->mem_pool = mp;
3433631Svbart@nginx.com     reopen->access_log = access_log;
3434631Svbart@nginx.com 
3435631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3436631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3437631Svbart@nginx.com         goto fail;
3438631Svbart@nginx.com     }
3439631Svbart@nginx.com 
3440651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3441651Svbart@nginx.com 
3442631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3443631Svbart@nginx.com     *b->mem.free++ = '\0';
3444631Svbart@nginx.com 
3445631Svbart@nginx.com     rt = task->thread->runtime;
3446631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3447631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3448631Svbart@nginx.com 
3449631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3450631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3451631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3452631Svbart@nginx.com                                            -1, reopen);
3453631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3454631Svbart@nginx.com         goto fail;
3455631Svbart@nginx.com     }
3456631Svbart@nginx.com 
3457631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3458631Svbart@nginx.com                                 stream, router_port->id, b);
3459631Svbart@nginx.com 
3460631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3461631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3462631Svbart@nginx.com         goto fail;
3463631Svbart@nginx.com     }
3464631Svbart@nginx.com 
3465651Svbart@nginx.com     nxt_mp_retain(mp);
3466651Svbart@nginx.com 
3467631Svbart@nginx.com     return;
3468631Svbart@nginx.com 
3469631Svbart@nginx.com fail:
3470631Svbart@nginx.com 
3471631Svbart@nginx.com     nxt_mp_destroy(mp);
3472631Svbart@nginx.com }
3473631Svbart@nginx.com 
3474631Svbart@nginx.com 
3475631Svbart@nginx.com static void
3476651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3477651Svbart@nginx.com {
3478651Svbart@nginx.com     nxt_mp_t   *mp;
3479651Svbart@nginx.com     nxt_buf_t  *b;
3480651Svbart@nginx.com 
3481651Svbart@nginx.com     b = obj;
3482651Svbart@nginx.com     mp = b->data;
3483651Svbart@nginx.com 
3484651Svbart@nginx.com     nxt_mp_release(mp);
3485651Svbart@nginx.com }
3486651Svbart@nginx.com 
3487651Svbart@nginx.com 
3488651Svbart@nginx.com static void
3489631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3490631Svbart@nginx.com     void *data)
3491631Svbart@nginx.com {
3492631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3493631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3494631Svbart@nginx.com 
3495631Svbart@nginx.com     reopen = data;
3496631Svbart@nginx.com 
3497631Svbart@nginx.com     access_log = reopen->access_log;
3498631Svbart@nginx.com 
3499631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3500631Svbart@nginx.com 
3501631Svbart@nginx.com         if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) {
3502631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3503631Svbart@nginx.com                       msg->fd, access_log->fd, nxt_errno);
3504631Svbart@nginx.com         }
3505631Svbart@nginx.com     }
3506631Svbart@nginx.com 
3507631Svbart@nginx.com     nxt_fd_close(msg->fd);
3508651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3509631Svbart@nginx.com }
3510631Svbart@nginx.com 
3511631Svbart@nginx.com 
3512631Svbart@nginx.com static void
3513631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3514631Svbart@nginx.com     void *data)
3515631Svbart@nginx.com {
3516631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3517631Svbart@nginx.com 
3518631Svbart@nginx.com     reopen = data;
3519631Svbart@nginx.com 
3520651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3521631Svbart@nginx.com }
3522631Svbart@nginx.com 
3523631Svbart@nginx.com 
3524630Svbart@nginx.com static void
352553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
352653Sigor@sysoev.ru {
3527141Smax.romanov@nginx.com     nxt_port_t           *port;
352853Sigor@sysoev.ru     nxt_thread_link_t    *link;
352953Sigor@sysoev.ru     nxt_event_engine_t   *engine;
353053Sigor@sysoev.ru     nxt_thread_handle_t  handle;
353153Sigor@sysoev.ru 
353258Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
353353Sigor@sysoev.ru     link = data;
353453Sigor@sysoev.ru 
353553Sigor@sysoev.ru     nxt_thread_wait(handle);
353653Sigor@sysoev.ru 
353753Sigor@sysoev.ru     engine = link->engine;
353853Sigor@sysoev.ru 
353953Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
354053Sigor@sysoev.ru 
3541141Smax.romanov@nginx.com     port = engine->port;
3542141Smax.romanov@nginx.com 
3543141Smax.romanov@nginx.com     // TODO notify all apps
3544141Smax.romanov@nginx.com 
3545343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3546163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3547343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3548163Smax.romanov@nginx.com 
3549163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
355063Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
355153Sigor@sysoev.ru 
355253Sigor@sysoev.ru     nxt_event_engine_free(engine);
355353Sigor@sysoev.ru 
355453Sigor@sysoev.ru     nxt_free(link);
355553Sigor@sysoev.ru }
355653Sigor@sysoev.ru 
355753Sigor@sysoev.ru 
355853Sigor@sysoev.ru static void
3559318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3560318Smax.romanov@nginx.com     void *data)
356188Smax.romanov@nginx.com {
35621123Smax.romanov@nginx.com     nxt_int_t               ret;
35631269Sigor@sysoev.ru     nxt_buf_t               *b, *next;
35641131Smax.romanov@nginx.com     nxt_port_t              *app_port;
35651123Smax.romanov@nginx.com     nxt_unit_field_t        *f;
35661123Smax.romanov@nginx.com     nxt_http_field_t        *field;
35671123Smax.romanov@nginx.com     nxt_http_request_t      *r;
35681123Smax.romanov@nginx.com     nxt_unit_response_t     *resp;
35691131Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
35701123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
357188Smax.romanov@nginx.com 
357288Smax.romanov@nginx.com     b = msg->buf;
35731123Smax.romanov@nginx.com     req_rpc_data = data;
357488Smax.romanov@nginx.com 
357588Smax.romanov@nginx.com     if (msg->size == 0) {
357688Smax.romanov@nginx.com         b = NULL;
357788Smax.romanov@nginx.com     }
357888Smax.romanov@nginx.com 
35791123Smax.romanov@nginx.com     r = req_rpc_data->request;
35801007Salexander.borisov@nginx.com     if (nxt_slow_path(r == NULL)) {
3581570Smax.romanov@nginx.com         return;
3582570Smax.romanov@nginx.com     }
3583425Smax.romanov@nginx.com 
35841007Salexander.borisov@nginx.com     if (r->error) {
35851123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3586608Sigor@sysoev.ru         return;
3587608Sigor@sysoev.ru     }
3588608Sigor@sysoev.ru 
358988Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
359088Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
359188Smax.romanov@nginx.com 
35921007Salexander.borisov@nginx.com         nxt_buf_chain_add(&b, nxt_http_buf_last(r));
3593167Smax.romanov@nginx.com 
35941123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3595425Smax.romanov@nginx.com 
3596425Smax.romanov@nginx.com     } else {
35971123Smax.romanov@nginx.com         if (req_rpc_data->app != NULL && req_rpc_data->app->timeout != 0) {
35981007Salexander.borisov@nginx.com             r->timer.handler = nxt_router_app_timeout;
35991123Smax.romanov@nginx.com             r->timer_data = req_rpc_data;
36001123Smax.romanov@nginx.com             nxt_timer_add(task->thread->engine, &r->timer,
36011123Smax.romanov@nginx.com                           req_rpc_data->app->timeout);
3602425Smax.romanov@nginx.com         }
360388Smax.romanov@nginx.com     }
360488Smax.romanov@nginx.com 
360588Smax.romanov@nginx.com     if (b == NULL) {
360688Smax.romanov@nginx.com         return;
360788Smax.romanov@nginx.com     }
360888Smax.romanov@nginx.com 
3609206Smax.romanov@nginx.com     if (msg->buf == b) {
3610206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3611206Smax.romanov@nginx.com         msg->buf = NULL;
3612206Smax.romanov@nginx.com     }
3613194Smax.romanov@nginx.com 
3614431Sigor@sysoev.ru     if (r->header_sent) {
3615431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3616431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3617277Sigor@sysoev.ru 
361888Smax.romanov@nginx.com     } else {
3619743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3620743Smax.romanov@nginx.com 
3621743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3622743Smax.romanov@nginx.com             goto fail;
3623743Smax.romanov@nginx.com         }
3624743Smax.romanov@nginx.com 
3625743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3626743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3627743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3628743Smax.romanov@nginx.com             goto fail;
3629743Smax.romanov@nginx.com         }
3630743Smax.romanov@nginx.com 
36311126Smax.romanov@nginx.com         field = NULL;
36321126Smax.romanov@nginx.com 
3633743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
36341126Smax.romanov@nginx.com             if (f->skip) {
36351126Smax.romanov@nginx.com                 continue;
36361126Smax.romanov@nginx.com             }
36371126Smax.romanov@nginx.com 
36381007Salexander.borisov@nginx.com             field = nxt_list_add(r->resp.fields);
3639743Smax.romanov@nginx.com 
3640743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3641743Smax.romanov@nginx.com                 goto fail;
3642743Smax.romanov@nginx.com             }
3643743Smax.romanov@nginx.com 
3644743Smax.romanov@nginx.com             field->hash = f->hash;
36451126Smax.romanov@nginx.com             field->skip = 0;
36461270Sigor@sysoev.ru             field->hopbyhop = 0;
3647743Smax.romanov@nginx.com 
3648743Smax.romanov@nginx.com             field->name_length = f->name_length;
3649743Smax.romanov@nginx.com             field->value_length = f->value_length;
3650743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3651743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3652743Smax.romanov@nginx.com 
36531126Smax.romanov@nginx.com             ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
36541126Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
36551126Smax.romanov@nginx.com                 goto fail;
36561126Smax.romanov@nginx.com             }
36571126Smax.romanov@nginx.com 
36581126Smax.romanov@nginx.com             nxt_debug(task, "header%s: %*s: %*s",
36591126Smax.romanov@nginx.com                       (field->skip ? " skipped" : ""),
3660743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3661743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
36621126Smax.romanov@nginx.com 
36631126Smax.romanov@nginx.com             if (field->skip) {
36641126Smax.romanov@nginx.com                 r->resp.fields->last->nelts--;
36651126Smax.romanov@nginx.com             }
3666743Smax.romanov@nginx.com         }
36671007Salexander.borisov@nginx.com 
3668743Smax.romanov@nginx.com         r->status = resp->status;
3669743Smax.romanov@nginx.com 
3670743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3671743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3672743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3673743Smax.romanov@nginx.com 
3674743Smax.romanov@nginx.com         } else {
3675743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3676743Smax.romanov@nginx.com         }
3677743Smax.romanov@nginx.com 
3678435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
36791269Sigor@sysoev.ru             next = b->next;
36801269Sigor@sysoev.ru             b->next = NULL;
36811269Sigor@sysoev.ru 
3682435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3683435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3684507Smax.romanov@nginx.com 
36851269Sigor@sysoev.ru             b = next;
3686520Smax.romanov@nginx.com         }
3687520Smax.romanov@nginx.com 
3688520Smax.romanov@nginx.com         if (b != NULL) {
3689431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3690431Sigor@sysoev.ru         }
3691431Sigor@sysoev.ru 
36921270Sigor@sysoev.ru         nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL);
36931127Smax.romanov@nginx.com 
36941131Smax.romanov@nginx.com         if (r->websocket_handshake
36951131Smax.romanov@nginx.com             && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
36961131Smax.romanov@nginx.com         {
36971131Smax.romanov@nginx.com             req_app_link = nxt_request_app_link_alloc(task,
36981131Smax.romanov@nginx.com                                                      req_rpc_data->req_app_link,
36991131Smax.romanov@nginx.com                                                      req_rpc_data);
37001131Smax.romanov@nginx.com             if (nxt_slow_path(req_app_link == NULL)) {
37011131Smax.romanov@nginx.com                 goto fail;
37021131Smax.romanov@nginx.com             }
37031131Smax.romanov@nginx.com 
37041131Smax.romanov@nginx.com             app_port = req_app_link->app_port;
37051131Smax.romanov@nginx.com 
37061131Smax.romanov@nginx.com             if (app_port == NULL && req_rpc_data->app_port != NULL) {
37071131Smax.romanov@nginx.com                 req_app_link->app_port = req_rpc_data->app_port;
37081131Smax.romanov@nginx.com                 app_port = req_app_link->app_port;
37091131Smax.romanov@nginx.com                 req_app_link->apr_action = req_rpc_data->apr_action;
37101131Smax.romanov@nginx.com 
37111131Smax.romanov@nginx.com                 req_rpc_data->app_port = NULL;
37121131Smax.romanov@nginx.com             }
37131131Smax.romanov@nginx.com 
37141131Smax.romanov@nginx.com             if (nxt_slow_path(app_port == NULL)) {
37151131Smax.romanov@nginx.com                 goto fail;
37161131Smax.romanov@nginx.com             }
37171131Smax.romanov@nginx.com 
37181131Smax.romanov@nginx.com             nxt_thread_mutex_lock(&req_rpc_data->app->mutex);
37191131Smax.romanov@nginx.com 
37201131Smax.romanov@nginx.com             nxt_queue_insert_tail(&app_port->active_websockets,
37211131Smax.romanov@nginx.com                                   &req_app_link->link_port_websockets);
37221131Smax.romanov@nginx.com 
37231131Smax.romanov@nginx.com             nxt_thread_mutex_unlock(&req_rpc_data->app->mutex);
37241131Smax.romanov@nginx.com 
37251131Smax.romanov@nginx.com             nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE);
37261131Smax.romanov@nginx.com             req_app_link->apr_action = NXT_APR_CLOSE;
37271131Smax.romanov@nginx.com 
37281131Smax.romanov@nginx.com             nxt_debug(task, "req_app_link stream #%uD upgrade",
37291131Smax.romanov@nginx.com                       req_app_link->stream);
37301131Smax.romanov@nginx.com 
37311131Smax.romanov@nginx.com             r->state = &nxt_http_websocket;
37321131Smax.romanov@nginx.com 
37331131Smax.romanov@nginx.com         } else {
37341131Smax.romanov@nginx.com             r->state = &nxt_http_request_send_state;
37351131Smax.romanov@nginx.com         }
3736431Sigor@sysoev.ru     }
3737431Sigor@sysoev.ru 
3738431Sigor@sysoev.ru     return;
3739431Sigor@sysoev.ru 
3740431Sigor@sysoev.ru fail:
3741431Sigor@sysoev.ru 
3742615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3743615Smax.romanov@nginx.com 
37441123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3745431Sigor@sysoev.ru }
3746431Sigor@sysoev.ru 
3747431Sigor@sysoev.ru 
3748431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3749431Sigor@sysoev.ru     nxt_aligned(64) =
3750431Sigor@sysoev.ru {
3751943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
3752431Sigor@sysoev.ru };
3753431Sigor@sysoev.ru 
3754431Sigor@sysoev.ru 
3755431Sigor@sysoev.ru static void
3756431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3757431Sigor@sysoev.ru {
3758431Sigor@sysoev.ru     nxt_buf_t           *out;
3759431Sigor@sysoev.ru     nxt_http_request_t  *r;
3760431Sigor@sysoev.ru 
3761431Sigor@sysoev.ru     r = obj;
3762431Sigor@sysoev.ru 
3763431Sigor@sysoev.ru     out = r->out;
3764431Sigor@sysoev.ru 
3765431Sigor@sysoev.ru     if (out != NULL) {
3766431Sigor@sysoev.ru         r->out = NULL;
3767431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
376888Smax.romanov@nginx.com     }
376988Smax.romanov@nginx.com }
377088Smax.romanov@nginx.com 
3771277Sigor@sysoev.ru 
3772318Smax.romanov@nginx.com static void
3773318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3774318Smax.romanov@nginx.com     void *data)
3775318Smax.romanov@nginx.com {
37761123Smax.romanov@nginx.com     nxt_int_t               res;
37771123Smax.romanov@nginx.com     nxt_port_t              *port;
37781123Smax.romanov@nginx.com     nxt_bool_t              cancelled;
37791123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
37801123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
37811123Smax.romanov@nginx.com 
37821123Smax.romanov@nginx.com     req_rpc_data = data;
37831123Smax.romanov@nginx.com 
37841123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
37851123Smax.romanov@nginx.com 
37861123Smax.romanov@nginx.com     if (req_app_link != NULL) {
37871123Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &req_app_link->msg_info,
37881123Smax.romanov@nginx.com                                           req_app_link->stream);
3789425Smax.romanov@nginx.com         if (cancelled) {
37901123Smax.romanov@nginx.com             res = nxt_router_app_port(task, req_rpc_data->app, req_app_link);
3791425Smax.romanov@nginx.com 
3792425Smax.romanov@nginx.com             if (res == NXT_OK) {
37931123Smax.romanov@nginx.com                 port = req_app_link->app_port;
3794425Smax.romanov@nginx.com 
3795551Smax.romanov@nginx.com                 if (nxt_slow_path(port == NULL)) {
37961123Smax.romanov@nginx.com                     nxt_log(task, NXT_LOG_ERR,
37971123Smax.romanov@nginx.com                             "port is NULL in cancelled req_app_link");
3798551Smax.romanov@nginx.com                     return;
3799551Smax.romanov@nginx.com                 }
3800425Smax.romanov@nginx.com 
38011123Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port,
38021123Smax.romanov@nginx.com                                          req_rpc_data, port->pid);
38031123Smax.romanov@nginx.com 
38041123Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, req_app_link);
3805425Smax.romanov@nginx.com             }
3806425Smax.romanov@nginx.com 
3807425Smax.romanov@nginx.com             msg->port_msg.last = 0;
3808425Smax.romanov@nginx.com 
3809425Smax.romanov@nginx.com             return;
3810425Smax.romanov@nginx.com         }
3811425Smax.romanov@nginx.com     }
3812425Smax.romanov@nginx.com 
38131123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
38141123Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
3815616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3816616Smax.romanov@nginx.com     }
3817318Smax.romanov@nginx.com 
38181123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3819318Smax.romanov@nginx.com }
3820318Smax.romanov@nginx.com 
3821318Smax.romanov@nginx.com 
3822141Smax.romanov@nginx.com static void
3823343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3824343Smax.romanov@nginx.com     void *data)
3825192Smax.romanov@nginx.com {
3826753Smax.romanov@nginx.com     nxt_app_t        *app;
3827753Smax.romanov@nginx.com     nxt_port_t       *port;
3828753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3829753Smax.romanov@nginx.com 
3830753Smax.romanov@nginx.com     app_joint = data;
3831347Smax.romanov@nginx.com     port = msg->u.new_port;
3832343Smax.romanov@nginx.com 
3833753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3834343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3835343Smax.romanov@nginx.com 
3836753Smax.romanov@nginx.com     app = app_joint->app;
3837753Smax.romanov@nginx.com 
3838753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3839753Smax.romanov@nginx.com 
3840753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3841753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3842753Smax.romanov@nginx.com 
3843753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3844753Smax.romanov@nginx.com 
3845753Smax.romanov@nginx.com         return;
3846753Smax.romanov@nginx.com     }
3847753Smax.romanov@nginx.com 
3848343Smax.romanov@nginx.com     port->app = app;
3849343Smax.romanov@nginx.com 
3850343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3851343Smax.romanov@nginx.com 
3852507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3853507Smax.romanov@nginx.com 
3854507Smax.romanov@nginx.com     app->pending_processes--;
3855507Smax.romanov@nginx.com     app->processes++;
3856343Smax.romanov@nginx.com 
3857343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3858343Smax.romanov@nginx.com 
3859507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3860507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3861343Smax.romanov@nginx.com 
38621123Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT);
3863192Smax.romanov@nginx.com }
3864192Smax.romanov@nginx.com 
3865192Smax.romanov@nginx.com 
3866192Smax.romanov@nginx.com static void
3867343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3868343Smax.romanov@nginx.com     void *data)
3869192Smax.romanov@nginx.com {
38701123Smax.romanov@nginx.com     nxt_app_t               *app;
38711123Smax.romanov@nginx.com     nxt_app_joint_t         *app_joint;
38721123Smax.romanov@nginx.com     nxt_queue_link_t        *lnk;
38731123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
3874343Smax.romanov@nginx.com 
3875753Smax.romanov@nginx.com     app_joint = data;
3876753Smax.romanov@nginx.com 
3877753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3878753Smax.romanov@nginx.com 
3879753Smax.romanov@nginx.com     app = app_joint->app;
3880753Smax.romanov@nginx.com 
3881753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3882753Smax.romanov@nginx.com 
3883753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3884753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
3885753Smax.romanov@nginx.com 
3886753Smax.romanov@nginx.com         return;
3887753Smax.romanov@nginx.com     }
3888343Smax.romanov@nginx.com 
3889343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
3890343Smax.romanov@nginx.com 
3891343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3892343Smax.romanov@nginx.com 
3893507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3894507Smax.romanov@nginx.com 
3895507Smax.romanov@nginx.com     app->pending_processes--;
3896318Smax.romanov@nginx.com 
3897318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
3898318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
3899318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3900343Smax.romanov@nginx.com         lnk->next = NULL;
3901318Smax.romanov@nginx.com 
39021123Smax.romanov@nginx.com         req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t,
39031123Smax.romanov@nginx.com                                            link_app_requests);
3904318Smax.romanov@nginx.com 
3905343Smax.romanov@nginx.com     } else {
39061123Smax.romanov@nginx.com         req_app_link = NULL;
3907343Smax.romanov@nginx.com     }
3908343Smax.romanov@nginx.com 
3909343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3910343Smax.romanov@nginx.com 
39111123Smax.romanov@nginx.com     if (req_app_link != NULL) {
3912318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
39131123Smax.romanov@nginx.com                   &app->name, app, req_app_link->stream);
39141123Smax.romanov@nginx.com 
39151446Smax.romanov@nginx.com         nxt_request_app_link_error(task, app, req_app_link,
39161123Smax.romanov@nginx.com                                    "Failed to start application process");
39171123Smax.romanov@nginx.com         nxt_request_app_link_use(task, req_app_link, -1);
3918318Smax.romanov@nginx.com     }
3919192Smax.romanov@nginx.com }
3920192Smax.romanov@nginx.com 
3921753Smax.romanov@nginx.com nxt_inline nxt_port_t *
3922753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app);
3923192Smax.romanov@nginx.com 
3924343Smax.romanov@nginx.com void
3925343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
3926141Smax.romanov@nginx.com {
3927343Smax.romanov@nginx.com     int  c;
3928343Smax.romanov@nginx.com 
3929343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
3930343Smax.romanov@nginx.com 
3931343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
3932343Smax.romanov@nginx.com 
3933753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
3934753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
3935753Smax.romanov@nginx.com 
3936753Smax.romanov@nginx.com         } else {
3937753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
3938753Smax.romanov@nginx.com         }
3939163Smax.romanov@nginx.com     }
3940343Smax.romanov@nginx.com }
3941343Smax.romanov@nginx.com 
3942343Smax.romanov@nginx.com 
3943424Smax.romanov@nginx.com nxt_inline nxt_bool_t
3944424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
3945424Smax.romanov@nginx.com {
3946424Smax.romanov@nginx.com     nxt_port_t        *port;
3947424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3948424Smax.romanov@nginx.com 
3949424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3950424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3951424Smax.romanov@nginx.com 
3952424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
3953424Smax.romanov@nginx.com }
3954424Smax.romanov@nginx.com 
3955424Smax.romanov@nginx.com 
3956343Smax.romanov@nginx.com nxt_inline nxt_port_t *
3957427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
3958343Smax.romanov@nginx.com {
3959343Smax.romanov@nginx.com     nxt_port_t        *port;
3960343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3961343Smax.romanov@nginx.com 
3962343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3963343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
3964343Smax.romanov@nginx.com 
3965343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3966343Smax.romanov@nginx.com 
3967424Smax.romanov@nginx.com     port->app_pending_responses++;
3968424Smax.romanov@nginx.com 
3969507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3970507Smax.romanov@nginx.com         app->idle_processes--;
3971507Smax.romanov@nginx.com 
3972507Smax.romanov@nginx.com         if (port->idle_start == 0) {
3973507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
3974507Smax.romanov@nginx.com 
3975507Smax.romanov@nginx.com         } else {
3976507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
3977507Smax.romanov@nginx.com 
3978507Smax.romanov@nginx.com             port->idle_start = 0;
3979507Smax.romanov@nginx.com         }
3980507Smax.romanov@nginx.com     }
3981507Smax.romanov@nginx.com 
3982428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
3983428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3984428Smax.romanov@nginx.com         && (app->max_requests == 0
3985428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3986428Smax.romanov@nginx.com                 < app->max_requests))
3987277Sigor@sysoev.ru     {
3988343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
3989343Smax.romanov@nginx.com 
3990425Smax.romanov@nginx.com         nxt_port_inc_use(port);
3991425Smax.romanov@nginx.com 
3992343Smax.romanov@nginx.com     } else {
3993343Smax.romanov@nginx.com         lnk->next = NULL;
3994167Smax.romanov@nginx.com     }
3995167Smax.romanov@nginx.com 
3996343Smax.romanov@nginx.com     return port;
3997163Smax.romanov@nginx.com }
3998163Smax.romanov@nginx.com 
3999163Smax.romanov@nginx.com 
4000507Smax.romanov@nginx.com nxt_inline nxt_port_t *
4001507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
4002141Smax.romanov@nginx.com {
4003343Smax.romanov@nginx.com     nxt_port_t  *port;
4004141Smax.romanov@nginx.com 
4005141Smax.romanov@nginx.com     port = NULL;
4006141Smax.romanov@nginx.com 
4007141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4008141Smax.romanov@nginx.com 
4009343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
4010343Smax.romanov@nginx.com 
4011424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
4012343Smax.romanov@nginx.com             port = NULL;
4013343Smax.romanov@nginx.com 
4014343Smax.romanov@nginx.com             continue;
4015343Smax.romanov@nginx.com         }
4016343Smax.romanov@nginx.com 
4017507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
4018507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4019507Smax.romanov@nginx.com 
4020507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
4021507Smax.romanov@nginx.com             app->idle_processes--;
4022507Smax.romanov@nginx.com         }
4023507Smax.romanov@nginx.com 
4024507Smax.romanov@nginx.com         port->app = NULL;
4025507Smax.romanov@nginx.com         app->processes--;
4026343Smax.romanov@nginx.com 
4027343Smax.romanov@nginx.com         break;
4028343Smax.romanov@nginx.com 
4029343Smax.romanov@nginx.com     } nxt_queue_loop;
4030141Smax.romanov@nginx.com 
4031141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4032141Smax.romanov@nginx.com 
4033141Smax.romanov@nginx.com     return port;
4034141Smax.romanov@nginx.com }
4035141Smax.romanov@nginx.com 
4036141Smax.romanov@nginx.com 
4037141Smax.romanov@nginx.com static void
4038753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
4039507Smax.romanov@nginx.com {
4040753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
4041507Smax.romanov@nginx.com 
4042507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
4043507Smax.romanov@nginx.com 
4044753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
4045507Smax.romanov@nginx.com }
4046507Smax.romanov@nginx.com 
4047507Smax.romanov@nginx.com 
4048507Smax.romanov@nginx.com static void
4049343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
4050141Smax.romanov@nginx.com {
40511123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
40521123Smax.romanov@nginx.com 
40531123Smax.romanov@nginx.com     req_app_link = data;
4054538Svbart@nginx.com 
4055538Svbart@nginx.com #if (NXT_DEBUG)
4056538Svbart@nginx.com     {
4057538Svbart@nginx.com     nxt_app_t  *app;
4058538Svbart@nginx.com 
4059343Smax.romanov@nginx.com     app = obj;
4060141Smax.romanov@nginx.com 
4061141Smax.romanov@nginx.com     nxt_assert(app != NULL);
40621123Smax.romanov@nginx.com     nxt_assert(req_app_link != NULL);
40631123Smax.romanov@nginx.com     nxt_assert(req_app_link->app_port != NULL);
4064343Smax.romanov@nginx.com 
4065343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
40661123Smax.romanov@nginx.com               &app->name, app, req_app_link->stream);
4067538Svbart@nginx.com     }
4068538Svbart@nginx.com #endif
4069343Smax.romanov@nginx.com 
40701123Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, req_app_link);
40711294Smax.romanov@nginx.com 
40721294Smax.romanov@nginx.com     nxt_request_app_link_use(task, req_app_link, -1);
4073343Smax.romanov@nginx.com }
4074343Smax.romanov@nginx.com 
4075343Smax.romanov@nginx.com 
4076343Smax.romanov@nginx.com static void
4077343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
40781123Smax.romanov@nginx.com     nxt_apr_action_t action)
4079343Smax.romanov@nginx.com {
40801123Smax.romanov@nginx.com     int                      inc_use;
40811123Smax.romanov@nginx.com     uint32_t                 dec_pending, got_response;
4082427Smax.romanov@nginx.com     nxt_app_t                *app;
4083507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
4084507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
4085427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
40861123Smax.romanov@nginx.com     nxt_request_app_link_t   *req_app_link, *pending_ra, *re_ra;
4087427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4088343Smax.romanov@nginx.com 
4089343Smax.romanov@nginx.com     nxt_assert(port != NULL);
4090343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
4091343Smax.romanov@nginx.com 
40921123Smax.romanov@nginx.com     req_app_link = NULL;
4093427Smax.romanov@nginx.com 
4094343Smax.romanov@nginx.com     app = port->app;
4095343Smax.romanov@nginx.com 
40961123Smax.romanov@nginx.com     inc_use = 0;
40971123Smax.romanov@nginx.com     dec_pending = 0;
40981123Smax.romanov@nginx.com     got_response = 0;
40991123Smax.romanov@nginx.com 
41001123Smax.romanov@nginx.com     switch (action) {
41011123Smax.romanov@nginx.com     case NXT_APR_NEW_PORT:
41021123Smax.romanov@nginx.com         break;
41031123Smax.romanov@nginx.com     case NXT_APR_REQUEST_FAILED:
41041123Smax.romanov@nginx.com         dec_pending = 1;
41051123Smax.romanov@nginx.com         inc_use = -1;
41061123Smax.romanov@nginx.com         break;
41071123Smax.romanov@nginx.com     case NXT_APR_GOT_RESPONSE:
41081123Smax.romanov@nginx.com         dec_pending = 1;
41091123Smax.romanov@nginx.com         got_response = 1;
41101123Smax.romanov@nginx.com         inc_use = -1;
41111123Smax.romanov@nginx.com         break;
41121131Smax.romanov@nginx.com     case NXT_APR_UPGRADE:
41131131Smax.romanov@nginx.com         dec_pending = 1;
41141131Smax.romanov@nginx.com         got_response = 1;
41151131Smax.romanov@nginx.com         break;
41161123Smax.romanov@nginx.com     case NXT_APR_CLOSE:
41171123Smax.romanov@nginx.com         inc_use = -1;
41181123Smax.romanov@nginx.com         break;
41191123Smax.romanov@nginx.com     }
41201123Smax.romanov@nginx.com 
4121343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4122343Smax.romanov@nginx.com 
41231123Smax.romanov@nginx.com     port->app_pending_responses -= dec_pending;
4124343Smax.romanov@nginx.com     port->app_responses += got_response;
4125343Smax.romanov@nginx.com 
4126427Smax.romanov@nginx.com     if (port->pair[1] != -1
4127426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
4128428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
4129428Smax.romanov@nginx.com         && (app->max_requests == 0
4130428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
4131428Smax.romanov@nginx.com                 < app->max_requests))
4132343Smax.romanov@nginx.com     {
4133424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
4134424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
4135424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
4136424Smax.romanov@nginx.com 
4137424Smax.romanov@nginx.com             } else {
4138424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
4139424Smax.romanov@nginx.com             }
4140424Smax.romanov@nginx.com 
4141425Smax.romanov@nginx.com             nxt_port_inc_use(port);
4142424Smax.romanov@nginx.com 
4143424Smax.romanov@nginx.com         } else {
4144424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
4145424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
4146424Smax.romanov@nginx.com             {
4147424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
4148424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
4149424Smax.romanov@nginx.com             }
4150424Smax.romanov@nginx.com         }
4151141Smax.romanov@nginx.com     }
4152141Smax.romanov@nginx.com 
4153427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
4154426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
4155343Smax.romanov@nginx.com     {
4156141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
4157141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4158343Smax.romanov@nginx.com         lnk->next = NULL;
4159141Smax.romanov@nginx.com 
41601123Smax.romanov@nginx.com         req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t,
41611123Smax.romanov@nginx.com                                            link_app_requests);
41621123Smax.romanov@nginx.com 
41631123Smax.romanov@nginx.com         req_app_link->app_port = nxt_router_pop_first_port(app);
41641123Smax.romanov@nginx.com 
41651123Smax.romanov@nginx.com         if (req_app_link->app_port->app_pending_responses > 1) {
41661123Smax.romanov@nginx.com             nxt_request_app_link_pending(task, app, req_app_link);
4167425Smax.romanov@nginx.com         }
4168425Smax.romanov@nginx.com     }
4169425Smax.romanov@nginx.com 
4170427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
41711123Smax.romanov@nginx.com     if (dec_pending > 0
4172425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
4173425Smax.romanov@nginx.com     {
4174425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
4175425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4176425Smax.romanov@nginx.com         lnk->next = NULL;
4177425Smax.romanov@nginx.com 
41781123Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
4179427Smax.romanov@nginx.com                                          link_port_pending);
4180427Smax.romanov@nginx.com 
4181427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
4182427Smax.romanov@nginx.com 
4183427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
4184427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
4185425Smax.romanov@nginx.com 
4186425Smax.romanov@nginx.com     } else {
4187427Smax.romanov@nginx.com         pending_ra = NULL;
4188141Smax.romanov@nginx.com     }
4189141Smax.romanov@nginx.com 
4190427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
4191427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
4192427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
4193427Smax.romanov@nginx.com 
41941123Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
41951123Smax.romanov@nginx.com                                     link_app_pending);
4196427Smax.romanov@nginx.com 
4197427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
4198427Smax.romanov@nginx.com 
4199427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
4200427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
4201427Smax.romanov@nginx.com 
4202427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
4203427Smax.romanov@nginx.com                                               re_ra->stream);
4204427Smax.romanov@nginx.com 
4205427Smax.romanov@nginx.com             if (cancelled) {
42061123Smax.romanov@nginx.com                 state.req_app_link = re_ra;
4207427Smax.romanov@nginx.com                 state.app = app;
4208427Smax.romanov@nginx.com 
42091375Smax.romanov@nginx.com                 /*
42101375Smax.romanov@nginx.com                  * Need to increment use count "in advance" because
42111375Smax.romanov@nginx.com                  * nxt_router_port_select() will remove re_ra from lists
42121375Smax.romanov@nginx.com                  * and decrement use count.
42131375Smax.romanov@nginx.com                  */
42141375Smax.romanov@nginx.com                 nxt_request_app_link_inc_use(re_ra);
42151375Smax.romanov@nginx.com 
4216427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
4217427Smax.romanov@nginx.com 
4218427Smax.romanov@nginx.com                 goto re_ra_cancelled;
4219427Smax.romanov@nginx.com             }
4220427Smax.romanov@nginx.com         }
4221427Smax.romanov@nginx.com     }
4222427Smax.romanov@nginx.com 
4223427Smax.romanov@nginx.com     re_ra = NULL;
4224427Smax.romanov@nginx.com 
4225427Smax.romanov@nginx.com re_ra_cancelled:
4226427Smax.romanov@nginx.com 
4227753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
4228753Smax.romanov@nginx.com                  && port->app_pending_responses == 0
4229753Smax.romanov@nginx.com                  && port->app_responses >= app->max_requests);
4230367Smax.romanov@nginx.com 
4231507Smax.romanov@nginx.com     if (send_quit) {
4232507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
4233507Smax.romanov@nginx.com 
4234507Smax.romanov@nginx.com         port->app = NULL;
4235507Smax.romanov@nginx.com         app->processes--;
4236507Smax.romanov@nginx.com 
4237507Smax.romanov@nginx.com     } else {
4238507Smax.romanov@nginx.com         port_unchained = 0;
4239507Smax.romanov@nginx.com     }
4240507Smax.romanov@nginx.com 
4241507Smax.romanov@nginx.com     adjust_idle_timer = 0;
4242507Smax.romanov@nginx.com 
42431131Smax.romanov@nginx.com     if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0
42441131Smax.romanov@nginx.com         && nxt_queue_is_empty(&port->active_websockets)
42451131Smax.romanov@nginx.com         && port->idle_link.next == NULL)
42461131Smax.romanov@nginx.com     {
4247507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
4248507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
4249507Smax.romanov@nginx.com         {
4250507Smax.romanov@nginx.com             adjust_idle_timer = 1;
4251507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
4252507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
4253507Smax.romanov@nginx.com         }
4254507Smax.romanov@nginx.com 
4255507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
4256507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
4257507Smax.romanov@nginx.com 
4258507Smax.romanov@nginx.com         } else {
4259507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
4260507Smax.romanov@nginx.com 
4261507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
4262507Smax.romanov@nginx.com         }
4263507Smax.romanov@nginx.com 
4264507Smax.romanov@nginx.com         app->idle_processes++;
4265507Smax.romanov@nginx.com     }
4266507Smax.romanov@nginx.com 
4267343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4268343Smax.romanov@nginx.com 
4269507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4270507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4271507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4272507Smax.romanov@nginx.com     }
4273507Smax.romanov@nginx.com 
4274427Smax.romanov@nginx.com     if (pending_ra != NULL) {
42751123Smax.romanov@nginx.com         nxt_request_app_link_use(task, pending_ra, -1);
4276427Smax.romanov@nginx.com     }
4277427Smax.romanov@nginx.com 
4278427Smax.romanov@nginx.com     if (re_ra != NULL) {
4279427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
42801294Smax.romanov@nginx.com             /*
42811375Smax.romanov@nginx.com              * Reference counter already incremented above, this will
42821375Smax.romanov@nginx.com              * keep re_ra while nxt_router_app_process_request()
42831375Smax.romanov@nginx.com              * task is in queue.  Reference counter decreased in
42841375Smax.romanov@nginx.com              * nxt_router_app_process_request() after processing.
42851294Smax.romanov@nginx.com              */
42861294Smax.romanov@nginx.com 
4287427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4288427Smax.romanov@nginx.com                                nxt_router_app_process_request,
4289427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
42901375Smax.romanov@nginx.com 
42911375Smax.romanov@nginx.com         } else {
42921375Smax.romanov@nginx.com             nxt_request_app_link_use(task, re_ra, -1);
4293427Smax.romanov@nginx.com         }
4294425Smax.romanov@nginx.com     }
4295425Smax.romanov@nginx.com 
42961123Smax.romanov@nginx.com     if (req_app_link != NULL) {
42971294Smax.romanov@nginx.com         /*
42981350Smax.romanov@nginx.com          * There should be call nxt_request_app_link_inc_use(req_app_link),
42991350Smax.romanov@nginx.com          * because of one more link in the queue.  But one link was
43001375Smax.romanov@nginx.com          * recently removed from app->requests linked list.
43011375Smax.romanov@nginx.com          * Corresponding decrement is in nxt_router_app_process_request().
43021294Smax.romanov@nginx.com          */
4303425Smax.romanov@nginx.com 
4304343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4305343Smax.romanov@nginx.com                            nxt_router_app_process_request,
43061123Smax.romanov@nginx.com                            &task->thread->engine->task, app, req_app_link);
4307343Smax.romanov@nginx.com 
4308343Smax.romanov@nginx.com         goto adjust_use;
4309343Smax.romanov@nginx.com     }
4310343Smax.romanov@nginx.com 
4311343Smax.romanov@nginx.com     /* ? */
4312163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
4313343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4314343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
4315343Smax.romanov@nginx.com 
4316343Smax.romanov@nginx.com         goto adjust_use;
4317163Smax.romanov@nginx.com     }
4318163Smax.romanov@nginx.com 
4319367Smax.romanov@nginx.com     if (send_quit) {
4320507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
4321167Smax.romanov@nginx.com                   &app->name, app);
4322163Smax.romanov@nginx.com 
4323163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
4324163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
4325163Smax.romanov@nginx.com 
4326507Smax.romanov@nginx.com         if (port_unchained) {
4327507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
4328507Smax.romanov@nginx.com         }
4329507Smax.romanov@nginx.com 
4330343Smax.romanov@nginx.com         goto adjust_use;
4331163Smax.romanov@nginx.com     }
4332163Smax.romanov@nginx.com 
4333167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4334167Smax.romanov@nginx.com               &app->name, app);
4335141Smax.romanov@nginx.com 
4336343Smax.romanov@nginx.com adjust_use:
4337343Smax.romanov@nginx.com 
43381123Smax.romanov@nginx.com     nxt_port_use(task, port, inc_use);
4339141Smax.romanov@nginx.com }
4340141Smax.romanov@nginx.com 
4341141Smax.romanov@nginx.com 
4342343Smax.romanov@nginx.com void
4343343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4344141Smax.romanov@nginx.com {
4345507Smax.romanov@nginx.com     nxt_app_t         *app;
4346507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4347507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4348507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4349141Smax.romanov@nginx.com 
4350141Smax.romanov@nginx.com     app = port->app;
4351343Smax.romanov@nginx.com 
4352343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4353141Smax.romanov@nginx.com 
4354141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4355141Smax.romanov@nginx.com 
4356507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4357507Smax.romanov@nginx.com 
4358507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4359507Smax.romanov@nginx.com         app->idle_processes--;
4360507Smax.romanov@nginx.com 
4361507Smax.romanov@nginx.com         if (port->idle_start == 0
4362507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4363507Smax.romanov@nginx.com         {
4364507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4365507Smax.romanov@nginx.com 
4366507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4367507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4368507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4369507Smax.romanov@nginx.com 
4370507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4371507Smax.romanov@nginx.com 
4372507Smax.romanov@nginx.com             idle_port->idle_start = 0;
4373507Smax.romanov@nginx.com         }
4374343Smax.romanov@nginx.com     }
4375343Smax.romanov@nginx.com 
4376507Smax.romanov@nginx.com     app->processes--;
4377507Smax.romanov@nginx.com 
4378753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4379507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
4380507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
4381507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
4382507Smax.romanov@nginx.com 
4383507Smax.romanov@nginx.com     if (start_process) {
4384507Smax.romanov@nginx.com         app->pending_processes++;
4385163Smax.romanov@nginx.com     }
4386141Smax.romanov@nginx.com 
4387141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4388163Smax.romanov@nginx.com 
4389507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4390343Smax.romanov@nginx.com 
4391343Smax.romanov@nginx.com     if (unchain) {
4392343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4393163Smax.romanov@nginx.com     }
4394163Smax.romanov@nginx.com 
4395507Smax.romanov@nginx.com     if (start_process) {
4396507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4397507Smax.romanov@nginx.com     }
4398507Smax.romanov@nginx.com }
4399507Smax.romanov@nginx.com 
4400507Smax.romanov@nginx.com 
4401507Smax.romanov@nginx.com static void
4402507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4403507Smax.romanov@nginx.com {
4404507Smax.romanov@nginx.com     nxt_app_t           *app;
4405507Smax.romanov@nginx.com     nxt_bool_t          queued;
4406507Smax.romanov@nginx.com     nxt_port_t          *port;
4407507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4408507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4409507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4410507Smax.romanov@nginx.com 
4411507Smax.romanov@nginx.com     app = obj;
4412507Smax.romanov@nginx.com     queued = (data == app);
4413507Smax.romanov@nginx.com 
4414507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4415507Smax.romanov@nginx.com               &app->name, queued);
4416507Smax.romanov@nginx.com 
4417507Smax.romanov@nginx.com     engine = task->thread->engine;
4418507Smax.romanov@nginx.com 
4419507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
4420507Smax.romanov@nginx.com 
4421811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
4422507Smax.romanov@nginx.com     timeout = 0;
4423507Smax.romanov@nginx.com 
4424507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4425507Smax.romanov@nginx.com 
4426507Smax.romanov@nginx.com     if (queued) {
4427507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
4428343Smax.romanov@nginx.com     }
4429507Smax.romanov@nginx.com 
4430507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
4431507Smax.romanov@nginx.com 
4432551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4433507Smax.romanov@nginx.com 
4434507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
4435507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4436507Smax.romanov@nginx.com 
4437507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
4438507Smax.romanov@nginx.com 
4439507Smax.romanov@nginx.com         if (timeout > threshold) {
4440507Smax.romanov@nginx.com             break;
4441507Smax.romanov@nginx.com         }
4442507Smax.romanov@nginx.com 
4443507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4444507Smax.romanov@nginx.com         lnk->next = NULL;
4445507Smax.romanov@nginx.com 
4446507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4447507Smax.romanov@nginx.com 
4448507Smax.romanov@nginx.com         app->idle_processes--;
4449507Smax.romanov@nginx.com         app->processes--;
4450507Smax.romanov@nginx.com         port->app = NULL;
4451507Smax.romanov@nginx.com 
4452507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4453507Smax.romanov@nginx.com 
4454507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4455507Smax.romanov@nginx.com                   &app->name, port->pid);
4456507Smax.romanov@nginx.com 
4457507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4458507Smax.romanov@nginx.com 
4459507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4460507Smax.romanov@nginx.com 
4461507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4462507Smax.romanov@nginx.com     }
4463507Smax.romanov@nginx.com 
4464507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4465507Smax.romanov@nginx.com 
4466507Smax.romanov@nginx.com     if (timeout > threshold) {
4467753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4468507Smax.romanov@nginx.com 
4469507Smax.romanov@nginx.com     } else {
4470753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4471507Smax.romanov@nginx.com     }
4472507Smax.romanov@nginx.com 
4473507Smax.romanov@nginx.com     if (queued) {
4474507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4475507Smax.romanov@nginx.com     }
4476507Smax.romanov@nginx.com }
4477507Smax.romanov@nginx.com 
4478507Smax.romanov@nginx.com 
4479507Smax.romanov@nginx.com static void
4480507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4481507Smax.romanov@nginx.com {
4482753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4483753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4484507Smax.romanov@nginx.com 
4485507Smax.romanov@nginx.com     timer = obj;
4486753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4487753Smax.romanov@nginx.com 
4488753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4489753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4490753Smax.romanov@nginx.com     }
4491753Smax.romanov@nginx.com }
4492753Smax.romanov@nginx.com 
4493753Smax.romanov@nginx.com 
4494753Smax.romanov@nginx.com static void
4495753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4496753Smax.romanov@nginx.com {
4497753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4498753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4499753Smax.romanov@nginx.com 
4500753Smax.romanov@nginx.com     timer = obj;
4501753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4502753Smax.romanov@nginx.com 
4503753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4504507Smax.romanov@nginx.com }
4505507Smax.romanov@nginx.com 
4506507Smax.romanov@nginx.com 
4507507Smax.romanov@nginx.com static void
4508753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4509507Smax.romanov@nginx.com {
4510753Smax.romanov@nginx.com     nxt_app_t        *app;
4511753Smax.romanov@nginx.com     nxt_port_t       *port;
4512753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4513753Smax.romanov@nginx.com 
4514753Smax.romanov@nginx.com     app_joint = obj;
4515753Smax.romanov@nginx.com     app = app_joint->app;
4516753Smax.romanov@nginx.com 
4517753Smax.romanov@nginx.com     for ( ;; ) {
4518753Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
4519753Smax.romanov@nginx.com         if (port == NULL) {
4520753Smax.romanov@nginx.com             break;
4521753Smax.romanov@nginx.com         }
4522753Smax.romanov@nginx.com 
4523753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4524753Smax.romanov@nginx.com 
4525753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4526753Smax.romanov@nginx.com 
4527753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4528753Smax.romanov@nginx.com     }
4529753Smax.romanov@nginx.com 
4530753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
4531753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4532753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->requests));
4533753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4534753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4535753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4536753Smax.romanov@nginx.com 
4537753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
4538753Smax.romanov@nginx.com     nxt_free(app);
4539753Smax.romanov@nginx.com 
4540753Smax.romanov@nginx.com     app_joint->app = NULL;
4541753Smax.romanov@nginx.com 
4542753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4543753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4544753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4545753Smax.romanov@nginx.com 
4546753Smax.romanov@nginx.com     } else {
4547753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4548753Smax.romanov@nginx.com     }
4549141Smax.romanov@nginx.com }
4550141Smax.romanov@nginx.com 
4551141Smax.romanov@nginx.com 
4552427Smax.romanov@nginx.com static void
4553427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
4554141Smax.romanov@nginx.com {
45551294Smax.romanov@nginx.com     int                     ra_use_delta;
45561123Smax.romanov@nginx.com     nxt_app_t               *app;
45571123Smax.romanov@nginx.com     nxt_bool_t              can_start_process;
45581123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
45591123Smax.romanov@nginx.com 
45601123Smax.romanov@nginx.com     req_app_link = state->req_app_link;
4561427Smax.romanov@nginx.com     app = state->app;
4562427Smax.romanov@nginx.com 
4563427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
45641294Smax.romanov@nginx.com     ra_use_delta = -nxt_queue_chk_remove(&req_app_link->link_app_requests);
45651123Smax.romanov@nginx.com 
45661123Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&req_app_link->link_port_pending))
4567425Smax.romanov@nginx.com     {
45681123Smax.romanov@nginx.com         nxt_assert(req_app_link->link_app_pending.next != NULL);
45691123Smax.romanov@nginx.com 
45701123Smax.romanov@nginx.com         nxt_queue_remove(&req_app_link->link_app_pending);
45711123Smax.romanov@nginx.com         req_app_link->link_app_pending.next = NULL;
45721123Smax.romanov@nginx.com 
45731294Smax.romanov@nginx.com         ra_use_delta--;
45741123Smax.romanov@nginx.com     }
45751123Smax.romanov@nginx.com 
45761123Smax.romanov@nginx.com     state->failed_port = req_app_link->app_port;
45771123Smax.romanov@nginx.com 
45781123Smax.romanov@nginx.com     if (req_app_link->app_port != NULL) {
4579427Smax.romanov@nginx.com         state->failed_port_use_delta--;
4580427Smax.romanov@nginx.com 
4581427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
4582427Smax.romanov@nginx.com 
4583427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
4584427Smax.romanov@nginx.com             state->failed_port_use_delta--;
4585427Smax.romanov@nginx.com         }
4586427Smax.romanov@nginx.com 
45871123Smax.romanov@nginx.com         req_app_link->app_port = NULL;
4588427Smax.romanov@nginx.com     }
4589427Smax.romanov@nginx.com 
4590507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
4591507Smax.romanov@nginx.com 
4592427Smax.romanov@nginx.com     state->port = NULL;
4593507Smax.romanov@nginx.com     state->start_process = 0;
4594427Smax.romanov@nginx.com 
4595427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
4596507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
4597427Smax.romanov@nginx.com     {
45981123Smax.romanov@nginx.com         req_app_link = nxt_request_app_link_alloc(task, req_app_link,
45991123Smax.romanov@nginx.com                                                   req_app_link->req_rpc_data);
46001123Smax.romanov@nginx.com         if (nxt_slow_path(req_app_link == NULL)) {
4601427Smax.romanov@nginx.com             goto fail;
4602427Smax.romanov@nginx.com         }
4603427Smax.romanov@nginx.com 
4604427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
46051123Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests,
46061123Smax.romanov@nginx.com                                   &req_app_link->link_app_requests);
4607427Smax.romanov@nginx.com 
4608427Smax.romanov@nginx.com         } else {
46091123Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests,
46101123Smax.romanov@nginx.com                                   &req_app_link->link_app_requests);
4611427Smax.romanov@nginx.com         }
4612427Smax.romanov@nginx.com 
46131294Smax.romanov@nginx.com         ra_use_delta++;
46141123Smax.romanov@nginx.com 
46151123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD enqueue to app->requests",
46161123Smax.romanov@nginx.com                   req_app_link->stream);
4617427Smax.romanov@nginx.com 
4618507Smax.romanov@nginx.com         if (can_start_process) {
4619507Smax.romanov@nginx.com             app->pending_processes++;
4620507Smax.romanov@nginx.com             state->start_process = 1;
4621425Smax.romanov@nginx.com         }
4622425Smax.romanov@nginx.com 
4623425Smax.romanov@nginx.com     } else {
4624427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
4625427Smax.romanov@nginx.com 
4626427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
46271123Smax.romanov@nginx.com             req_app_link = nxt_request_app_link_alloc(task, req_app_link,
46281123Smax.romanov@nginx.com                                                     req_app_link->req_rpc_data);
46291123Smax.romanov@nginx.com             if (nxt_slow_path(req_app_link == NULL)) {
4630427Smax.romanov@nginx.com                 goto fail;
4631351Smax.romanov@nginx.com             }
4632427Smax.romanov@nginx.com 
46331123Smax.romanov@nginx.com             req_app_link->app_port = state->port;
46341123Smax.romanov@nginx.com 
46351123Smax.romanov@nginx.com             nxt_request_app_link_pending(task, app, req_app_link);
4636425Smax.romanov@nginx.com         }
4637507Smax.romanov@nginx.com 
4638507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
4639507Smax.romanov@nginx.com             app->pending_processes++;
4640507Smax.romanov@nginx.com             state->start_process = 1;
4641507Smax.romanov@nginx.com         }
4642343Smax.romanov@nginx.com     }
4643343Smax.romanov@nginx.com 
46441294Smax.romanov@nginx.com     nxt_request_app_link_chk_use(req_app_link, ra_use_delta);
46451294Smax.romanov@nginx.com 
4646427Smax.romanov@nginx.com fail:
4647427Smax.romanov@nginx.com 
46481123Smax.romanov@nginx.com     state->shared_ra = req_app_link;
4649427Smax.romanov@nginx.com }
4650427Smax.romanov@nginx.com 
4651427Smax.romanov@nginx.com 
4652427Smax.romanov@nginx.com static nxt_int_t
4653427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
4654427Smax.romanov@nginx.com {
46551123Smax.romanov@nginx.com     nxt_int_t               res;
46561123Smax.romanov@nginx.com     nxt_app_t               *app;
46571123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
46581123Smax.romanov@nginx.com 
46591123Smax.romanov@nginx.com     req_app_link = state->shared_ra;
4660427Smax.romanov@nginx.com     app = state->app;
4661427Smax.romanov@nginx.com 
4662427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
4663427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
4664425Smax.romanov@nginx.com     }
4665425Smax.romanov@nginx.com 
46661123Smax.romanov@nginx.com     if (nxt_slow_path(req_app_link == NULL)) {
4667427Smax.romanov@nginx.com         if (state->port != NULL) {
4668427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
4669425Smax.romanov@nginx.com         }
4670425Smax.romanov@nginx.com 
46711446Smax.romanov@nginx.com         nxt_request_app_link_error(task, app, state->req_app_link,
4672427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
4673427Smax.romanov@nginx.com 
4674351Smax.romanov@nginx.com         return NXT_ERROR;
4675351Smax.romanov@nginx.com     }
4676351Smax.romanov@nginx.com 
4677427Smax.romanov@nginx.com     if (state->port != NULL) {
4678343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
4679163Smax.romanov@nginx.com 
46801123Smax.romanov@nginx.com         req_app_link->app_port = state->port;
4681343Smax.romanov@nginx.com 
4682507Smax.romanov@nginx.com         if (state->start_process) {
4683507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
4684507Smax.romanov@nginx.com         }
4685507Smax.romanov@nginx.com 
4686141Smax.romanov@nginx.com         return NXT_OK;
4687141Smax.romanov@nginx.com     }
4688141Smax.romanov@nginx.com 
4689507Smax.romanov@nginx.com     if (!state->start_process) {
4690507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
4691343Smax.romanov@nginx.com                   &app->name, app);
4692343Smax.romanov@nginx.com 
4693343Smax.romanov@nginx.com         return NXT_AGAIN;
4694343Smax.romanov@nginx.com     }
4695343Smax.romanov@nginx.com 
4696507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
4697343Smax.romanov@nginx.com 
4698343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
46991446Smax.romanov@nginx.com         nxt_request_app_link_error(task, app, req_app_link,
47001123Smax.romanov@nginx.com                                    "Failed to start app process");
4701343Smax.romanov@nginx.com 
4702141Smax.romanov@nginx.com         return NXT_ERROR;
4703141Smax.romanov@nginx.com     }
4704141Smax.romanov@nginx.com 
4705141Smax.romanov@nginx.com     return NXT_AGAIN;
470688Smax.romanov@nginx.com }
470788Smax.romanov@nginx.com 
470888Smax.romanov@nginx.com 
4709427Smax.romanov@nginx.com static nxt_int_t
47101123Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
47111123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
4712427Smax.romanov@nginx.com {
4713427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4714427Smax.romanov@nginx.com 
47151123Smax.romanov@nginx.com     state.req_app_link = req_app_link;
4716427Smax.romanov@nginx.com     state.app = app;
4717427Smax.romanov@nginx.com 
4718427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4719427Smax.romanov@nginx.com 
4720427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
4721427Smax.romanov@nginx.com 
4722427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4723427Smax.romanov@nginx.com 
4724427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
4725427Smax.romanov@nginx.com }
4726427Smax.romanov@nginx.com 
4727427Smax.romanov@nginx.com 
4728431Sigor@sysoev.ru void
47291007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
4730964Sigor@sysoev.ru     nxt_app_t *app)
473153Sigor@sysoev.ru {
47321123Smax.romanov@nginx.com     nxt_int_t               res;
47331123Smax.romanov@nginx.com     nxt_port_t              *port;
47341123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
47351123Smax.romanov@nginx.com     nxt_request_app_link_t  ra_local, *req_app_link;
47361123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
4737431Sigor@sysoev.ru 
473888Smax.romanov@nginx.com     engine = task->thread->engine;
473988Smax.romanov@nginx.com 
47401123Smax.romanov@nginx.com     req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
4741318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4742318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
47431123Smax.romanov@nginx.com                                           sizeof(nxt_request_rpc_data_t));
47441123Smax.romanov@nginx.com     if (nxt_slow_path(req_rpc_data == NULL)) {
4745431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4746141Smax.romanov@nginx.com         return;
474788Smax.romanov@nginx.com     }
474888Smax.romanov@nginx.com 
47491402Smax.romanov@nginx.com     /*
47501402Smax.romanov@nginx.com      * At this point we have request req_rpc_data allocated and registered
47511402Smax.romanov@nginx.com      * in port handlers.  Need to fixup request memory pool.  Counterpart
47521402Smax.romanov@nginx.com      * release will be called via following call chain:
47531402Smax.romanov@nginx.com      *    nxt_request_rpc_data_unlink() ->
47541402Smax.romanov@nginx.com      *        nxt_router_http_request_done() ->
47551402Smax.romanov@nginx.com      *            nxt_router_http_request_release()
47561402Smax.romanov@nginx.com      */
47571402Smax.romanov@nginx.com     nxt_mp_retain(r->mem_pool);
47581402Smax.romanov@nginx.com 
47591402Smax.romanov@nginx.com     r->timer.task = &engine->task;
47601402Smax.romanov@nginx.com     r->timer.work_queue = &engine->fast_work_queue;
47611402Smax.romanov@nginx.com     r->timer.log = engine->task.log;
47621402Smax.romanov@nginx.com     r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
47631402Smax.romanov@nginx.com 
47641123Smax.romanov@nginx.com     req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
47651123Smax.romanov@nginx.com     req_rpc_data->app = app;
4766425Smax.romanov@nginx.com 
4767425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4768425Smax.romanov@nginx.com 
47691123Smax.romanov@nginx.com     req_rpc_data->request = r;
47701131Smax.romanov@nginx.com     r->req_rpc_data = req_rpc_data;
47711123Smax.romanov@nginx.com 
47721123Smax.romanov@nginx.com     req_app_link = &ra_local;
47731123Smax.romanov@nginx.com     nxt_request_app_link_init(task, req_app_link, req_rpc_data);
47741123Smax.romanov@nginx.com 
47751123Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, req_app_link);
47761123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
47771294Smax.romanov@nginx.com 
47781294Smax.romanov@nginx.com     if (res == NXT_OK) {
47791294Smax.romanov@nginx.com         port = req_app_link->app_port;
47801294Smax.romanov@nginx.com 
47811294Smax.romanov@nginx.com         nxt_assert(port != NULL);
47821294Smax.romanov@nginx.com 
47831294Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, port->pid);
47841294Smax.romanov@nginx.com 
47851294Smax.romanov@nginx.com         nxt_router_app_prepare_request(task, req_app_link);
47861294Smax.romanov@nginx.com     }
47871294Smax.romanov@nginx.com 
47881294Smax.romanov@nginx.com     nxt_request_app_link_use(task, req_app_link, -1);
4789167Smax.romanov@nginx.com }
4790167Smax.romanov@nginx.com 
4791167Smax.romanov@nginx.com 
4792167Smax.romanov@nginx.com static void
4793423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4794423Smax.romanov@nginx.com {
4795423Smax.romanov@nginx.com }
4796423Smax.romanov@nginx.com 
4797423Smax.romanov@nginx.com 
4798423Smax.romanov@nginx.com static void
47991123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task,
48001123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
4801167Smax.romanov@nginx.com {
48021414Smax.romanov@nginx.com     nxt_buf_t         *buf;
48031123Smax.romanov@nginx.com     nxt_int_t         res;
48041123Smax.romanov@nginx.com     nxt_port_t        *port, *c_port, *reply_port;
48051123Smax.romanov@nginx.com     nxt_apr_action_t  apr_action;
48061123Smax.romanov@nginx.com 
48071123Smax.romanov@nginx.com     nxt_assert(req_app_link->app_port != NULL);
48081123Smax.romanov@nginx.com 
48091123Smax.romanov@nginx.com     port = req_app_link->app_port;
48101123Smax.romanov@nginx.com     reply_port = req_app_link->reply_port;
48111123Smax.romanov@nginx.com 
48121123Smax.romanov@nginx.com     apr_action = NXT_APR_REQUEST_FAILED;
4813343Smax.romanov@nginx.com 
48141452Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port);
48151446Smax.romanov@nginx.com 
4816141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
4817141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
4818122Smax.romanov@nginx.com 
4819122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
48201446Smax.romanov@nginx.com             nxt_request_app_link_error(task, port->app, req_app_link,
4821345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
48221446Smax.romanov@nginx.com 
4823343Smax.romanov@nginx.com             goto release_port;
4824122Smax.romanov@nginx.com         }
48251452Smax.romanov@nginx.com 
48261452Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
482788Smax.romanov@nginx.com     }
482888Smax.romanov@nginx.com 
48291123Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, req_app_link->request, port,
4830743Smax.romanov@nginx.com                                  nxt_app_msg_prefix[port->app->type]);
4831743Smax.romanov@nginx.com 
4832743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
48331446Smax.romanov@nginx.com         nxt_request_app_link_error(task, port->app, req_app_link,
4834345Smax.romanov@nginx.com                             "Failed to prepare message for application");
4835343Smax.romanov@nginx.com         goto release_port;
4836122Smax.romanov@nginx.com     }
483788Smax.romanov@nginx.com 
4838507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4839743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4840743Smax.romanov@nginx.com                     port->socket.fd);
484188Smax.romanov@nginx.com 
48421123Smax.romanov@nginx.com     apr_action = NXT_APR_NEW_PORT;
48431123Smax.romanov@nginx.com 
48441123Smax.romanov@nginx.com     req_app_link->msg_info.buf = buf;
48451123Smax.romanov@nginx.com     req_app_link->msg_info.completion_handler = buf->completion_handler;
4846743Smax.romanov@nginx.com 
4847743Smax.romanov@nginx.com     for (; buf; buf = buf->next) {
4848743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
4849423Smax.romanov@nginx.com     }
4850423Smax.romanov@nginx.com 
48511123Smax.romanov@nginx.com     buf = req_app_link->msg_info.buf;
48521123Smax.romanov@nginx.com 
48531123Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port,
48541123Smax.romanov@nginx.com                                      &req_app_link->msg_info.tracking,
48551123Smax.romanov@nginx.com                                      req_app_link->stream);
4856423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
48571446Smax.romanov@nginx.com         nxt_request_app_link_error(task, port->app, req_app_link,
48581123Smax.romanov@nginx.com                                    "Failed to get tracking area");
4859423Smax.romanov@nginx.com         goto release_port;
4860423Smax.romanov@nginx.com     }
4861423Smax.romanov@nginx.com 
48621414Smax.romanov@nginx.com     if (req_app_link->body_fd != -1) {
48631414Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: send body fd %d", req_app_link->stream,
48641414Smax.romanov@nginx.com                   req_app_link->body_fd);
48651414Smax.romanov@nginx.com 
48661414Smax.romanov@nginx.com         lseek(req_app_link->body_fd, 0, SEEK_SET);
48671414Smax.romanov@nginx.com     }
48681414Smax.romanov@nginx.com 
48691414Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_REQ_HEADERS,
48701414Smax.romanov@nginx.com                                  req_app_link->body_fd,
48711403Smax.romanov@nginx.com                                  req_app_link->stream, reply_port->id, buf,
48721123Smax.romanov@nginx.com                                  &req_app_link->msg_info.tracking);
4873122Smax.romanov@nginx.com 
4874122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
48751446Smax.romanov@nginx.com         nxt_request_app_link_error(task, port->app, req_app_link,
48761123Smax.romanov@nginx.com                                    "Failed to send message to application");
4877343Smax.romanov@nginx.com         goto release_port;
4878122Smax.romanov@nginx.com     }
4879343Smax.romanov@nginx.com 
4880343Smax.romanov@nginx.com release_port:
4881343Smax.romanov@nginx.com 
48821123Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, apr_action);
48831123Smax.romanov@nginx.com 
48841123Smax.romanov@nginx.com     nxt_request_app_link_update_peer(task, req_app_link);
488553Sigor@sysoev.ru }
488653Sigor@sysoev.ru 
488753Sigor@sysoev.ru 
4888743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4889743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4890743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4891743Smax.romanov@nginx.com };
4892743Smax.romanov@nginx.com 
4893743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4894743Smax.romanov@nginx.com 
4895743Smax.romanov@nginx.com 
4896743Smax.romanov@nginx.com static nxt_http_field_t *
4897743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4898216Sigor@sysoev.ru {
4899743Smax.romanov@nginx.com     if (part == NULL) {
4900743Smax.romanov@nginx.com         return NULL;
4901216Sigor@sysoev.ru     }
4902216Sigor@sysoev.ru 
4903743Smax.romanov@nginx.com     while (part->nelts == 0) {
4904743Smax.romanov@nginx.com         part = part->next;
4905743Smax.romanov@nginx.com         if (part == NULL) {
4906743Smax.romanov@nginx.com             return NULL;
4907743Smax.romanov@nginx.com         }
4908216Sigor@sysoev.ru     }
4909216Sigor@sysoev.ru 
4910743Smax.romanov@nginx.com     i->part = part;
4911743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4912743Smax.romanov@nginx.com 
4913743Smax.romanov@nginx.com     return i->field;
4914743Smax.romanov@nginx.com }
4915743Smax.romanov@nginx.com 
4916743Smax.romanov@nginx.com 
4917743Smax.romanov@nginx.com static nxt_http_field_t *
4918743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4919743Smax.romanov@nginx.com {
4920743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4921743Smax.romanov@nginx.com }
4922743Smax.romanov@nginx.com 
4923743Smax.romanov@nginx.com 
4924743Smax.romanov@nginx.com static nxt_http_field_t *
4925743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4926743Smax.romanov@nginx.com {
4927743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4928743Smax.romanov@nginx.com 
4929743Smax.romanov@nginx.com     end += i->part->nelts;
4930743Smax.romanov@nginx.com     i->field++;
4931743Smax.romanov@nginx.com 
4932743Smax.romanov@nginx.com     if (i->field < end) {
4933743Smax.romanov@nginx.com         return i->field;
4934216Sigor@sysoev.ru     }
4935216Sigor@sysoev.ru 
4936743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4937216Sigor@sysoev.ru }
4938216Sigor@sysoev.ru 
4939216Sigor@sysoev.ru 
4940743Smax.romanov@nginx.com static nxt_buf_t *
49411007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
4942743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix)
4943216Sigor@sysoev.ru {
49441007Salexander.borisov@nginx.com     void                *target_pos, *query_pos;
49451007Salexander.borisov@nginx.com     u_char              *pos, *end, *p, c;
49461007Salexander.borisov@nginx.com     size_t              fields_count, req_size, size, free_size;
49471007Salexander.borisov@nginx.com     size_t              copy_size;
49481007Salexander.borisov@nginx.com     nxt_off_t           content_length;
49491007Salexander.borisov@nginx.com     nxt_buf_t           *b, *buf, *out, **tail;
49501007Salexander.borisov@nginx.com     nxt_http_field_t    *field, *dup;
49511007Salexander.borisov@nginx.com     nxt_unit_field_t    *dst_field;
49521007Salexander.borisov@nginx.com     nxt_fields_iter_t   iter, dup_iter;
49531007Salexander.borisov@nginx.com     nxt_unit_request_t  *req;
4954216Sigor@sysoev.ru 
4955743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
49561007Salexander.borisov@nginx.com                + r->method->length + 1
49571007Salexander.borisov@nginx.com                + r->version.length + 1
49581007Salexander.borisov@nginx.com                + r->remote->length + 1
49591007Salexander.borisov@nginx.com                + r->local->length + 1
49601007Salexander.borisov@nginx.com                + r->server_name.length + 1
49611007Salexander.borisov@nginx.com                + r->target.length + 1
49621007Salexander.borisov@nginx.com                + (r->path->start != r->target.start ? r->path->length + 1 : 0);
49631007Salexander.borisov@nginx.com 
49641007Salexander.borisov@nginx.com     content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
4965743Smax.romanov@nginx.com     fields_count = 0;
4966743Smax.romanov@nginx.com 
49671007Salexander.borisov@nginx.com     nxt_list_each(field, r->fields) {
4968743Smax.romanov@nginx.com         fields_count++;
4969743Smax.romanov@nginx.com 
4970743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4971743Smax.romanov@nginx.com                     + field->value_length + 1;
4972743Smax.romanov@nginx.com     } nxt_list_loop;
4973743Smax.romanov@nginx.com 
4974743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4975743Smax.romanov@nginx.com 
4976743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4977743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4978743Smax.romanov@nginx.com                   (int) req_size);
4979743Smax.romanov@nginx.com 
4980743Smax.romanov@nginx.com         return NULL;
4981743Smax.romanov@nginx.com     }
4982743Smax.romanov@nginx.com 
4983743Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, port,
49841007Salexander.borisov@nginx.com               nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
4985743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4986743Smax.romanov@nginx.com         return NULL;
4987743Smax.romanov@nginx.com     }
4988743Smax.romanov@nginx.com 
4989743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4990743Smax.romanov@nginx.com     out->mem.free += req_size;
4991743Smax.romanov@nginx.com 
49921007Salexander.borisov@nginx.com     req->content_length = content_length;
4993743Smax.romanov@nginx.com 
4994743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4995743Smax.romanov@nginx.com 
4996743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4997743Smax.romanov@nginx.com 
49981007Salexander.borisov@nginx.com     req->method_length = r->method->length;
4999743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
50001007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->method->start, r->method->length);
5001743Smax.romanov@nginx.com     *p++ = '\0';
5002743Smax.romanov@nginx.com 
50031007Salexander.borisov@nginx.com     req->version_length = r->version.length;
5004743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
50051007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->version.start, r->version.length);
5006743Smax.romanov@nginx.com     *p++ = '\0';
5007743Smax.romanov@nginx.com 
50081007Salexander.borisov@nginx.com     req->remote_length = r->remote->address_length;
5009743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
50101007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
50111007Salexander.borisov@nginx.com                    r->remote->address_length);
5012743Smax.romanov@nginx.com     *p++ = '\0';
5013743Smax.romanov@nginx.com 
50141007Salexander.borisov@nginx.com     req->local_length = r->local->address_length;
5015743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
50161007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
5017743Smax.romanov@nginx.com     *p++ = '\0';
5018743Smax.romanov@nginx.com 
50191011Smax.romanov@nginx.com     req->tls = (r->tls != NULL);
50201131Smax.romanov@nginx.com     req->websocket_handshake = r->websocket_handshake;
50211011Smax.romanov@nginx.com 
50221007Salexander.borisov@nginx.com     req->server_name_length = r->server_name.length;
5023967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
50241007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
5025967Svbart@nginx.com     *p++ = '\0';
5026967Svbart@nginx.com 
5027743Smax.romanov@nginx.com     target_pos = p;
50281007Salexander.borisov@nginx.com     req->target_length = (uint32_t) r->target.length;
5029743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
50301007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->target.start, r->target.length);
5031743Smax.romanov@nginx.com     *p++ = '\0';
5032743Smax.romanov@nginx.com 
50331007Salexander.borisov@nginx.com     req->path_length = (uint32_t) r->path->length;
50341007Salexander.borisov@nginx.com     if (r->path->start == r->target.start) {
5035743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
5036277Sigor@sysoev.ru 
5037216Sigor@sysoev.ru     } else {
5038743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
50391007Salexander.borisov@nginx.com         p = nxt_cpymem(p, r->path->start, r->path->length);
5040743Smax.romanov@nginx.com         *p++ = '\0';
5041305Smax.romanov@nginx.com     }
5042216Sigor@sysoev.ru 
50431007Salexander.borisov@nginx.com     req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
50441007Salexander.borisov@nginx.com     if (r->args != NULL && r->args->start != NULL) {
5045743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
50461007Salexander.borisov@nginx.com                                    r->args->start - r->target.start);
5047743Smax.romanov@nginx.com 
5048743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
5049277Sigor@sysoev.ru 
5050216Sigor@sysoev.ru     } else {
5051743Smax.romanov@nginx.com         req->query.offset = 0;
5052216Sigor@sysoev.ru     }
5053216Sigor@sysoev.ru 
5054743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
5055743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
5056743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
5057743Smax.romanov@nginx.com 
5058743Smax.romanov@nginx.com     dst_field = req->fields;
5059743Smax.romanov@nginx.com 
50601007Salexander.borisov@nginx.com     for (field = nxt_fields_first(r->fields, &iter);
5061743Smax.romanov@nginx.com          field != NULL;
5062743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
5063743Smax.romanov@nginx.com     {
5064743Smax.romanov@nginx.com         if (field->skip) {
5065743Smax.romanov@nginx.com             continue;
5066743Smax.romanov@nginx.com         }
5067743Smax.romanov@nginx.com 
5068743Smax.romanov@nginx.com         dst_field->hash = field->hash;
5069743Smax.romanov@nginx.com         dst_field->skip = 0;
5070743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
5071743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
5072743Smax.romanov@nginx.com 
50731007Salexander.borisov@nginx.com         if (field == r->content_length) {
5074743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
5075743Smax.romanov@nginx.com 
50761007Salexander.borisov@nginx.com         } else if (field == r->content_type) {
5077743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
5078743Smax.romanov@nginx.com 
50791007Salexander.borisov@nginx.com         } else if (field == r->cookie) {
5080743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
5081743Smax.romanov@nginx.com         }
5082743Smax.romanov@nginx.com 
5083743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
5084743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
5085743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
5086743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
5087743Smax.romanov@nginx.com 
5088743Smax.romanov@nginx.com         if (prefix->length != 0) {
5089743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
5090743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
5091743Smax.romanov@nginx.com 
5092743Smax.romanov@nginx.com             end = field->name + field->name_length;
5093743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
5094743Smax.romanov@nginx.com                 c = *pos;
5095743Smax.romanov@nginx.com 
5096743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
5097743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
5098743Smax.romanov@nginx.com                     continue;
5099743Smax.romanov@nginx.com                 }
5100743Smax.romanov@nginx.com 
5101743Smax.romanov@nginx.com                 if (c == '-') {
5102743Smax.romanov@nginx.com                     *p++ = '_';
5103743Smax.romanov@nginx.com                     continue;
5104743Smax.romanov@nginx.com                 }
5105743Smax.romanov@nginx.com 
5106743Smax.romanov@nginx.com                 *p++ = c;
5107743Smax.romanov@nginx.com             }
5108743Smax.romanov@nginx.com 
5109743Smax.romanov@nginx.com         } else {
5110743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
5111743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
5112743Smax.romanov@nginx.com         }
5113743Smax.romanov@nginx.com 
5114743Smax.romanov@nginx.com         *p++ = '\0';
5115743Smax.romanov@nginx.com 
5116743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
5117743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
5118743Smax.romanov@nginx.com 
5119743Smax.romanov@nginx.com         if (prefix->length != 0) {
5120743Smax.romanov@nginx.com             dup_iter = iter;
5121743Smax.romanov@nginx.com 
5122743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
5123743Smax.romanov@nginx.com                  dup != NULL;
5124743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
5125743Smax.romanov@nginx.com             {
5126743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
5127743Smax.romanov@nginx.com                     || dup->skip
5128743Smax.romanov@nginx.com                     || dup->hash != field->hash
5129743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
5130743Smax.romanov@nginx.com                 {
5131743Smax.romanov@nginx.com                     continue;
5132743Smax.romanov@nginx.com                 }
5133743Smax.romanov@nginx.com 
5134743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
5135743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
5136743Smax.romanov@nginx.com 
5137743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
5138743Smax.romanov@nginx.com 
5139743Smax.romanov@nginx.com                 dup->skip = 1;
5140743Smax.romanov@nginx.com             }
5141743Smax.romanov@nginx.com         }
5142743Smax.romanov@nginx.com 
5143743Smax.romanov@nginx.com         *p++ = '\0';
5144743Smax.romanov@nginx.com 
5145743Smax.romanov@nginx.com         dst_field++;
5146743Smax.romanov@nginx.com     }
5147743Smax.romanov@nginx.com 
51481007Salexander.borisov@nginx.com     req->fields_count = (uint32_t) (dst_field - req->fields);
5149743Smax.romanov@nginx.com 
5150743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5151743Smax.romanov@nginx.com 
5152743Smax.romanov@nginx.com     buf = out;
5153743Smax.romanov@nginx.com     tail = &buf->next;
5154216Sigor@sysoev.ru 
51551007Salexander.borisov@nginx.com     for (b = r->body; b != NULL; b = b->next) {
5156743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
5157743Smax.romanov@nginx.com         pos = b->mem.pos;
5158743Smax.romanov@nginx.com 
5159743Smax.romanov@nginx.com         while (size > 0) {
5160743Smax.romanov@nginx.com             if (buf == NULL) {
5161743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5162743Smax.romanov@nginx.com 
5163743Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, port, free_size);
5164743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
5165743Smax.romanov@nginx.com                     while (out != NULL) {
5166743Smax.romanov@nginx.com                         buf = out->next;
51671269Sigor@sysoev.ru                         out->next = NULL;
5168743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
5169743Smax.romanov@nginx.com                         out = buf;
5170743Smax.romanov@nginx.com                     }
5171743Smax.romanov@nginx.com                     return NULL;
5172743Smax.romanov@nginx.com                 }
5173743Smax.romanov@nginx.com 
5174743Smax.romanov@nginx.com                 *tail = buf;
5175743Smax.romanov@nginx.com                 tail = &buf->next;
5176743Smax.romanov@nginx.com 
5177743Smax.romanov@nginx.com             } else {
5178743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
5179743Smax.romanov@nginx.com                 if (free_size < size
5180743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
5181743Smax.romanov@nginx.com                        == NXT_OK)
5182743Smax.romanov@nginx.com                 {
5183743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
5184743Smax.romanov@nginx.com                 }
5185743Smax.romanov@nginx.com             }
5186743Smax.romanov@nginx.com 
5187743Smax.romanov@nginx.com             if (free_size > 0) {
5188743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
5189743Smax.romanov@nginx.com 
5190743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5191743Smax.romanov@nginx.com 
5192743Smax.romanov@nginx.com                 size -= copy_size;
5193743Smax.romanov@nginx.com                 pos += copy_size;
5194743Smax.romanov@nginx.com 
5195743Smax.romanov@nginx.com                 if (size == 0) {
5196743Smax.romanov@nginx.com                     break;
5197743Smax.romanov@nginx.com                 }
5198743Smax.romanov@nginx.com             }
5199743Smax.romanov@nginx.com 
5200743Smax.romanov@nginx.com             buf = NULL;
5201743Smax.romanov@nginx.com         }
5202216Sigor@sysoev.ru     }
5203216Sigor@sysoev.ru 
5204743Smax.romanov@nginx.com     return out;
5205584Salexander.borisov@nginx.com }
5206584Salexander.borisov@nginx.com 
5207584Salexander.borisov@nginx.com 
520853Sigor@sysoev.ru static void
5209318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5210318Smax.romanov@nginx.com {
5211615Smax.romanov@nginx.com     nxt_app_t                *app;
5212615Smax.romanov@nginx.com     nxt_bool_t               cancelled, unlinked;
5213615Smax.romanov@nginx.com     nxt_port_t               *port;
5214615Smax.romanov@nginx.com     nxt_timer_t              *timer;
5215615Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
52161007Salexander.borisov@nginx.com     nxt_http_request_t       *r;
52171123Smax.romanov@nginx.com     nxt_request_app_link_t   *pending_ra;
52181123Smax.romanov@nginx.com     nxt_request_rpc_data_t   *req_rpc_data;
5219615Smax.romanov@nginx.com     nxt_port_select_state_t  state;
5220318Smax.romanov@nginx.com 
5221318Smax.romanov@nginx.com     timer = obj;
5222318Smax.romanov@nginx.com 
5223318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
5224318Smax.romanov@nginx.com 
52251007Salexander.borisov@nginx.com     r = nxt_timer_data(timer, nxt_http_request_t, timer);
52261123Smax.romanov@nginx.com     req_rpc_data = r->timer_data;
52271123Smax.romanov@nginx.com     app = req_rpc_data->app;
5228615Smax.romanov@nginx.com 
5229615Smax.romanov@nginx.com     if (app == NULL) {
5230615Smax.romanov@nginx.com         goto generate_error;
5231615Smax.romanov@nginx.com     }
5232615Smax.romanov@nginx.com 
5233615Smax.romanov@nginx.com     port = NULL;
5234615Smax.romanov@nginx.com     pending_ra = NULL;
5235615Smax.romanov@nginx.com 
52361123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
52371123Smax.romanov@nginx.com         port = req_rpc_data->app_port;
52381123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
52391123Smax.romanov@nginx.com     }
52401123Smax.romanov@nginx.com 
52411123Smax.romanov@nginx.com     if (port == NULL && req_rpc_data->req_app_link != NULL
52421123Smax.romanov@nginx.com         && req_rpc_data->req_app_link->app_port != NULL)
52431123Smax.romanov@nginx.com     {
52441123Smax.romanov@nginx.com         port = req_rpc_data->req_app_link->app_port;
52451123Smax.romanov@nginx.com         req_rpc_data->req_app_link->app_port = NULL;
5246615Smax.romanov@nginx.com     }
5247615Smax.romanov@nginx.com 
5248615Smax.romanov@nginx.com     if (port == NULL) {
5249615Smax.romanov@nginx.com         goto generate_error;
5250431Sigor@sysoev.ru     }
5251615Smax.romanov@nginx.com 
5252615Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
5253615Smax.romanov@nginx.com 
5254615Smax.romanov@nginx.com     unlinked = nxt_queue_chk_remove(&port->app_link);
5255615Smax.romanov@nginx.com 
5256615Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&port->pending_requests)) {
5257615Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
5258615Smax.romanov@nginx.com 
52591123Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
5260615Smax.romanov@nginx.com                                          link_port_pending);
5261615Smax.romanov@nginx.com 
5262615Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
5263615Smax.romanov@nginx.com 
5264615Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pending request #%uD found",
5265615Smax.romanov@nginx.com                   &app->name, pending_ra->stream);
5266615Smax.romanov@nginx.com 
5267615Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info,
5268615Smax.romanov@nginx.com                                           pending_ra->stream);
5269615Smax.romanov@nginx.com 
5270615Smax.romanov@nginx.com         if (cancelled) {
52711123Smax.romanov@nginx.com             state.req_app_link = pending_ra;
5272615Smax.romanov@nginx.com             state.app = app;
5273615Smax.romanov@nginx.com 
52741375Smax.romanov@nginx.com             /*
52751375Smax.romanov@nginx.com              * Need to increment use count "in advance" because
52761375Smax.romanov@nginx.com              * nxt_router_port_select() will remove pending_ra from lists
52771375Smax.romanov@nginx.com              * and decrement use count.
52781375Smax.romanov@nginx.com              */
52791375Smax.romanov@nginx.com             nxt_request_app_link_inc_use(pending_ra);
52801375Smax.romanov@nginx.com 
5281615Smax.romanov@nginx.com             nxt_router_port_select(task, &state);
5282615Smax.romanov@nginx.com 
5283615Smax.romanov@nginx.com         } else {
5284615Smax.romanov@nginx.com             pending_ra = NULL;
5285615Smax.romanov@nginx.com         }
5286615Smax.romanov@nginx.com     }
5287615Smax.romanov@nginx.com 
5288615Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
5289615Smax.romanov@nginx.com 
52901294Smax.romanov@nginx.com     if (pending_ra != NULL) {
52911294Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
52921375Smax.romanov@nginx.com             /*
52931375Smax.romanov@nginx.com              * Reference counter already incremented above, this will
52941375Smax.romanov@nginx.com              * keep pending_ra while nxt_router_app_process_request()
52951375Smax.romanov@nginx.com              * task is in queue.  Reference counter decreased in
52961375Smax.romanov@nginx.com              * nxt_router_app_process_request() after processing.
52971375Smax.romanov@nginx.com              */
52981375Smax.romanov@nginx.com 
52991375Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
53001375Smax.romanov@nginx.com                                nxt_router_app_process_request,
53011375Smax.romanov@nginx.com                                &task->thread->engine->task, app, pending_ra);
53021375Smax.romanov@nginx.com 
53031375Smax.romanov@nginx.com         } else {
53041375Smax.romanov@nginx.com             nxt_request_app_link_use(task, pending_ra, -1);
53051294Smax.romanov@nginx.com         }
5306615Smax.romanov@nginx.com     }
5307615Smax.romanov@nginx.com 
5308615Smax.romanov@nginx.com     nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid);
5309615Smax.romanov@nginx.com 
5310615Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
5311615Smax.romanov@nginx.com 
5312615Smax.romanov@nginx.com     nxt_port_use(task, port, unlinked ? -2 : -1);
5313615Smax.romanov@nginx.com 
5314615Smax.romanov@nginx.com generate_error:
5315615Smax.romanov@nginx.com 
53161007Salexander.borisov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5317615Smax.romanov@nginx.com 
53181123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
5319318Smax.romanov@nginx.com }
53201007Salexander.borisov@nginx.com 
53211007Salexander.borisov@nginx.com 
53221007Salexander.borisov@nginx.com static nxt_int_t
53231007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r)
53241007Salexander.borisov@nginx.com {
53251007Salexander.borisov@nginx.com     r->timer.handler = nxt_router_http_request_release;
53261007Salexander.borisov@nginx.com     nxt_timer_add(task->thread->engine, &r->timer, 0);
53271007Salexander.borisov@nginx.com 
53281007Salexander.borisov@nginx.com     return NXT_OK;
53291007Salexander.borisov@nginx.com }
53301007Salexander.borisov@nginx.com 
53311007Salexander.borisov@nginx.com 
53321007Salexander.borisov@nginx.com static void
53331007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
53341007Salexander.borisov@nginx.com {
53351007Salexander.borisov@nginx.com     nxt_http_request_t  *r;
53361007Salexander.borisov@nginx.com 
53371007Salexander.borisov@nginx.com     nxt_debug(task, "http app release");
53381007Salexander.borisov@nginx.com 
53391007Salexander.borisov@nginx.com     r = nxt_timer_data(obj, nxt_http_request_t, timer);
53401007Salexander.borisov@nginx.com 
53411007Salexander.borisov@nginx.com     nxt_mp_release(r->mem_pool);
53421007Salexander.borisov@nginx.com }
53431321Smax.romanov@nginx.com 
53441321Smax.romanov@nginx.com 
53451321Smax.romanov@nginx.com static void
53461321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
53471321Smax.romanov@nginx.com {
53481321Smax.romanov@nginx.com     size_t                   mi;
53491321Smax.romanov@nginx.com     uint32_t                 i;
53501321Smax.romanov@nginx.com     nxt_bool_t               ack;
53511321Smax.romanov@nginx.com     nxt_process_t            *process;
53521321Smax.romanov@nginx.com     nxt_free_map_t           *m;
53531321Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
53541321Smax.romanov@nginx.com 
53551321Smax.romanov@nginx.com     nxt_debug(task, "oosm in %PI", msg->port_msg.pid);
53561321Smax.romanov@nginx.com 
53571321Smax.romanov@nginx.com     process = nxt_runtime_process_find(task->thread->runtime,
53581321Smax.romanov@nginx.com                                        msg->port_msg.pid);
53591321Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
53601321Smax.romanov@nginx.com         return;
53611321Smax.romanov@nginx.com     }
53621321Smax.romanov@nginx.com 
53631321Smax.romanov@nginx.com     ack = 0;
53641321Smax.romanov@nginx.com 
53651321Smax.romanov@nginx.com     /*
53661321Smax.romanov@nginx.com      * To mitigate possible racing condition (when OOSM message received
53671321Smax.romanov@nginx.com      * after some of the memory was already freed), need to try to find
53681321Smax.romanov@nginx.com      * first free segment in shared memory and send ACK if found.
53691321Smax.romanov@nginx.com      */
53701321Smax.romanov@nginx.com 
53711321Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
53721321Smax.romanov@nginx.com 
53731321Smax.romanov@nginx.com     for (i = 0; i < process->incoming.size; i++) {
53741321Smax.romanov@nginx.com         hdr = process->incoming.elts[i].mmap_handler->hdr;
53751321Smax.romanov@nginx.com         m = hdr->free_map;
53761321Smax.romanov@nginx.com 
53771321Smax.romanov@nginx.com         for (mi = 0; mi < MAX_FREE_IDX; mi++) {
53781321Smax.romanov@nginx.com             if (m[mi] != 0) {
53791321Smax.romanov@nginx.com                 ack = 1;
53801321Smax.romanov@nginx.com 
53811321Smax.romanov@nginx.com                 nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA",
53821321Smax.romanov@nginx.com                           i, mi, m[mi]);
53831321Smax.romanov@nginx.com 
53841321Smax.romanov@nginx.com                 break;
53851321Smax.romanov@nginx.com             }
53861321Smax.romanov@nginx.com         }
53871321Smax.romanov@nginx.com     }
53881321Smax.romanov@nginx.com 
53891321Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
53901321Smax.romanov@nginx.com 
53911321Smax.romanov@nginx.com     if (ack) {
53921321Smax.romanov@nginx.com         (void) nxt_port_socket_write(task, msg->port, NXT_PORT_MSG_SHM_ACK,
53931321Smax.romanov@nginx.com                                      -1, 0, 0, NULL);
53941321Smax.romanov@nginx.com     }
53951321Smax.romanov@nginx.com }
5396