xref: /unit/src/nxt_router.c (revision 1183)
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
981123Smax.romanov@nginx.com nxt_request_app_link_dec_use(nxt_request_app_link_t *req_app_link)
99425Smax.romanov@nginx.com {
100538Svbart@nginx.com #if (NXT_DEBUG)
101425Smax.romanov@nginx.com     int  c;
102425Smax.romanov@nginx.com 
1031123Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&req_app_link->use_count, -1);
104425Smax.romanov@nginx.com 
105425Smax.romanov@nginx.com     nxt_assert(c > 1);
106538Svbart@nginx.com #else
1071123Smax.romanov@nginx.com     (void) nxt_atomic_fetch_add(&req_app_link->use_count, -1);
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);
125*1183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
126*1183Svbart@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);
2511007Salexander.borisov@nginx.com 
2521149Smax.romanov@nginx.com extern const nxt_http_request_state_t  nxt_http_websocket;
2531131Smax.romanov@nginx.com 
254119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
25520Sigor@sysoev.ru 
256743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
257743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
258743Smax.romanov@nginx.com 
259743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
260804Svbart@nginx.com     &empty_prefix,
261743Smax.romanov@nginx.com     &http_prefix,
262743Smax.romanov@nginx.com     &http_prefix,
263743Smax.romanov@nginx.com     &http_prefix,
264743Smax.romanov@nginx.com     &http_prefix,
265977Smax.romanov@gmail.com     &empty_prefix,
266216Sigor@sysoev.ru };
267216Sigor@sysoev.ru 
268216Sigor@sysoev.ru 
269662Smax.romanov@nginx.com nxt_port_handlers_t  nxt_router_process_port_handlers = {
270662Smax.romanov@nginx.com     .quit         = nxt_worker_process_quit_handler,
271662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
272662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
273662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
274662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
275662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
276662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
277662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
278662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
279662Smax.romanov@nginx.com };
280662Smax.romanov@nginx.com 
281662Smax.romanov@nginx.com 
28220Sigor@sysoev.ru nxt_int_t
283141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data)
28420Sigor@sysoev.ru {
285141Smax.romanov@nginx.com     nxt_int_t      ret;
286662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
287141Smax.romanov@nginx.com     nxt_router_t   *router;
288141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
289141Smax.romanov@nginx.com 
290141Smax.romanov@nginx.com     rt = task->thread->runtime;
29153Sigor@sysoev.ru 
292771Sigor@sysoev.ru #if (NXT_TLS)
293771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
294771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
295771Sigor@sysoev.ru         return NXT_ERROR;
296771Sigor@sysoev.ru     }
297771Sigor@sysoev.ru 
298771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
299771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
300771Sigor@sysoev.ru         return ret;
301771Sigor@sysoev.ru     }
302771Sigor@sysoev.ru #endif
303771Sigor@sysoev.ru 
304431Sigor@sysoev.ru     ret = nxt_http_init(task, rt);
30588Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
30688Smax.romanov@nginx.com         return ret;
30788Smax.romanov@nginx.com     }
30888Smax.romanov@nginx.com 
30953Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
31053Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
31153Sigor@sysoev.ru         return NXT_ERROR;
31253Sigor@sysoev.ru     }
31353Sigor@sysoev.ru 
31453Sigor@sysoev.ru     nxt_queue_init(&router->engines);
31553Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
316133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
31753Sigor@sysoev.ru 
318119Smax.romanov@nginx.com     nxt_router = router;
319119Smax.romanov@nginx.com 
320662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
321662Smax.romanov@nginx.com     if (controller_port != NULL) {
322662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
323662Smax.romanov@nginx.com     }
324662Smax.romanov@nginx.com 
325115Sigor@sysoev.ru     return NXT_OK;
326115Sigor@sysoev.ru }
327115Sigor@sysoev.ru 
328115Sigor@sysoev.ru 
329343Smax.romanov@nginx.com static void
330662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
331662Smax.romanov@nginx.com {
332662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
333662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
334662Smax.romanov@nginx.com }
335662Smax.romanov@nginx.com 
336662Smax.romanov@nginx.com 
337662Smax.romanov@nginx.com static void
338507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
339507Smax.romanov@nginx.com     void *data)
340167Smax.romanov@nginx.com {
341343Smax.romanov@nginx.com     size_t         size;
342343Smax.romanov@nginx.com     uint32_t       stream;
343430Sigor@sysoev.ru     nxt_mp_t       *mp;
344648Svbart@nginx.com     nxt_int_t      ret;
345343Smax.romanov@nginx.com     nxt_app_t      *app;
346343Smax.romanov@nginx.com     nxt_buf_t      *b;
347343Smax.romanov@nginx.com     nxt_port_t     *main_port;
348343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
349343Smax.romanov@nginx.com 
350343Smax.romanov@nginx.com     app = data;
351167Smax.romanov@nginx.com 
352167Smax.romanov@nginx.com     rt = task->thread->runtime;
353240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
354167Smax.romanov@nginx.com 
355507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
356343Smax.romanov@nginx.com 
357343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
358343Smax.romanov@nginx.com 
359343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
360343Smax.romanov@nginx.com 
361343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
362343Smax.romanov@nginx.com         goto failed;
363167Smax.romanov@nginx.com     }
364167Smax.romanov@nginx.com 
365343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
366343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
367343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
368343Smax.romanov@nginx.com 
369753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
370753Smax.romanov@nginx.com 
371343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
372343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
373343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
374753Smax.romanov@nginx.com                                            -1, app->joint);
375343Smax.romanov@nginx.com 
376343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
377753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
378753Smax.romanov@nginx.com 
379343Smax.romanov@nginx.com         goto failed;
380343Smax.romanov@nginx.com     }
381343Smax.romanov@nginx.com 
382648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
383648Svbart@nginx.com                                 stream, port->id, b);
384648Svbart@nginx.com 
385648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
386648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
387753Smax.romanov@nginx.com 
388753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
389753Smax.romanov@nginx.com 
390648Svbart@nginx.com         goto failed;
391648Svbart@nginx.com     }
392343Smax.romanov@nginx.com 
393753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
394753Smax.romanov@nginx.com 
395343Smax.romanov@nginx.com     return;
396343Smax.romanov@nginx.com 
397343Smax.romanov@nginx.com failed:
398343Smax.romanov@nginx.com 
399648Svbart@nginx.com     if (b != NULL) {
400648Svbart@nginx.com         mp = b->data;
401648Svbart@nginx.com         nxt_mp_free(mp, b);
402648Svbart@nginx.com         nxt_mp_release(mp);
403648Svbart@nginx.com     }
404648Svbart@nginx.com 
405343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
406343Smax.romanov@nginx.com 
407507Smax.romanov@nginx.com     app->pending_processes--;
408343Smax.romanov@nginx.com 
409343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
410343Smax.romanov@nginx.com 
411343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
412167Smax.romanov@nginx.com }
413167Smax.romanov@nginx.com 
414167Smax.romanov@nginx.com 
415753Smax.romanov@nginx.com static void
416753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
417753Smax.romanov@nginx.com {
418753Smax.romanov@nginx.com     app_joint->use_count += i;
419753Smax.romanov@nginx.com 
420753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
421753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
422753Smax.romanov@nginx.com 
423753Smax.romanov@nginx.com         nxt_free(app_joint);
424753Smax.romanov@nginx.com     }
425753Smax.romanov@nginx.com }
426753Smax.romanov@nginx.com 
427753Smax.romanov@nginx.com 
428343Smax.romanov@nginx.com static nxt_int_t
429507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
430141Smax.romanov@nginx.com {
431343Smax.romanov@nginx.com     nxt_int_t      res;
432343Smax.romanov@nginx.com     nxt_port_t     *router_port;
433343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
434343Smax.romanov@nginx.com 
435343Smax.romanov@nginx.com     rt = task->thread->runtime;
436343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
437343Smax.romanov@nginx.com 
438343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
439343Smax.romanov@nginx.com 
440507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
441343Smax.romanov@nginx.com                         app);
442343Smax.romanov@nginx.com 
443343Smax.romanov@nginx.com     if (res == NXT_OK) {
444343Smax.romanov@nginx.com         return res;
445318Smax.romanov@nginx.com     }
446318Smax.romanov@nginx.com 
447343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
448343Smax.romanov@nginx.com 
449507Smax.romanov@nginx.com     app->pending_processes--;
450343Smax.romanov@nginx.com 
451343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
452343Smax.romanov@nginx.com 
453343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
454343Smax.romanov@nginx.com 
455343Smax.romanov@nginx.com     return NXT_ERROR;
456318Smax.romanov@nginx.com }
457318Smax.romanov@nginx.com 
458318Smax.romanov@nginx.com 
459351Smax.romanov@nginx.com nxt_inline void
4601123Smax.romanov@nginx.com nxt_request_app_link_init(nxt_task_t *task,
4611123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link, nxt_request_rpc_data_t *req_rpc_data)
462167Smax.romanov@nginx.com {
463318Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
464351Smax.romanov@nginx.com 
465318Smax.romanov@nginx.com     engine = task->thread->engine;
466167Smax.romanov@nginx.com 
4671123Smax.romanov@nginx.com     nxt_memzero(req_app_link, sizeof(nxt_request_app_link_t));
4681123Smax.romanov@nginx.com 
4691123Smax.romanov@nginx.com     req_app_link->stream = req_rpc_data->stream;
4701123Smax.romanov@nginx.com     req_app_link->use_count = 1;
4711123Smax.romanov@nginx.com     req_app_link->req_rpc_data = req_rpc_data;
4721123Smax.romanov@nginx.com     req_rpc_data->req_app_link = req_app_link;
4731123Smax.romanov@nginx.com     req_app_link->reply_port = engine->port;
4741123Smax.romanov@nginx.com     req_app_link->request = req_rpc_data->request;
4751123Smax.romanov@nginx.com     req_app_link->apr_action = NXT_APR_GOT_RESPONSE;
4761123Smax.romanov@nginx.com 
4771123Smax.romanov@nginx.com     req_app_link->work.handler = NULL;
4781123Smax.romanov@nginx.com     req_app_link->work.task = &engine->task;
4791123Smax.romanov@nginx.com     req_app_link->work.obj = req_app_link;
4801123Smax.romanov@nginx.com     req_app_link->work.data = engine;
481351Smax.romanov@nginx.com }
482351Smax.romanov@nginx.com 
483351Smax.romanov@nginx.com 
4841123Smax.romanov@nginx.com nxt_inline nxt_request_app_link_t *
4851123Smax.romanov@nginx.com nxt_request_app_link_alloc(nxt_task_t *task,
4861123Smax.romanov@nginx.com     nxt_request_app_link_t *ra_src, nxt_request_rpc_data_t *req_rpc_data)
487351Smax.romanov@nginx.com {
4881123Smax.romanov@nginx.com     nxt_mp_t                *mp;
4891123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
4901123Smax.romanov@nginx.com 
4911123Smax.romanov@nginx.com     if (ra_src != NULL && ra_src->mem_pool != NULL) {
492425Smax.romanov@nginx.com         return ra_src;
493425Smax.romanov@nginx.com     }
494425Smax.romanov@nginx.com 
4951123Smax.romanov@nginx.com     mp = req_rpc_data->request->mem_pool;
4961123Smax.romanov@nginx.com 
4971123Smax.romanov@nginx.com     req_app_link = nxt_mp_alloc(mp, sizeof(nxt_request_app_link_t));
4981123Smax.romanov@nginx.com 
4991123Smax.romanov@nginx.com     if (nxt_slow_path(req_app_link == NULL)) {
5001123Smax.romanov@nginx.com 
5011123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
5021123Smax.romanov@nginx.com 
5031123Smax.romanov@nginx.com         if (ra_src != NULL) {
5041123Smax.romanov@nginx.com             ra_src->req_rpc_data = NULL;
5051123Smax.romanov@nginx.com         }
506351Smax.romanov@nginx.com 
507351Smax.romanov@nginx.com         return NULL;
508351Smax.romanov@nginx.com     }
509351Smax.romanov@nginx.com 
510430Sigor@sysoev.ru     nxt_mp_retain(mp);
511430Sigor@sysoev.ru 
5121123Smax.romanov@nginx.com     nxt_request_app_link_init(task, req_app_link, req_rpc_data);
5131123Smax.romanov@nginx.com 
5141123Smax.romanov@nginx.com     req_app_link->mem_pool = mp;
5151123Smax.romanov@nginx.com 
5161123Smax.romanov@nginx.com     return req_app_link;
517167Smax.romanov@nginx.com }
518167Smax.romanov@nginx.com 
519167Smax.romanov@nginx.com 
520423Smax.romanov@nginx.com nxt_inline nxt_bool_t
521423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info,
522423Smax.romanov@nginx.com     uint32_t stream)
523423Smax.romanov@nginx.com {
524423Smax.romanov@nginx.com     nxt_buf_t   *b, *next;
525423Smax.romanov@nginx.com     nxt_bool_t  cancelled;
526423Smax.romanov@nginx.com 
527423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
528423Smax.romanov@nginx.com         return 0;
529423Smax.romanov@nginx.com     }
530423Smax.romanov@nginx.com 
531423Smax.romanov@nginx.com     cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking,
532423Smax.romanov@nginx.com                                               stream);
533423Smax.romanov@nginx.com 
534423Smax.romanov@nginx.com     if (cancelled) {
535423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router", stream);
536423Smax.romanov@nginx.com     }
537423Smax.romanov@nginx.com 
538423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
539423Smax.romanov@nginx.com         next = b->next;
540423Smax.romanov@nginx.com 
541423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
542423Smax.romanov@nginx.com 
543423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
544423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
545423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
546423Smax.romanov@nginx.com         }
547423Smax.romanov@nginx.com     }
548423Smax.romanov@nginx.com 
549423Smax.romanov@nginx.com     msg_info->buf = NULL;
550423Smax.romanov@nginx.com 
551423Smax.romanov@nginx.com     return cancelled;
552423Smax.romanov@nginx.com }
553423Smax.romanov@nginx.com 
554423Smax.romanov@nginx.com 
555167Smax.romanov@nginx.com static void
5561123Smax.romanov@nginx.com nxt_request_app_link_update_peer_handler(nxt_task_t *task, void *obj,
5571123Smax.romanov@nginx.com     void *data)
5581123Smax.romanov@nginx.com {
5591123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
5601123Smax.romanov@nginx.com 
5611123Smax.romanov@nginx.com     req_app_link = obj;
5621123Smax.romanov@nginx.com 
5631123Smax.romanov@nginx.com     nxt_request_app_link_update_peer(task, req_app_link);
5641123Smax.romanov@nginx.com 
5651123Smax.romanov@nginx.com     nxt_request_app_link_use(task, req_app_link, -1);
5661123Smax.romanov@nginx.com }
567425Smax.romanov@nginx.com 
568425Smax.romanov@nginx.com 
569425Smax.romanov@nginx.com static void
5701123Smax.romanov@nginx.com nxt_request_app_link_update_peer(nxt_task_t *task,
5711123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
572167Smax.romanov@nginx.com {
5731123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
5741123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
5751123Smax.romanov@nginx.com 
5761123Smax.romanov@nginx.com     engine = req_app_link->work.data;
5771123Smax.romanov@nginx.com 
5781123Smax.romanov@nginx.com     if (task->thread->engine != engine) {
5791123Smax.romanov@nginx.com         nxt_request_app_link_inc_use(req_app_link);
5801123Smax.romanov@nginx.com 
5811123Smax.romanov@nginx.com         req_app_link->work.handler = nxt_request_app_link_update_peer_handler;
5821123Smax.romanov@nginx.com         req_app_link->work.task = &engine->task;
5831123Smax.romanov@nginx.com         req_app_link->work.next = NULL;
5841123Smax.romanov@nginx.com 
5851123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD post update peer to %p",
5861123Smax.romanov@nginx.com                   req_app_link->stream, engine);
5871123Smax.romanov@nginx.com 
5881123Smax.romanov@nginx.com         nxt_event_engine_post(engine, &req_app_link->work);
5891123Smax.romanov@nginx.com 
5901123Smax.romanov@nginx.com         return;
5911123Smax.romanov@nginx.com     }
5921123Smax.romanov@nginx.com 
5931123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD update peer",
5941123Smax.romanov@nginx.com               req_app_link->stream);
5951123Smax.romanov@nginx.com 
5961123Smax.romanov@nginx.com     req_rpc_data = req_app_link->req_rpc_data;
5971123Smax.romanov@nginx.com 
5981123Smax.romanov@nginx.com     if (req_rpc_data != NULL && req_app_link->app_port != NULL) {
5991123Smax.romanov@nginx.com         nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data,
6001123Smax.romanov@nginx.com                                  req_app_link->app_port->pid);
6011123Smax.romanov@nginx.com     }
6021123Smax.romanov@nginx.com 
6031123Smax.romanov@nginx.com     nxt_request_app_link_use(task, req_app_link, -1);
604425Smax.romanov@nginx.com }
605425Smax.romanov@nginx.com 
606425Smax.romanov@nginx.com 
607425Smax.romanov@nginx.com static void
6081123Smax.romanov@nginx.com nxt_request_app_link_release(nxt_task_t *task,
6091123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
610425Smax.romanov@nginx.com {
611431Sigor@sysoev.ru     nxt_mp_t                *mp;
6121131Smax.romanov@nginx.com     nxt_http_request_t      *r;
6131123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
6141123Smax.romanov@nginx.com 
6151123Smax.romanov@nginx.com     nxt_assert(task->thread->engine == req_app_link->work.data);
6161123Smax.romanov@nginx.com     nxt_assert(req_app_link->use_count == 0);
6171123Smax.romanov@nginx.com 
6181123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD release", req_app_link->stream);
6191123Smax.romanov@nginx.com 
6201123Smax.romanov@nginx.com     req_rpc_data = req_app_link->req_rpc_data;
6211123Smax.romanov@nginx.com 
6221123Smax.romanov@nginx.com     if (req_rpc_data != NULL) {
6231123Smax.romanov@nginx.com         if (nxt_slow_path(req_app_link->err_code != 0)) {
6241123Smax.romanov@nginx.com             nxt_http_request_error(task, req_rpc_data->request,
6251123Smax.romanov@nginx.com                                    req_app_link->err_code);
626423Smax.romanov@nginx.com 
627423Smax.romanov@nginx.com         } else {
6281123Smax.romanov@nginx.com             req_rpc_data->app_port = req_app_link->app_port;
6291123Smax.romanov@nginx.com             req_rpc_data->apr_action = req_app_link->apr_action;
6301123Smax.romanov@nginx.com             req_rpc_data->msg_info = req_app_link->msg_info;
6311123Smax.romanov@nginx.com 
6321123Smax.romanov@nginx.com             if (req_rpc_data->app->timeout != 0) {
6331131Smax.romanov@nginx.com                 r = req_rpc_data->request;
6341131Smax.romanov@nginx.com 
6351131Smax.romanov@nginx.com                 r->timer.handler = nxt_router_app_timeout;
6361131Smax.romanov@nginx.com                 r->timer_data = req_rpc_data;
6371131Smax.romanov@nginx.com                 nxt_timer_add(task->thread->engine, &r->timer,
6381123Smax.romanov@nginx.com                               req_rpc_data->app->timeout);
639425Smax.romanov@nginx.com             }
640425Smax.romanov@nginx.com 
6411123Smax.romanov@nginx.com             req_app_link->app_port = NULL;
6421123Smax.romanov@nginx.com             req_app_link->msg_info.buf = NULL;
643423Smax.romanov@nginx.com         }
644343Smax.romanov@nginx.com 
6451123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
6461123Smax.romanov@nginx.com         req_app_link->req_rpc_data = NULL;
6471123Smax.romanov@nginx.com     }
6481123Smax.romanov@nginx.com 
6491123Smax.romanov@nginx.com     if (req_app_link->app_port != NULL) {
6501123Smax.romanov@nginx.com         nxt_router_app_port_release(task, req_app_link->app_port,
6511123Smax.romanov@nginx.com                                     req_app_link->apr_action);
6521123Smax.romanov@nginx.com 
6531123Smax.romanov@nginx.com         req_app_link->app_port = NULL;
6541123Smax.romanov@nginx.com     }
6551123Smax.romanov@nginx.com 
6561123Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &req_app_link->msg_info, req_app_link->stream);
6571123Smax.romanov@nginx.com 
6581123Smax.romanov@nginx.com     mp = req_app_link->mem_pool;
659430Sigor@sysoev.ru 
660430Sigor@sysoev.ru     if (mp != NULL) {
6611123Smax.romanov@nginx.com         nxt_mp_free(mp, req_app_link);
662430Sigor@sysoev.ru         nxt_mp_release(mp);
663351Smax.romanov@nginx.com     }
664167Smax.romanov@nginx.com }
665167Smax.romanov@nginx.com 
666167Smax.romanov@nginx.com 
667425Smax.romanov@nginx.com static void
6681123Smax.romanov@nginx.com nxt_request_app_link_release_handler(nxt_task_t *task, void *obj, void *data)
669425Smax.romanov@nginx.com {
6701123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
6711123Smax.romanov@nginx.com 
6721123Smax.romanov@nginx.com     req_app_link = obj;
6731123Smax.romanov@nginx.com 
6741123Smax.romanov@nginx.com     nxt_assert(req_app_link->work.data == data);
6751123Smax.romanov@nginx.com 
6761123Smax.romanov@nginx.com     nxt_atomic_fetch_add(&req_app_link->use_count, -1);
6771123Smax.romanov@nginx.com 
6781123Smax.romanov@nginx.com     nxt_request_app_link_release(task, req_app_link);
679425Smax.romanov@nginx.com }
680425Smax.romanov@nginx.com 
681425Smax.romanov@nginx.com 
682425Smax.romanov@nginx.com static void
6831123Smax.romanov@nginx.com nxt_request_app_link_use(nxt_task_t *task, nxt_request_app_link_t *req_app_link,
6841123Smax.romanov@nginx.com     int i)
685425Smax.romanov@nginx.com {
686425Smax.romanov@nginx.com     int                 c;
687425Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
688425Smax.romanov@nginx.com 
6891123Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&req_app_link->use_count, i);
690425Smax.romanov@nginx.com 
691425Smax.romanov@nginx.com     if (i < 0 && c == -i) {
6921123Smax.romanov@nginx.com         engine = req_app_link->work.data;
693425Smax.romanov@nginx.com 
694425Smax.romanov@nginx.com         if (task->thread->engine == engine) {
6951123Smax.romanov@nginx.com             nxt_request_app_link_release(task, req_app_link);
696425Smax.romanov@nginx.com 
697425Smax.romanov@nginx.com             return;
698425Smax.romanov@nginx.com         }
699425Smax.romanov@nginx.com 
7001123Smax.romanov@nginx.com         nxt_request_app_link_inc_use(req_app_link);
7011123Smax.romanov@nginx.com 
7021123Smax.romanov@nginx.com         req_app_link->work.handler = nxt_request_app_link_release_handler;
7031123Smax.romanov@nginx.com         req_app_link->work.task = &engine->task;
7041123Smax.romanov@nginx.com         req_app_link->work.next = NULL;
7051123Smax.romanov@nginx.com 
7061123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD post release to %p",
7071123Smax.romanov@nginx.com                   req_app_link->stream, engine);
7081123Smax.romanov@nginx.com 
7091123Smax.romanov@nginx.com         nxt_event_engine_post(engine, &req_app_link->work);
710425Smax.romanov@nginx.com     }
711425Smax.romanov@nginx.com }
712425Smax.romanov@nginx.com 
713425Smax.romanov@nginx.com 
714423Smax.romanov@nginx.com nxt_inline void
7151123Smax.romanov@nginx.com nxt_request_app_link_error(nxt_request_app_link_t *req_app_link, int code,
7161123Smax.romanov@nginx.com     const char *str)
717345Smax.romanov@nginx.com {
7181123Smax.romanov@nginx.com     req_app_link->app_port = NULL;
7191123Smax.romanov@nginx.com     req_app_link->err_code = code;
7201123Smax.romanov@nginx.com     req_app_link->err_str = str;
721345Smax.romanov@nginx.com }
722345Smax.romanov@nginx.com 
723345Smax.romanov@nginx.com 
724427Smax.romanov@nginx.com nxt_inline void
7251123Smax.romanov@nginx.com nxt_request_app_link_pending(nxt_task_t *task, nxt_app_t *app,
7261123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
727427Smax.romanov@nginx.com {
7281123Smax.romanov@nginx.com     nxt_queue_insert_tail(&req_app_link->app_port->pending_requests,
7291123Smax.romanov@nginx.com                           &req_app_link->link_port_pending);
7301123Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->pending, &req_app_link->link_app_pending);
7311123Smax.romanov@nginx.com 
7321123Smax.romanov@nginx.com     nxt_request_app_link_inc_use(req_app_link);
7331123Smax.romanov@nginx.com 
7341123Smax.romanov@nginx.com     req_app_link->res_time = nxt_thread_monotonic_time(task->thread)
7351123Smax.romanov@nginx.com                              + app->res_timeout;
7361123Smax.romanov@nginx.com 
7371123Smax.romanov@nginx.com     nxt_debug(task, "req_app_link stream #%uD enqueue to pending_requests",
7381123Smax.romanov@nginx.com               req_app_link->stream);
739427Smax.romanov@nginx.com }
740427Smax.romanov@nginx.com 
741427Smax.romanov@nginx.com 
742425Smax.romanov@nginx.com nxt_inline nxt_bool_t
743425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
744425Smax.romanov@nginx.com {
745425Smax.romanov@nginx.com     if (lnk->next != NULL) {
746425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
747425Smax.romanov@nginx.com 
748425Smax.romanov@nginx.com         lnk->next = NULL;
749425Smax.romanov@nginx.com 
750425Smax.romanov@nginx.com         return 1;
751425Smax.romanov@nginx.com     }
752425Smax.romanov@nginx.com 
753425Smax.romanov@nginx.com     return 0;
754425Smax.romanov@nginx.com }
755425Smax.romanov@nginx.com 
756425Smax.romanov@nginx.com 
757343Smax.romanov@nginx.com nxt_inline void
7581123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task,
7591123Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
760343Smax.romanov@nginx.com {
7611123Smax.romanov@nginx.com     int                     ra_use_delta;
7621123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
7631123Smax.romanov@nginx.com 
7641123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
7651123Smax.romanov@nginx.com         nxt_router_app_port_release(task, req_rpc_data->app_port,
7661123Smax.romanov@nginx.com                                     req_rpc_data->apr_action);
7671123Smax.romanov@nginx.com 
7681123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
7691123Smax.romanov@nginx.com     }
7701123Smax.romanov@nginx.com 
7711123Smax.romanov@nginx.com     nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
7721123Smax.romanov@nginx.com 
7731123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
7741123Smax.romanov@nginx.com     if (req_app_link != NULL) {
7751123Smax.romanov@nginx.com         req_rpc_data->req_app_link = NULL;
7761123Smax.romanov@nginx.com         req_app_link->req_rpc_data = NULL;
777343Smax.romanov@nginx.com 
778425Smax.romanov@nginx.com         ra_use_delta = 0;
779425Smax.romanov@nginx.com 
7801123Smax.romanov@nginx.com         nxt_thread_mutex_lock(&req_rpc_data->app->mutex);
7811123Smax.romanov@nginx.com 
7821123Smax.romanov@nginx.com         if (req_app_link->link_app_requests.next == NULL
7831123Smax.romanov@nginx.com             && req_app_link->link_port_pending.next == NULL
7841131Smax.romanov@nginx.com             && req_app_link->link_app_pending.next == NULL
7851131Smax.romanov@nginx.com             && req_app_link->link_port_websockets.next == NULL)
786425Smax.romanov@nginx.com         {
7871123Smax.romanov@nginx.com             req_app_link = NULL;
788343Smax.romanov@nginx.com 
789343Smax.romanov@nginx.com         } else {
7901123Smax.romanov@nginx.com             ra_use_delta -=
7911123Smax.romanov@nginx.com                 nxt_queue_chk_remove(&req_app_link->link_app_requests)
7921131Smax.romanov@nginx.com                 + nxt_queue_chk_remove(&req_app_link->link_port_pending)
7931131Smax.romanov@nginx.com                 + nxt_queue_chk_remove(&req_app_link->link_port_websockets);
7941123Smax.romanov@nginx.com 
7951123Smax.romanov@nginx.com             nxt_queue_chk_remove(&req_app_link->link_app_pending);
796343Smax.romanov@nginx.com         }
797343Smax.romanov@nginx.com 
7981123Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&req_rpc_data->app->mutex);
7991123Smax.romanov@nginx.com 
8001123Smax.romanov@nginx.com         if (req_app_link != NULL) {
8011123Smax.romanov@nginx.com             nxt_request_app_link_use(task, req_app_link, ra_use_delta);
802425Smax.romanov@nginx.com         }
803343Smax.romanov@nginx.com     }
804343Smax.romanov@nginx.com 
8051123Smax.romanov@nginx.com     if (req_rpc_data->app != NULL) {
8061123Smax.romanov@nginx.com         nxt_router_app_use(task, req_rpc_data->app, -1);
8071123Smax.romanov@nginx.com 
8081123Smax.romanov@nginx.com         req_rpc_data->app = NULL;
8091123Smax.romanov@nginx.com     }
8101123Smax.romanov@nginx.com 
8111123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
8121123Smax.romanov@nginx.com         req_rpc_data->request->timer_data = NULL;
8131123Smax.romanov@nginx.com 
8141123Smax.romanov@nginx.com         nxt_router_http_request_done(task, req_rpc_data->request);
8151123Smax.romanov@nginx.com 
8161131Smax.romanov@nginx.com         req_rpc_data->request->req_rpc_data = NULL;
8171123Smax.romanov@nginx.com         req_rpc_data->request = NULL;
818346Smax.romanov@nginx.com     }
819343Smax.romanov@nginx.com }
820343Smax.romanov@nginx.com 
821343Smax.romanov@nginx.com 
822141Smax.romanov@nginx.com void
823141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
824141Smax.romanov@nginx.com {
825141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
826141Smax.romanov@nginx.com 
827670Smax.romanov@nginx.com     if (msg->u.new_port != NULL
828670Smax.romanov@nginx.com         && msg->u.new_port->type == NXT_PROCESS_CONTROLLER)
829670Smax.romanov@nginx.com     {
830662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
831662Smax.romanov@nginx.com     }
832662Smax.romanov@nginx.com 
833192Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
834141Smax.romanov@nginx.com         return;
835141Smax.romanov@nginx.com     }
836141Smax.romanov@nginx.com 
837426Smax.romanov@nginx.com     if (msg->u.new_port == NULL
838426Smax.romanov@nginx.com         || msg->u.new_port->type != NXT_PROCESS_WORKER)
839347Smax.romanov@nginx.com     {
840192Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
841141Smax.romanov@nginx.com     }
842192Smax.romanov@nginx.com 
843192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
844141Smax.romanov@nginx.com }
845141Smax.romanov@nginx.com 
846141Smax.romanov@nginx.com 
847139Sigor@sysoev.ru void
848139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
849115Sigor@sysoev.ru {
850198Sigor@sysoev.ru     nxt_int_t               ret;
851139Sigor@sysoev.ru     nxt_buf_t               *b;
852139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
853139Sigor@sysoev.ru 
854139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
855139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
856139Sigor@sysoev.ru         return;
85753Sigor@sysoev.ru     }
85853Sigor@sysoev.ru 
859494Spluknet@nginx.com     nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s",
860423Smax.romanov@nginx.com               nxt_buf_used_size(msg->buf),
861493Spluknet@nginx.com               (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos);
862423Smax.romanov@nginx.com 
863591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
864139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
865139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
866198Sigor@sysoev.ru                                        msg->port_msg.pid,
867198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
868198Sigor@sysoev.ru 
869779Smax.romanov@nginx.com     if (nxt_slow_path(tmcf->port == NULL)) {
870779Smax.romanov@nginx.com         nxt_alert(task, "reply port not found");
871779Smax.romanov@nginx.com 
872779Smax.romanov@nginx.com         return;
873779Smax.romanov@nginx.com     }
874779Smax.romanov@nginx.com 
875779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
876779Smax.romanov@nginx.com 
877591Sigor@sysoev.ru     b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool,
878591Sigor@sysoev.ru                                msg->buf, msg->size);
879551Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
880551Smax.romanov@nginx.com         nxt_router_conf_error(task, tmcf);
881551Smax.romanov@nginx.com 
882551Smax.romanov@nginx.com         return;
883551Smax.romanov@nginx.com     }
884551Smax.romanov@nginx.com 
885198Sigor@sysoev.ru     ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free);
886198Sigor@sysoev.ru 
887198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
888198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
889198Sigor@sysoev.ru 
890198Sigor@sysoev.ru     } else {
891198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
892139Sigor@sysoev.ru     }
89353Sigor@sysoev.ru }
89453Sigor@sysoev.ru 
89553Sigor@sysoev.ru 
896347Smax.romanov@nginx.com static void
897507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
898507Smax.romanov@nginx.com     void *data)
899347Smax.romanov@nginx.com {
900347Smax.romanov@nginx.com     union {
901347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
902347Smax.romanov@nginx.com         void       *data;
903347Smax.romanov@nginx.com     } u;
904347Smax.romanov@nginx.com 
905347Smax.romanov@nginx.com     u.data = data;
906347Smax.romanov@nginx.com 
907347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
908347Smax.romanov@nginx.com }
909347Smax.romanov@nginx.com 
910347Smax.romanov@nginx.com 
911192Smax.romanov@nginx.com void
912192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
913192Smax.romanov@nginx.com {
914347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
915318Smax.romanov@nginx.com 
916192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
917192Smax.romanov@nginx.com 
918318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
919318Smax.romanov@nginx.com     {
920507Smax.romanov@nginx.com         nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
921347Smax.romanov@nginx.com                       msg->u.data);
922318Smax.romanov@nginx.com     }
923318Smax.romanov@nginx.com     nxt_queue_loop;
924318Smax.romanov@nginx.com 
9251085Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
9261085Smax.romanov@nginx.com         return;
9271085Smax.romanov@nginx.com     }
9281085Smax.romanov@nginx.com 
929192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
930192Smax.romanov@nginx.com 
931192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
932192Smax.romanov@nginx.com }
933192Smax.romanov@nginx.com 
934192Smax.romanov@nginx.com 
93553Sigor@sysoev.ru static nxt_router_temp_conf_t *
936139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
93753Sigor@sysoev.ru {
93865Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
93953Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
94053Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
94153Sigor@sysoev.ru 
94265Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
94353Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
94453Sigor@sysoev.ru         return NULL;
94553Sigor@sysoev.ru     }
94653Sigor@sysoev.ru 
94765Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
94853Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
94953Sigor@sysoev.ru         goto fail;
95053Sigor@sysoev.ru     }
95153Sigor@sysoev.ru 
95253Sigor@sysoev.ru     rtcf->mem_pool = mp;
95353Sigor@sysoev.ru 
95465Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
95553Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
95653Sigor@sysoev.ru         goto fail;
95753Sigor@sysoev.ru     }
95853Sigor@sysoev.ru 
95965Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
96053Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
96153Sigor@sysoev.ru         goto temp_fail;
96253Sigor@sysoev.ru     }
96353Sigor@sysoev.ru 
96453Sigor@sysoev.ru     tmcf->mem_pool = tmp;
965591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
966139Sigor@sysoev.ru     tmcf->count = 1;
967139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
96853Sigor@sysoev.ru 
96953Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
97053Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
97153Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
97253Sigor@sysoev.ru         goto temp_fail;
97353Sigor@sysoev.ru     }
97453Sigor@sysoev.ru 
97553Sigor@sysoev.ru     nxt_queue_init(&tmcf->deleting);
97653Sigor@sysoev.ru     nxt_queue_init(&tmcf->keeping);
97753Sigor@sysoev.ru     nxt_queue_init(&tmcf->updating);
97853Sigor@sysoev.ru     nxt_queue_init(&tmcf->pending);
97953Sigor@sysoev.ru     nxt_queue_init(&tmcf->creating);
980416Smax.romanov@nginx.com 
981774Svbart@nginx.com #if (NXT_TLS)
982774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
983774Svbart@nginx.com #endif
984774Svbart@nginx.com 
985133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
986133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
98753Sigor@sysoev.ru 
98853Sigor@sysoev.ru     return tmcf;
98953Sigor@sysoev.ru 
99053Sigor@sysoev.ru temp_fail:
99153Sigor@sysoev.ru 
99265Sigor@sysoev.ru     nxt_mp_destroy(tmp);
99353Sigor@sysoev.ru 
99453Sigor@sysoev.ru fail:
99553Sigor@sysoev.ru 
99665Sigor@sysoev.ru     nxt_mp_destroy(mp);
99753Sigor@sysoev.ru 
99853Sigor@sysoev.ru     return NULL;
99953Sigor@sysoev.ru }
100053Sigor@sysoev.ru 
100153Sigor@sysoev.ru 
1002507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1003507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
1004507Smax.romanov@nginx.com {
1005507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
1006507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
1007507Smax.romanov@nginx.com }
1008507Smax.romanov@nginx.com 
1009507Smax.romanov@nginx.com 
1010507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1011507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
1012507Smax.romanov@nginx.com {
1013507Smax.romanov@nginx.com     return app->idle_processes + app->pending_processes
1014507Smax.romanov@nginx.com             < app->spare_processes;
1015507Smax.romanov@nginx.com }
1016507Smax.romanov@nginx.com 
1017507Smax.romanov@nginx.com 
1018198Sigor@sysoev.ru static void
1019198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1020139Sigor@sysoev.ru {
1021139Sigor@sysoev.ru     nxt_int_t                    ret;
1022507Smax.romanov@nginx.com     nxt_app_t                    *app;
1023139Sigor@sysoev.ru     nxt_router_t                 *router;
1024139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1025198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1026198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1027630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1028198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1029139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1030774Svbart@nginx.com #if (NXT_TLS)
1031774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
1032774Svbart@nginx.com #endif
1033139Sigor@sysoev.ru 
1034198Sigor@sysoev.ru     tmcf = obj;
1035198Sigor@sysoev.ru 
1036198Sigor@sysoev.ru     qlk = nxt_queue_first(&tmcf->pending);
1037198Sigor@sysoev.ru 
1038198Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&tmcf->pending)) {
1039198Sigor@sysoev.ru         nxt_queue_remove(qlk);
1040198Sigor@sysoev.ru         nxt_queue_insert_tail(&tmcf->creating, qlk);
1041198Sigor@sysoev.ru 
1042198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1043198Sigor@sysoev.ru 
1044198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1045198Sigor@sysoev.ru 
1046198Sigor@sysoev.ru         return;
1047139Sigor@sysoev.ru     }
1048139Sigor@sysoev.ru 
1049774Svbart@nginx.com #if (NXT_TLS)
1050774Svbart@nginx.com     qlk = nxt_queue_first(&tmcf->tls);
1051774Svbart@nginx.com 
1052774Svbart@nginx.com     if (qlk != nxt_queue_tail(&tmcf->tls)) {
1053774Svbart@nginx.com         nxt_queue_remove(qlk);
1054774Svbart@nginx.com 
1055774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1056774Svbart@nginx.com 
1057774Svbart@nginx.com         nxt_router_tls_rpc_create(task, tmcf, tls);
1058774Svbart@nginx.com         return;
1059774Svbart@nginx.com     }
1060774Svbart@nginx.com #endif
1061774Svbart@nginx.com 
1062507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1063507Smax.romanov@nginx.com 
1064507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1065507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1066507Smax.romanov@nginx.com             return;
1067507Smax.romanov@nginx.com         }
1068507Smax.romanov@nginx.com 
1069507Smax.romanov@nginx.com     } nxt_queue_loop;
1070507Smax.romanov@nginx.com 
1071630Svbart@nginx.com     rtcf = tmcf->router_conf;
1072630Svbart@nginx.com 
1073630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1074630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1075630Svbart@nginx.com         return;
1076630Svbart@nginx.com     }
1077630Svbart@nginx.com 
1078139Sigor@sysoev.ru     rt = task->thread->runtime;
1079139Sigor@sysoev.ru 
1080139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1081139Sigor@sysoev.ru 
1082630Svbart@nginx.com     router = rtcf->router;
1083198Sigor@sysoev.ru 
1084139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1085139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1086198Sigor@sysoev.ru         goto fail;
1087139Sigor@sysoev.ru     }
1088139Sigor@sysoev.ru 
1089139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1090139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1091198Sigor@sysoev.ru         goto fail;
1092139Sigor@sysoev.ru     }
1093139Sigor@sysoev.ru 
1094343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1095139Sigor@sysoev.ru 
1096315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1097139Sigor@sysoev.ru 
1098139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->updating);
1099139Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->creating);
1100139Sigor@sysoev.ru 
1101630Svbart@nginx.com     router->access_log = rtcf->access_log;
1102630Svbart@nginx.com 
1103198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1104198Sigor@sysoev.ru 
1105198Sigor@sysoev.ru     return;
1106198Sigor@sysoev.ru 
1107198Sigor@sysoev.ru fail:
1108198Sigor@sysoev.ru 
1109198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1110198Sigor@sysoev.ru 
1111198Sigor@sysoev.ru     return;
1112139Sigor@sysoev.ru }
1113139Sigor@sysoev.ru 
1114139Sigor@sysoev.ru 
1115139Sigor@sysoev.ru static void
1116139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1117139Sigor@sysoev.ru {
1118153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1119153Sigor@sysoev.ru 
1120153Sigor@sysoev.ru     job = obj;
1121153Sigor@sysoev.ru 
1122198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1123139Sigor@sysoev.ru }
1124139Sigor@sysoev.ru 
1125139Sigor@sysoev.ru 
1126139Sigor@sysoev.ru static void
1127198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1128139Sigor@sysoev.ru {
1129139Sigor@sysoev.ru     nxt_debug(task, "temp conf count:%D", tmcf->count);
1130139Sigor@sysoev.ru 
1131139Sigor@sysoev.ru     if (--tmcf->count == 0) {
1132193Smax.romanov@nginx.com         nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1133139Sigor@sysoev.ru     }
1134139Sigor@sysoev.ru }
1135139Sigor@sysoev.ru 
1136139Sigor@sysoev.ru 
1137139Sigor@sysoev.ru static void
1138139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1139139Sigor@sysoev.ru {
1140507Smax.romanov@nginx.com     nxt_app_t          *app;
1141568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1142148Sigor@sysoev.ru     nxt_socket_t       s;
1143149Sigor@sysoev.ru     nxt_router_t       *router;
1144148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1145148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1146630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1147148Sigor@sysoev.ru 
1148564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1149198Sigor@sysoev.ru 
1150148Sigor@sysoev.ru     for (qlk = nxt_queue_first(&tmcf->creating);
1151148Sigor@sysoev.ru          qlk != nxt_queue_tail(&tmcf->creating);
1152148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1153148Sigor@sysoev.ru     {
1154148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1155359Sigor@sysoev.ru         s = skcf->listen->socket;
1156148Sigor@sysoev.ru 
1157148Sigor@sysoev.ru         if (s != -1) {
1158148Sigor@sysoev.ru             nxt_socket_close(task, s);
1159148Sigor@sysoev.ru         }
1160148Sigor@sysoev.ru 
1161359Sigor@sysoev.ru         nxt_free(skcf->listen);
1162148Sigor@sysoev.ru     }
1163148Sigor@sysoev.ru 
1164568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
1165568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->updating);
1166568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->pending);
1167568Smax.romanov@nginx.com     nxt_queue_add(&new_socket_confs, &tmcf->creating);
1168568Smax.romanov@nginx.com 
1169964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1170964Sigor@sysoev.ru 
1171964Sigor@sysoev.ru     nxt_http_routes_cleanup(task, rtcf->routes);
1172964Sigor@sysoev.ru 
1173568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1174568Smax.romanov@nginx.com 
1175964Sigor@sysoev.ru         if (skcf->pass != NULL) {
1176964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
1177568Smax.romanov@nginx.com         }
1178568Smax.romanov@nginx.com 
1179568Smax.romanov@nginx.com     } nxt_queue_loop;
1180568Smax.romanov@nginx.com 
1181507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1182507Smax.romanov@nginx.com 
1183753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1184507Smax.romanov@nginx.com 
1185507Smax.romanov@nginx.com     } nxt_queue_loop;
1186507Smax.romanov@nginx.com 
1187630Svbart@nginx.com     router = rtcf->router;
1188149Sigor@sysoev.ru 
1189149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->keeping);
1190149Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &tmcf->deleting);
1191149Sigor@sysoev.ru 
1192416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1193416Smax.romanov@nginx.com 
1194148Sigor@sysoev.ru     // TODO: new engines and threads
1195148Sigor@sysoev.ru 
1196630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1197630Svbart@nginx.com 
1198630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1199139Sigor@sysoev.ru 
1200193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1201139Sigor@sysoev.ru }
1202139Sigor@sysoev.ru 
1203139Sigor@sysoev.ru 
1204139Sigor@sysoev.ru static void
1205139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1206193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1207139Sigor@sysoev.ru {
1208193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1209779Smax.romanov@nginx.com 
1210779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1211779Smax.romanov@nginx.com 
1212779Smax.romanov@nginx.com     tmcf->port = NULL;
1213139Sigor@sysoev.ru }
1214139Sigor@sysoev.ru 
1215139Sigor@sysoev.ru 
1216115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1217115Sigor@sysoev.ru     {
1218133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1219115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1220115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1221115Sigor@sysoev.ru     },
1222115Sigor@sysoev.ru };
1223115Sigor@sysoev.ru 
1224115Sigor@sysoev.ru 
1225133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1226115Sigor@sysoev.ru     {
1227133Sigor@sysoev.ru         nxt_string("type"),
1228115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1229133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1230115Sigor@sysoev.ru     },
1231115Sigor@sysoev.ru 
1232115Sigor@sysoev.ru     {
1233507Smax.romanov@nginx.com         nxt_string("limits"),
1234507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1235507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1236133Sigor@sysoev.ru     },
1237318Smax.romanov@nginx.com 
1238318Smax.romanov@nginx.com     {
1239507Smax.romanov@nginx.com         nxt_string("processes"),
1240507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1241507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1242507Smax.romanov@nginx.com     },
1243507Smax.romanov@nginx.com 
1244507Smax.romanov@nginx.com     {
1245507Smax.romanov@nginx.com         nxt_string("processes"),
1246318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1247507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1248318Smax.romanov@nginx.com     },
1249318Smax.romanov@nginx.com };
1250318Smax.romanov@nginx.com 
1251318Smax.romanov@nginx.com 
1252318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1253318Smax.romanov@nginx.com     {
1254318Smax.romanov@nginx.com         nxt_string("timeout"),
1255318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1256318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1257318Smax.romanov@nginx.com     },
1258318Smax.romanov@nginx.com 
1259318Smax.romanov@nginx.com     {
1260427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1261427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1262427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1263427Smax.romanov@nginx.com     },
1264427Smax.romanov@nginx.com 
1265427Smax.romanov@nginx.com     {
1266318Smax.romanov@nginx.com         nxt_string("requests"),
1267318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1268318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1269318Smax.romanov@nginx.com     },
1270133Sigor@sysoev.ru };
1271133Sigor@sysoev.ru 
1272133Sigor@sysoev.ru 
1273507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1274507Smax.romanov@nginx.com     {
1275507Smax.romanov@nginx.com         nxt_string("spare"),
1276507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1277507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1278507Smax.romanov@nginx.com     },
1279507Smax.romanov@nginx.com 
1280507Smax.romanov@nginx.com     {
1281507Smax.romanov@nginx.com         nxt_string("max"),
1282507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1283507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1284507Smax.romanov@nginx.com     },
1285507Smax.romanov@nginx.com 
1286507Smax.romanov@nginx.com     {
1287507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1288507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1289507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1290507Smax.romanov@nginx.com     },
1291507Smax.romanov@nginx.com };
1292507Smax.romanov@nginx.com 
1293507Smax.romanov@nginx.com 
1294133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1295133Sigor@sysoev.ru     {
1296964Sigor@sysoev.ru         nxt_string("pass"),
1297964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1298964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1299964Sigor@sysoev.ru     },
1300964Sigor@sysoev.ru 
1301964Sigor@sysoev.ru     {
1302133Sigor@sysoev.ru         nxt_string("application"),
1303964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1304133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1305115Sigor@sysoev.ru     },
1306115Sigor@sysoev.ru };
1307115Sigor@sysoev.ru 
1308115Sigor@sysoev.ru 
1309115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1310115Sigor@sysoev.ru     {
1311115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1312115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1313115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1314115Sigor@sysoev.ru     },
1315115Sigor@sysoev.ru 
1316115Sigor@sysoev.ru     {
1317115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1318115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1319115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1320115Sigor@sysoev.ru     },
1321115Sigor@sysoev.ru 
1322115Sigor@sysoev.ru     {
1323206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1324206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1325206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1326206Smax.romanov@nginx.com     },
1327206Smax.romanov@nginx.com 
1328206Smax.romanov@nginx.com     {
1329206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1330206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1331206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1332206Smax.romanov@nginx.com     },
1333206Smax.romanov@nginx.com 
1334206Smax.romanov@nginx.com     {
1335206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1336206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1337206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1338206Smax.romanov@nginx.com     },
1339206Smax.romanov@nginx.com 
1340206Smax.romanov@nginx.com     {
1341431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1342431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1343431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1344431Sigor@sysoev.ru     },
1345431Sigor@sysoev.ru 
1346431Sigor@sysoev.ru     {
1347115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1348115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1349115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1350115Sigor@sysoev.ru     },
1351206Smax.romanov@nginx.com 
1352206Smax.romanov@nginx.com     {
1353206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1354206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1355206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1356206Smax.romanov@nginx.com     },
1357431Sigor@sysoev.ru 
1358431Sigor@sysoev.ru     {
1359431Sigor@sysoev.ru         nxt_string("send_timeout"),
1360431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1361431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1362431Sigor@sysoev.ru     },
1363115Sigor@sysoev.ru };
1364115Sigor@sysoev.ru 
1365115Sigor@sysoev.ru 
13661131Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_websocket_conf[] = {
13671131Smax.romanov@nginx.com     {
13681131Smax.romanov@nginx.com         nxt_string("max_frame_size"),
13691131Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
13701131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, max_frame_size),
13711131Smax.romanov@nginx.com     },
13721131Smax.romanov@nginx.com 
13731131Smax.romanov@nginx.com     {
13741131Smax.romanov@nginx.com         nxt_string("read_timeout"),
13751131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
13761131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, read_timeout),
13771131Smax.romanov@nginx.com     },
13781131Smax.romanov@nginx.com 
13791131Smax.romanov@nginx.com     {
13801131Smax.romanov@nginx.com         nxt_string("keepalive_interval"),
13811131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
13821131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, keepalive_interval),
13831131Smax.romanov@nginx.com     },
13841131Smax.romanov@nginx.com 
13851131Smax.romanov@nginx.com };
13861131Smax.romanov@nginx.com 
13871131Smax.romanov@nginx.com 
138853Sigor@sysoev.ru static nxt_int_t
1389115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1390115Sigor@sysoev.ru     u_char *start, u_char *end)
139153Sigor@sysoev.ru {
1392133Sigor@sysoev.ru     u_char                      *p;
1393133Sigor@sysoev.ru     size_t                      size;
1394115Sigor@sysoev.ru     nxt_mp_t                    *mp;
1395115Sigor@sysoev.ru     uint32_t                    next;
1396115Sigor@sysoev.ru     nxt_int_t                   ret;
1397630Svbart@nginx.com     nxt_str_t                   name, path;
1398133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
1399359Sigor@sysoev.ru     nxt_router_t                *router;
1400753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
14011131Smax.romanov@nginx.com     nxt_conf_value_t            *conf, *http, *value, *websocket;
1402133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1403133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
1404*1183Svbart@nginx.com     nxt_conf_value_t            *routes_conf, *static_conf;
1405115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1406964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1407507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1408216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1409133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1410630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1411115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1412774Svbart@nginx.com #if (NXT_TLS)
1413774Svbart@nginx.com     nxt_router_tlssock_t        *tls;
1414774Svbart@nginx.com #endif
1415115Sigor@sysoev.ru 
1416716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1417133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1418115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1419964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1420630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1421774Svbart@nginx.com #if (NXT_TLS)
1422774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1423774Svbart@nginx.com #endif
1424*1183Svbart@nginx.com     static nxt_str_t  static_path = nxt_string("/settings/http/static");
14251131Smax.romanov@nginx.com     static nxt_str_t  websocket_path = nxt_string("/settings/http/websocket");
1426115Sigor@sysoev.ru 
1427208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1428115Sigor@sysoev.ru     if (conf == NULL) {
1429564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1430115Sigor@sysoev.ru         return NXT_ERROR;
1431115Sigor@sysoev.ru     }
1432115Sigor@sysoev.ru 
1433591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1434213Svbart@nginx.com 
1435213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1436591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1437115Sigor@sysoev.ru     if (ret != NXT_OK) {
1438564Svbart@nginx.com         nxt_alert(task, "root map error");
1439115Sigor@sysoev.ru         return NXT_ERROR;
1440115Sigor@sysoev.ru     }
1441115Sigor@sysoev.ru 
1442591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1443591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1444117Sigor@sysoev.ru     }
1445117Sigor@sysoev.ru 
1446*1183Svbart@nginx.com     static_conf = nxt_conf_get_path(conf, &static_path);
1447*1183Svbart@nginx.com 
1448*1183Svbart@nginx.com     ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
1449*1183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1450*1183Svbart@nginx.com         return NXT_ERROR;
1451*1183Svbart@nginx.com     }
1452*1183Svbart@nginx.com 
14531115Svbart@nginx.com     router = tmcf->router_conf->router;
14541115Svbart@nginx.com 
1455133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
14561115Svbart@nginx.com 
14571115Svbart@nginx.com     if (applications != NULL) {
14581115Svbart@nginx.com         next = 0;
14591115Svbart@nginx.com 
14601115Svbart@nginx.com         for ( ;; ) {
14611115Svbart@nginx.com             application = nxt_conf_next_object_member(applications, &name, &next);
14621115Svbart@nginx.com             if (application == NULL) {
14631115Svbart@nginx.com                 break;
14641115Svbart@nginx.com             }
14651115Svbart@nginx.com 
14661115Svbart@nginx.com             nxt_debug(task, "application \"%V\"", &name);
14671115Svbart@nginx.com 
14681115Svbart@nginx.com             size = nxt_conf_json_length(application, NULL);
14691115Svbart@nginx.com 
14701115Svbart@nginx.com             app = nxt_malloc(sizeof(nxt_app_t) + name.length + size);
14711115Svbart@nginx.com             if (app == NULL) {
14721115Svbart@nginx.com                 goto fail;
14731115Svbart@nginx.com             }
14741115Svbart@nginx.com 
14751115Svbart@nginx.com             nxt_memzero(app, sizeof(nxt_app_t));
14761115Svbart@nginx.com 
14771115Svbart@nginx.com             app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
14781115Svbart@nginx.com             app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
14791115Svbart@nginx.com                                                   + name.length);
14801115Svbart@nginx.com 
14811115Svbart@nginx.com             p = nxt_conf_json_print(app->conf.start, application, NULL);
14821115Svbart@nginx.com             app->conf.length = p - app->conf.start;
14831115Svbart@nginx.com 
14841115Svbart@nginx.com             nxt_assert(app->conf.length <= size);
14851115Svbart@nginx.com 
14861115Svbart@nginx.com             nxt_debug(task, "application conf \"%V\"", &app->conf);
14871115Svbart@nginx.com 
14881115Svbart@nginx.com             prev = nxt_router_app_find(&router->apps, &name);
14891115Svbart@nginx.com 
14901115Svbart@nginx.com             if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
14911115Svbart@nginx.com                 nxt_free(app);
14921115Svbart@nginx.com 
14931115Svbart@nginx.com                 nxt_queue_remove(&prev->link);
14941115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
14951115Svbart@nginx.com                 continue;
14961115Svbart@nginx.com             }
14971115Svbart@nginx.com 
14981115Svbart@nginx.com             apcf.processes = 1;
14991115Svbart@nginx.com             apcf.max_processes = 1;
15001115Svbart@nginx.com             apcf.spare_processes = 0;
15011115Svbart@nginx.com             apcf.timeout = 0;
15021115Svbart@nginx.com             apcf.res_timeout = 1000;
15031115Svbart@nginx.com             apcf.idle_timeout = 15000;
15041115Svbart@nginx.com             apcf.requests = 0;
15051115Svbart@nginx.com             apcf.limits_value = NULL;
15061115Svbart@nginx.com             apcf.processes_value = NULL;
15071115Svbart@nginx.com 
15081115Svbart@nginx.com             app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
15091115Svbart@nginx.com             if (nxt_slow_path(app_joint == NULL)) {
1510318Smax.romanov@nginx.com                 goto app_fail;
1511318Smax.romanov@nginx.com             }
1512318Smax.romanov@nginx.com 
15131115Svbart@nginx.com             nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
15141115Svbart@nginx.com 
15151115Svbart@nginx.com             ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
15161115Svbart@nginx.com                                       nxt_nitems(nxt_router_app_conf), &apcf);
1517318Smax.romanov@nginx.com             if (ret != NXT_OK) {
15181115Svbart@nginx.com                 nxt_alert(task, "application map error");
1519318Smax.romanov@nginx.com                 goto app_fail;
1520318Smax.romanov@nginx.com             }
15211115Svbart@nginx.com 
15221115Svbart@nginx.com             if (apcf.limits_value != NULL) {
15231115Svbart@nginx.com 
15241115Svbart@nginx.com                 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
15251115Svbart@nginx.com                     nxt_alert(task, "application limits is not object");
15261115Svbart@nginx.com                     goto app_fail;
15271115Svbart@nginx.com                 }
15281115Svbart@nginx.com 
15291115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.limits_value,
15301115Svbart@nginx.com                                         nxt_router_app_limits_conf,
15311115Svbart@nginx.com                                         nxt_nitems(nxt_router_app_limits_conf),
15321115Svbart@nginx.com                                         &apcf);
15331115Svbart@nginx.com                 if (ret != NXT_OK) {
15341115Svbart@nginx.com                     nxt_alert(task, "application limits map error");
15351115Svbart@nginx.com                     goto app_fail;
15361115Svbart@nginx.com                 }
15371115Svbart@nginx.com             }
15381115Svbart@nginx.com 
15391115Svbart@nginx.com             if (apcf.processes_value != NULL
15401115Svbart@nginx.com                 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
15411115Svbart@nginx.com             {
15421115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.processes_value,
15431115Svbart@nginx.com                                      nxt_router_app_processes_conf,
15441115Svbart@nginx.com                                      nxt_nitems(nxt_router_app_processes_conf),
15451115Svbart@nginx.com                                      &apcf);
15461115Svbart@nginx.com                 if (ret != NXT_OK) {
15471115Svbart@nginx.com                     nxt_alert(task, "application processes map error");
15481115Svbart@nginx.com                     goto app_fail;
15491115Svbart@nginx.com                 }
15501115Svbart@nginx.com 
15511115Svbart@nginx.com             } else {
15521115Svbart@nginx.com                 apcf.max_processes = apcf.processes;
15531115Svbart@nginx.com                 apcf.spare_processes = apcf.processes;
15541115Svbart@nginx.com             }
15551115Svbart@nginx.com 
15561115Svbart@nginx.com             nxt_debug(task, "application type: %V", &apcf.type);
15571115Svbart@nginx.com             nxt_debug(task, "application processes: %D", apcf.processes);
15581115Svbart@nginx.com             nxt_debug(task, "application request timeout: %M", apcf.timeout);
15591115Svbart@nginx.com             nxt_debug(task, "application reschedule timeout: %M",
15601115Svbart@nginx.com                       apcf.res_timeout);
15611115Svbart@nginx.com             nxt_debug(task, "application requests: %D", apcf.requests);
15621115Svbart@nginx.com 
15631115Svbart@nginx.com             lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
15641115Svbart@nginx.com 
15651115Svbart@nginx.com             if (lang == NULL) {
15661115Svbart@nginx.com                 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1567507Smax.romanov@nginx.com                 goto app_fail;
1568507Smax.romanov@nginx.com             }
1569507Smax.romanov@nginx.com 
15701115Svbart@nginx.com             nxt_debug(task, "application language module: \"%s\"", lang->file);
15711115Svbart@nginx.com 
15721115Svbart@nginx.com             ret = nxt_thread_mutex_create(&app->mutex);
15731115Svbart@nginx.com             if (ret != NXT_OK) {
15741115Svbart@nginx.com                 goto app_fail;
15751115Svbart@nginx.com             }
15761115Svbart@nginx.com 
15771115Svbart@nginx.com             nxt_queue_init(&app->ports);
15781115Svbart@nginx.com             nxt_queue_init(&app->spare_ports);
15791115Svbart@nginx.com             nxt_queue_init(&app->idle_ports);
15801115Svbart@nginx.com             nxt_queue_init(&app->requests);
15811115Svbart@nginx.com             nxt_queue_init(&app->pending);
15821115Svbart@nginx.com 
15831115Svbart@nginx.com             app->name.length = name.length;
15841115Svbart@nginx.com             nxt_memcpy(app->name.start, name.start, name.length);
15851115Svbart@nginx.com 
15861115Svbart@nginx.com             app->type = lang->type;
15871115Svbart@nginx.com             app->max_processes = apcf.max_processes;
15881115Svbart@nginx.com             app->spare_processes = apcf.spare_processes;
15891115Svbart@nginx.com             app->max_pending_processes = apcf.spare_processes
15901115Svbart@nginx.com                                          ? apcf.spare_processes : 1;
15911115Svbart@nginx.com             app->timeout = apcf.timeout;
15921115Svbart@nginx.com             app->res_timeout = apcf.res_timeout * 1000000;
15931115Svbart@nginx.com             app->idle_timeout = apcf.idle_timeout;
15941115Svbart@nginx.com             app->max_pending_responses = 2;
15951115Svbart@nginx.com             app->max_requests = apcf.requests;
15961115Svbart@nginx.com 
15971115Svbart@nginx.com             engine = task->thread->engine;
15981115Svbart@nginx.com 
15991115Svbart@nginx.com             app->engine = engine;
16001115Svbart@nginx.com 
16011115Svbart@nginx.com             app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
16021115Svbart@nginx.com             app->adjust_idle_work.task = &engine->task;
16031115Svbart@nginx.com             app->adjust_idle_work.obj = app;
16041115Svbart@nginx.com 
16051115Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->apps, &app->link);
16061115Svbart@nginx.com 
16071115Svbart@nginx.com             nxt_router_app_use(task, app, 1);
16081115Svbart@nginx.com 
16091115Svbart@nginx.com             app->joint = app_joint;
16101115Svbart@nginx.com 
16111115Svbart@nginx.com             app_joint->use_count = 1;
16121115Svbart@nginx.com             app_joint->app = app;
16131115Svbart@nginx.com 
16141115Svbart@nginx.com             app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
16151115Svbart@nginx.com             app_joint->idle_timer.work_queue = &engine->fast_work_queue;
16161115Svbart@nginx.com             app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
16171115Svbart@nginx.com             app_joint->idle_timer.task = &engine->task;
16181115Svbart@nginx.com             app_joint->idle_timer.log = app_joint->idle_timer.task->log;
16191115Svbart@nginx.com 
16201115Svbart@nginx.com             app_joint->free_app_work.handler = nxt_router_free_app;
16211115Svbart@nginx.com             app_joint->free_app_work.task = &engine->task;
16221115Svbart@nginx.com             app_joint->free_app_work.obj = app_joint;
1623133Sigor@sysoev.ru         }
1624133Sigor@sysoev.ru     }
1625133Sigor@sysoev.ru 
1626964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1627964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1628964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1629964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1630964Sigor@sysoev.ru             return NXT_ERROR;
1631964Sigor@sysoev.ru         }
1632964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1633964Sigor@sysoev.ru     }
1634964Sigor@sysoev.ru 
1635133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1636133Sigor@sysoev.ru #if 0
1637133Sigor@sysoev.ru     if (http == NULL) {
1638564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1639133Sigor@sysoev.ru         return NXT_ERROR;
1640133Sigor@sysoev.ru     }
1641133Sigor@sysoev.ru #endif
1642133Sigor@sysoev.ru 
16431131Smax.romanov@nginx.com     websocket = nxt_conf_get_path(conf, &websocket_path);
16441131Smax.romanov@nginx.com 
1645133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
16461115Svbart@nginx.com 
16471115Svbart@nginx.com     if (listeners != NULL) {
16481115Svbart@nginx.com         next = 0;
16491115Svbart@nginx.com 
16501115Svbart@nginx.com         for ( ;; ) {
16511115Svbart@nginx.com             listener = nxt_conf_next_object_member(listeners, &name, &next);
16521115Svbart@nginx.com             if (listener == NULL) {
16531115Svbart@nginx.com                 break;
16541115Svbart@nginx.com             }
16551115Svbart@nginx.com 
16561115Svbart@nginx.com             skcf = nxt_router_socket_conf(task, tmcf, &name);
16571115Svbart@nginx.com             if (skcf == NULL) {
16581115Svbart@nginx.com                 goto fail;
16591115Svbart@nginx.com             }
16601115Svbart@nginx.com 
16611115Svbart@nginx.com             nxt_memzero(&lscf, sizeof(lscf));
16621115Svbart@nginx.com 
16631115Svbart@nginx.com             ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
16641115Svbart@nginx.com                                       nxt_nitems(nxt_router_listener_conf),
16651115Svbart@nginx.com                                       &lscf);
1666133Sigor@sysoev.ru             if (ret != NXT_OK) {
16671115Svbart@nginx.com                 nxt_alert(task, "listener map error");
1668133Sigor@sysoev.ru                 goto fail;
1669133Sigor@sysoev.ru             }
16701115Svbart@nginx.com 
16711115Svbart@nginx.com             nxt_debug(task, "application: %V", &lscf.application);
16721115Svbart@nginx.com 
16731115Svbart@nginx.com             // STUB, default values if http block is not defined.
16741115Svbart@nginx.com             skcf->header_buffer_size = 2048;
16751115Svbart@nginx.com             skcf->large_header_buffer_size = 8192;
16761115Svbart@nginx.com             skcf->large_header_buffers = 4;
16771115Svbart@nginx.com             skcf->body_buffer_size = 16 * 1024;
16781115Svbart@nginx.com             skcf->max_body_size = 8 * 1024 * 1024;
16791115Svbart@nginx.com             skcf->idle_timeout = 180 * 1000;
16801115Svbart@nginx.com             skcf->header_read_timeout = 30 * 1000;
16811115Svbart@nginx.com             skcf->body_read_timeout = 30 * 1000;
16821115Svbart@nginx.com             skcf->send_timeout = 30 * 1000;
16831115Svbart@nginx.com 
16841131Smax.romanov@nginx.com             skcf->websocket_conf.max_frame_size = 1024 * 1024;
16851131Smax.romanov@nginx.com             skcf->websocket_conf.read_timeout = 60 * 1000;
16861131Smax.romanov@nginx.com             skcf->websocket_conf.keepalive_interval = 30 * 1000;
16871131Smax.romanov@nginx.com 
16881115Svbart@nginx.com             if (http != NULL) {
16891115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
16901115Svbart@nginx.com                                           nxt_nitems(nxt_router_http_conf),
16911115Svbart@nginx.com                                           skcf);
16921115Svbart@nginx.com                 if (ret != NXT_OK) {
16931115Svbart@nginx.com                     nxt_alert(task, "http map error");
16941115Svbart@nginx.com                     goto fail;
16951115Svbart@nginx.com                 }
16961115Svbart@nginx.com             }
1697115Sigor@sysoev.ru 
16981131Smax.romanov@nginx.com             if (websocket != NULL) {
16991131Smax.romanov@nginx.com                 ret = nxt_conf_map_object(mp, websocket,
17001131Smax.romanov@nginx.com                                           nxt_router_websocket_conf,
17011131Smax.romanov@nginx.com                                           nxt_nitems(nxt_router_websocket_conf),
17021131Smax.romanov@nginx.com                                           &skcf->websocket_conf);
17031131Smax.romanov@nginx.com                 if (ret != NXT_OK) {
17041131Smax.romanov@nginx.com                     nxt_alert(task, "websocket map error");
17051131Smax.romanov@nginx.com                     goto fail;
17061131Smax.romanov@nginx.com                 }
17071131Smax.romanov@nginx.com             }
17081131Smax.romanov@nginx.com 
1709774Svbart@nginx.com #if (NXT_TLS)
17101115Svbart@nginx.com             value = nxt_conf_get_path(listener, &certificate_path);
17111115Svbart@nginx.com 
17121115Svbart@nginx.com             if (value != NULL) {
17131115Svbart@nginx.com                 nxt_conf_get_string(value, &name);
17141115Svbart@nginx.com 
17151115Svbart@nginx.com                 tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
17161115Svbart@nginx.com                 if (nxt_slow_path(tls == NULL)) {
17171115Svbart@nginx.com                     goto fail;
17181115Svbart@nginx.com                 }
17191115Svbart@nginx.com 
17201115Svbart@nginx.com                 tls->name = name;
17211115Svbart@nginx.com                 tls->conf = skcf;
17221115Svbart@nginx.com 
17231115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1724774Svbart@nginx.com             }
1725774Svbart@nginx.com #endif
1726774Svbart@nginx.com 
17271115Svbart@nginx.com             skcf->listen->handler = nxt_http_conn_init;
17281115Svbart@nginx.com             skcf->router_conf = tmcf->router_conf;
17291115Svbart@nginx.com             skcf->router_conf->count++;
17301115Svbart@nginx.com 
17311115Svbart@nginx.com             if (lscf.pass.length != 0) {
17321115Svbart@nginx.com                 skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass);
17331115Svbart@nginx.com 
17341115Svbart@nginx.com             /* COMPATIBILITY: listener application. */
17351115Svbart@nginx.com             } else if (lscf.application.length > 0) {
17361115Svbart@nginx.com                 skcf->pass = nxt_http_pass_application(task, tmcf,
17371115Svbart@nginx.com                                                        &lscf.application);
17381115Svbart@nginx.com             }
1739770Smax.romanov@nginx.com         }
1740115Sigor@sysoev.ru     }
174153Sigor@sysoev.ru 
1742630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1743630Svbart@nginx.com 
1744630Svbart@nginx.com     if (value != NULL) {
1745630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1746630Svbart@nginx.com 
1747630Svbart@nginx.com         access_log = router->access_log;
1748630Svbart@nginx.com 
1749630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1750630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1751630Svbart@nginx.com             access_log->count++;
1752630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1753630Svbart@nginx.com 
1754630Svbart@nginx.com         } else {
1755630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1756630Svbart@nginx.com                                     + path.length);
1757630Svbart@nginx.com             if (access_log == NULL) {
1758630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1759630Svbart@nginx.com                 goto fail;
1760630Svbart@nginx.com             }
1761630Svbart@nginx.com 
1762630Svbart@nginx.com             access_log->fd = -1;
1763630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1764630Svbart@nginx.com             access_log->count = 1;
1765630Svbart@nginx.com 
1766630Svbart@nginx.com             access_log->path.length = path.length;
1767630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1768630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1769630Svbart@nginx.com 
1770630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1771630Svbart@nginx.com         }
1772630Svbart@nginx.com 
1773630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1774630Svbart@nginx.com     }
1775630Svbart@nginx.com 
1776964Sigor@sysoev.ru     nxt_http_routes_resolve(task, tmcf);
1777964Sigor@sysoev.ru 
1778359Sigor@sysoev.ru     nxt_queue_add(&tmcf->deleting, &router->sockets);
1779359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1780198Sigor@sysoev.ru 
178153Sigor@sysoev.ru     return NXT_OK;
1782133Sigor@sysoev.ru 
1783133Sigor@sysoev.ru app_fail:
1784133Sigor@sysoev.ru 
1785133Sigor@sysoev.ru     nxt_free(app);
1786133Sigor@sysoev.ru 
1787133Sigor@sysoev.ru fail:
1788133Sigor@sysoev.ru 
1789141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1790141Smax.romanov@nginx.com 
1791141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1792133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
1793133Sigor@sysoev.ru         nxt_free(app);
1794141Smax.romanov@nginx.com 
1795141Smax.romanov@nginx.com     } nxt_queue_loop;
1796133Sigor@sysoev.ru 
1797133Sigor@sysoev.ru     return NXT_ERROR;
1798133Sigor@sysoev.ru }
1799133Sigor@sysoev.ru 
1800133Sigor@sysoev.ru 
1801*1183Svbart@nginx.com static nxt_int_t
1802*1183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
1803*1183Svbart@nginx.com     nxt_conf_value_t *conf)
1804*1183Svbart@nginx.com {
1805*1183Svbart@nginx.com     uint32_t          next, i;
1806*1183Svbart@nginx.com     nxt_mp_t          *mp;
1807*1183Svbart@nginx.com     nxt_str_t         *type, extension, str;
1808*1183Svbart@nginx.com     nxt_int_t         ret;
1809*1183Svbart@nginx.com     nxt_uint_t        exts;
1810*1183Svbart@nginx.com     nxt_conf_value_t  *mtypes_conf, *ext_conf, *value;
1811*1183Svbart@nginx.com 
1812*1183Svbart@nginx.com     static nxt_str_t  mtypes_path = nxt_string("/mime_types");
1813*1183Svbart@nginx.com 
1814*1183Svbart@nginx.com     mp = rtcf->mem_pool;
1815*1183Svbart@nginx.com 
1816*1183Svbart@nginx.com     ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
1817*1183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
1818*1183Svbart@nginx.com         return NXT_ERROR;
1819*1183Svbart@nginx.com     }
1820*1183Svbart@nginx.com 
1821*1183Svbart@nginx.com     if (conf == NULL) {
1822*1183Svbart@nginx.com         return NXT_OK;
1823*1183Svbart@nginx.com     }
1824*1183Svbart@nginx.com 
1825*1183Svbart@nginx.com     mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
1826*1183Svbart@nginx.com 
1827*1183Svbart@nginx.com     if (mtypes_conf != NULL) {
1828*1183Svbart@nginx.com         next = 0;
1829*1183Svbart@nginx.com 
1830*1183Svbart@nginx.com         for ( ;; ) {
1831*1183Svbart@nginx.com             ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
1832*1183Svbart@nginx.com 
1833*1183Svbart@nginx.com             if (ext_conf == NULL) {
1834*1183Svbart@nginx.com                 break;
1835*1183Svbart@nginx.com             }
1836*1183Svbart@nginx.com 
1837*1183Svbart@nginx.com             type = nxt_str_dup(mp, NULL, &str);
1838*1183Svbart@nginx.com             if (nxt_slow_path(type == NULL)) {
1839*1183Svbart@nginx.com                 return NXT_ERROR;
1840*1183Svbart@nginx.com             }
1841*1183Svbart@nginx.com 
1842*1183Svbart@nginx.com             if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
1843*1183Svbart@nginx.com                 nxt_conf_get_string(ext_conf, &str);
1844*1183Svbart@nginx.com 
1845*1183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
1846*1183Svbart@nginx.com                     return NXT_ERROR;
1847*1183Svbart@nginx.com                 }
1848*1183Svbart@nginx.com 
1849*1183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
1850*1183Svbart@nginx.com                                                       &extension, type);
1851*1183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
1852*1183Svbart@nginx.com                     return NXT_ERROR;
1853*1183Svbart@nginx.com                 }
1854*1183Svbart@nginx.com 
1855*1183Svbart@nginx.com                 continue;
1856*1183Svbart@nginx.com             }
1857*1183Svbart@nginx.com 
1858*1183Svbart@nginx.com             exts = nxt_conf_array_elements_count(ext_conf);
1859*1183Svbart@nginx.com 
1860*1183Svbart@nginx.com             for (i = 0; i < exts; i++) {
1861*1183Svbart@nginx.com                 value = nxt_conf_get_array_element(ext_conf, i);
1862*1183Svbart@nginx.com 
1863*1183Svbart@nginx.com                 nxt_conf_get_string(value, &str);
1864*1183Svbart@nginx.com 
1865*1183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
1866*1183Svbart@nginx.com                     return NXT_ERROR;
1867*1183Svbart@nginx.com                 }
1868*1183Svbart@nginx.com 
1869*1183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
1870*1183Svbart@nginx.com                                                       &extension, type);
1871*1183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
1872*1183Svbart@nginx.com                     return NXT_ERROR;
1873*1183Svbart@nginx.com                 }
1874*1183Svbart@nginx.com             }
1875*1183Svbart@nginx.com         }
1876*1183Svbart@nginx.com     }
1877*1183Svbart@nginx.com 
1878*1183Svbart@nginx.com     return NXT_OK;
1879*1183Svbart@nginx.com }
1880*1183Svbart@nginx.com 
1881*1183Svbart@nginx.com 
1882133Sigor@sysoev.ru static nxt_app_t *
1883133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1884133Sigor@sysoev.ru {
1885141Smax.romanov@nginx.com     nxt_app_t  *app;
1886141Smax.romanov@nginx.com 
1887141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1888133Sigor@sysoev.ru 
1889133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1890133Sigor@sysoev.ru             return app;
1891133Sigor@sysoev.ru         }
1892141Smax.romanov@nginx.com 
1893141Smax.romanov@nginx.com     } nxt_queue_loop;
1894133Sigor@sysoev.ru 
1895133Sigor@sysoev.ru     return NULL;
1896133Sigor@sysoev.ru }
1897133Sigor@sysoev.ru 
1898133Sigor@sysoev.ru 
1899964Sigor@sysoev.ru nxt_app_t *
1900133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name)
1901133Sigor@sysoev.ru {
1902133Sigor@sysoev.ru     nxt_app_t  *app;
1903133Sigor@sysoev.ru 
1904133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1905133Sigor@sysoev.ru 
1906133Sigor@sysoev.ru     if (app == NULL) {
1907134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1908133Sigor@sysoev.ru     }
1909133Sigor@sysoev.ru 
1910133Sigor@sysoev.ru     return app;
191153Sigor@sysoev.ru }
191253Sigor@sysoev.ru 
191353Sigor@sysoev.ru 
191453Sigor@sysoev.ru static nxt_socket_conf_t *
1915359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1916359Sigor@sysoev.ru     nxt_str_t *name)
191753Sigor@sysoev.ru {
1918359Sigor@sysoev.ru     size_t               size;
1919359Sigor@sysoev.ru     nxt_int_t            ret;
1920359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1921359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1922359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1923359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1924359Sigor@sysoev.ru 
1925359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1926359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1927564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1928359Sigor@sysoev.ru         return NULL;
1929359Sigor@sysoev.ru     }
1930359Sigor@sysoev.ru 
1931359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1932359Sigor@sysoev.ru 
1933359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1934493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1935359Sigor@sysoev.ru 
1936591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1937163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
193853Sigor@sysoev.ru         return NULL;
193953Sigor@sysoev.ru     }
194053Sigor@sysoev.ru 
1941359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1942359Sigor@sysoev.ru 
1943359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1944359Sigor@sysoev.ru 
1945359Sigor@sysoev.ru     if (ret != NXT_OK) {
1946359Sigor@sysoev.ru 
1947359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1948359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1949359Sigor@sysoev.ru             return NULL;
1950359Sigor@sysoev.ru         }
1951359Sigor@sysoev.ru 
1952359Sigor@sysoev.ru         skcf->listen = ls;
1953359Sigor@sysoev.ru 
1954359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1955359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1956359Sigor@sysoev.ru 
1957359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1958359Sigor@sysoev.ru 
1959359Sigor@sysoev.ru         ls->socket = -1;
1960359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
1961359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
1962359Sigor@sysoev.ru         ls->read_after_accept = 1;
1963359Sigor@sysoev.ru     }
1964359Sigor@sysoev.ru 
1965359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
1966359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1967359Sigor@sysoev.ru     case AF_UNIX:
1968359Sigor@sysoev.ru         wildcard = 0;
1969359Sigor@sysoev.ru         break;
1970359Sigor@sysoev.ru #endif
1971359Sigor@sysoev.ru #if (NXT_INET6)
1972359Sigor@sysoev.ru     case AF_INET6:
1973359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
1974359Sigor@sysoev.ru         break;
1975359Sigor@sysoev.ru #endif
1976359Sigor@sysoev.ru     case AF_INET:
1977359Sigor@sysoev.ru     default:
1978359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
1979359Sigor@sysoev.ru         break;
1980359Sigor@sysoev.ru     }
1981359Sigor@sysoev.ru 
1982359Sigor@sysoev.ru     if (!wildcard) {
1983591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
1984359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
1985359Sigor@sysoev.ru             return NULL;
1986359Sigor@sysoev.ru         }
1987359Sigor@sysoev.ru 
1988359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
1989359Sigor@sysoev.ru     }
1990163Smax.romanov@nginx.com 
1991163Smax.romanov@nginx.com     return skcf;
199253Sigor@sysoev.ru }
199353Sigor@sysoev.ru 
199453Sigor@sysoev.ru 
1995359Sigor@sysoev.ru static nxt_int_t
1996359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
1997359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
199853Sigor@sysoev.ru {
1999359Sigor@sysoev.ru     nxt_router_t       *router;
2000359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
2001359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
2002359Sigor@sysoev.ru 
2003591Sigor@sysoev.ru     router = tmcf->router_conf->router;
2004359Sigor@sysoev.ru 
2005359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
2006359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
2007359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
200853Sigor@sysoev.ru     {
2009359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2010359Sigor@sysoev.ru 
2011359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2012359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
2013359Sigor@sysoev.ru 
2014359Sigor@sysoev.ru             nxt_queue_remove(qlk);
2015359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->keeping, qlk);
2016359Sigor@sysoev.ru 
2017359Sigor@sysoev.ru             nxt_queue_insert_tail(&tmcf->updating, &nskcf->link);
2018359Sigor@sysoev.ru 
2019359Sigor@sysoev.ru             return NXT_OK;
202053Sigor@sysoev.ru         }
202153Sigor@sysoev.ru     }
202253Sigor@sysoev.ru 
2023359Sigor@sysoev.ru     nxt_queue_insert_tail(&tmcf->pending, &nskcf->link);
2024359Sigor@sysoev.ru 
2025359Sigor@sysoev.ru     return NXT_DECLINED;
202653Sigor@sysoev.ru }
202753Sigor@sysoev.ru 
202853Sigor@sysoev.ru 
2029198Sigor@sysoev.ru static void
2030198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2031198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2032198Sigor@sysoev.ru {
2033358Sigor@sysoev.ru     size_t            size;
2034198Sigor@sysoev.ru     uint32_t          stream;
2035648Svbart@nginx.com     nxt_int_t         ret;
2036198Sigor@sysoev.ru     nxt_buf_t         *b;
2037198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
2038198Sigor@sysoev.ru     nxt_runtime_t     *rt;
2039198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
2040198Sigor@sysoev.ru 
2041198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2042198Sigor@sysoev.ru     if (rpc == NULL) {
2043198Sigor@sysoev.ru         goto fail;
2044198Sigor@sysoev.ru     }
2045198Sigor@sysoev.ru 
2046198Sigor@sysoev.ru     rpc->socket_conf = skcf;
2047198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
2048198Sigor@sysoev.ru 
2049359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
2050358Sigor@sysoev.ru 
2051358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2052198Sigor@sysoev.ru     if (b == NULL) {
2053198Sigor@sysoev.ru         goto fail;
2054198Sigor@sysoev.ru     }
2055198Sigor@sysoev.ru 
2056359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2057198Sigor@sysoev.ru 
2058198Sigor@sysoev.ru     rt = task->thread->runtime;
2059240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2060198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2061198Sigor@sysoev.ru 
2062198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
2063198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
2064198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
2065198Sigor@sysoev.ru                                            main_port->pid, rpc);
2066645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
2067198Sigor@sysoev.ru         goto fail;
2068198Sigor@sysoev.ru     }
2069198Sigor@sysoev.ru 
2070648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2071648Svbart@nginx.com                                 stream, router_port->id, b);
2072648Svbart@nginx.com 
2073648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2074648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2075648Svbart@nginx.com         goto fail;
2076648Svbart@nginx.com     }
2077198Sigor@sysoev.ru 
2078198Sigor@sysoev.ru     return;
2079198Sigor@sysoev.ru 
2080198Sigor@sysoev.ru fail:
2081198Sigor@sysoev.ru 
2082198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
2083198Sigor@sysoev.ru }
2084198Sigor@sysoev.ru 
2085198Sigor@sysoev.ru 
2086198Sigor@sysoev.ru static void
2087198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2088198Sigor@sysoev.ru     void *data)
208953Sigor@sysoev.ru {
2090359Sigor@sysoev.ru     nxt_int_t         ret;
2091359Sigor@sysoev.ru     nxt_socket_t      s;
2092359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
209353Sigor@sysoev.ru 
2094198Sigor@sysoev.ru     rpc = data;
2095198Sigor@sysoev.ru 
2096198Sigor@sysoev.ru     s = msg->fd;
2097198Sigor@sysoev.ru 
2098198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
2099198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2100198Sigor@sysoev.ru         goto fail;
210153Sigor@sysoev.ru     }
210253Sigor@sysoev.ru 
2103359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2104198Sigor@sysoev.ru 
2105198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2106198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2107198Sigor@sysoev.ru         goto fail;
2108198Sigor@sysoev.ru     }
2109198Sigor@sysoev.ru 
2110359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
2111198Sigor@sysoev.ru 
2112198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2113198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2114198Sigor@sysoev.ru 
2115198Sigor@sysoev.ru     return;
2116148Sigor@sysoev.ru 
2117148Sigor@sysoev.ru fail:
2118148Sigor@sysoev.ru 
2119148Sigor@sysoev.ru     nxt_socket_close(task, s);
2120148Sigor@sysoev.ru 
2121198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2122198Sigor@sysoev.ru }
2123198Sigor@sysoev.ru 
2124198Sigor@sysoev.ru 
2125198Sigor@sysoev.ru static void
2126198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2127198Sigor@sysoev.ru     void *data)
2128198Sigor@sysoev.ru {
2129955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2130955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2131955Svbart@nginx.com 
2132955Svbart@nginx.com     rpc = data;
2133955Svbart@nginx.com     tmcf = rpc->temp_conf;
2134955Svbart@nginx.com 
2135955Svbart@nginx.com #if 0
2136198Sigor@sysoev.ru     u_char                  *p;
2137198Sigor@sysoev.ru     size_t                  size;
2138198Sigor@sysoev.ru     uint8_t                 error;
2139198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2140198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2141198Sigor@sysoev.ru 
2142198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2143198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2144198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2145198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2146198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2147198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2148198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2149198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2150198Sigor@sysoev.ru     };
2151198Sigor@sysoev.ru 
2152359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2153352Smax.romanov@nginx.com 
2154352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2155352Smax.romanov@nginx.com 
2156551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2157551Smax.romanov@nginx.com         return;
2158551Smax.romanov@nginx.com     }
2159352Smax.romanov@nginx.com 
2160198Sigor@sysoev.ru     p = in->mem.pos;
2161198Sigor@sysoev.ru 
2162198Sigor@sysoev.ru     error = *p++;
2163198Sigor@sysoev.ru 
2164703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2165703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2166198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2167198Sigor@sysoev.ru 
2168198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2169198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2170198Sigor@sysoev.ru         return;
2171198Sigor@sysoev.ru     }
2172198Sigor@sysoev.ru 
2173198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2174198Sigor@sysoev.ru                         "listen socket error: "
2175198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2176493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2177198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2178198Sigor@sysoev.ru 
2179198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2180955Svbart@nginx.com #endif
2181198Sigor@sysoev.ru 
2182198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
218353Sigor@sysoev.ru }
218453Sigor@sysoev.ru 
218553Sigor@sysoev.ru 
2186774Svbart@nginx.com #if (NXT_TLS)
2187774Svbart@nginx.com 
2188774Svbart@nginx.com static void
2189774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2190774Svbart@nginx.com     nxt_router_tlssock_t *tls)
2191774Svbart@nginx.com {
2192774Svbart@nginx.com     nxt_socket_rpc_t  *rpc;
2193774Svbart@nginx.com 
2194774Svbart@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2195774Svbart@nginx.com     if (rpc == NULL) {
2196774Svbart@nginx.com         nxt_router_conf_error(task, tmcf);
2197774Svbart@nginx.com         return;
2198774Svbart@nginx.com     }
2199774Svbart@nginx.com 
2200774Svbart@nginx.com     rpc->socket_conf = tls->conf;
2201774Svbart@nginx.com     rpc->temp_conf = tmcf;
2202774Svbart@nginx.com 
2203774Svbart@nginx.com     nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
2204774Svbart@nginx.com                        nxt_router_tls_rpc_handler, rpc);
2205774Svbart@nginx.com }
2206774Svbart@nginx.com 
2207774Svbart@nginx.com 
2208774Svbart@nginx.com static void
2209774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2210774Svbart@nginx.com     void *data)
2211774Svbart@nginx.com {
2212774Svbart@nginx.com     nxt_mp_t               *mp;
2213774Svbart@nginx.com     nxt_int_t              ret;
2214774Svbart@nginx.com     nxt_tls_conf_t         *tlscf;
2215774Svbart@nginx.com     nxt_socket_rpc_t       *rpc;
2216774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf;
2217774Svbart@nginx.com 
2218774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2219774Svbart@nginx.com 
2220774Svbart@nginx.com     rpc = data;
2221774Svbart@nginx.com     tmcf = rpc->temp_conf;
2222774Svbart@nginx.com 
2223774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2224774Svbart@nginx.com         goto fail;
2225774Svbart@nginx.com     }
2226774Svbart@nginx.com 
2227774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2228774Svbart@nginx.com 
2229774Svbart@nginx.com     tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2230774Svbart@nginx.com     if (nxt_slow_path(tlscf == NULL)) {
2231774Svbart@nginx.com         goto fail;
2232774Svbart@nginx.com     }
2233774Svbart@nginx.com 
2234774Svbart@nginx.com     tlscf->chain_file = msg->fd;
2235774Svbart@nginx.com 
2236774Svbart@nginx.com     ret = task->thread->runtime->tls->server_init(task, tlscf);
2237774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2238774Svbart@nginx.com         goto fail;
2239774Svbart@nginx.com     }
2240774Svbart@nginx.com 
2241774Svbart@nginx.com     rpc->socket_conf->tls = tlscf;
2242774Svbart@nginx.com 
2243774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2244774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2245774Svbart@nginx.com     return;
2246774Svbart@nginx.com 
2247774Svbart@nginx.com fail:
2248774Svbart@nginx.com 
2249774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2250774Svbart@nginx.com }
2251774Svbart@nginx.com 
2252774Svbart@nginx.com #endif
2253774Svbart@nginx.com 
2254774Svbart@nginx.com 
2255507Smax.romanov@nginx.com static void
2256507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2257507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2258507Smax.romanov@nginx.com {
2259507Smax.romanov@nginx.com     size_t         size;
2260507Smax.romanov@nginx.com     uint32_t       stream;
2261648Svbart@nginx.com     nxt_int_t      ret;
2262507Smax.romanov@nginx.com     nxt_buf_t      *b;
2263507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
2264507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2265507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2266507Smax.romanov@nginx.com 
2267507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2268507Smax.romanov@nginx.com     if (rpc == NULL) {
2269507Smax.romanov@nginx.com         goto fail;
2270507Smax.romanov@nginx.com     }
2271507Smax.romanov@nginx.com 
2272507Smax.romanov@nginx.com     rpc->app = app;
2273507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2274507Smax.romanov@nginx.com 
2275507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
2276507Smax.romanov@nginx.com 
2277507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
2278507Smax.romanov@nginx.com 
2279507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2280507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2281507Smax.romanov@nginx.com         goto fail;
2282507Smax.romanov@nginx.com     }
2283507Smax.romanov@nginx.com 
2284507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
2285507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
2286507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2287507Smax.romanov@nginx.com 
2288507Smax.romanov@nginx.com     rt = task->thread->runtime;
2289507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2290507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2291507Smax.romanov@nginx.com 
2292507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2293507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
2294507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
2295507Smax.romanov@nginx.com                                            -1, rpc);
2296507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2297507Smax.romanov@nginx.com         goto fail;
2298507Smax.romanov@nginx.com     }
2299507Smax.romanov@nginx.com 
2300648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1,
2301648Svbart@nginx.com                                 stream, router_port->id, b);
2302648Svbart@nginx.com 
2303648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2304648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2305648Svbart@nginx.com         goto fail;
2306648Svbart@nginx.com     }
2307648Svbart@nginx.com 
2308507Smax.romanov@nginx.com     app->pending_processes++;
2309507Smax.romanov@nginx.com 
2310507Smax.romanov@nginx.com     return;
2311507Smax.romanov@nginx.com 
2312507Smax.romanov@nginx.com fail:
2313507Smax.romanov@nginx.com 
2314507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2315507Smax.romanov@nginx.com }
2316507Smax.romanov@nginx.com 
2317507Smax.romanov@nginx.com 
2318507Smax.romanov@nginx.com static void
2319507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2320507Smax.romanov@nginx.com     void *data)
2321507Smax.romanov@nginx.com {
2322507Smax.romanov@nginx.com     nxt_app_t           *app;
2323507Smax.romanov@nginx.com     nxt_port_t          *port;
2324507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2325507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2326507Smax.romanov@nginx.com 
2327507Smax.romanov@nginx.com     rpc = data;
2328507Smax.romanov@nginx.com     app = rpc->app;
2329507Smax.romanov@nginx.com 
2330507Smax.romanov@nginx.com     port = msg->u.new_port;
2331507Smax.romanov@nginx.com     port->app = app;
2332507Smax.romanov@nginx.com 
2333507Smax.romanov@nginx.com     app->pending_processes--;
2334507Smax.romanov@nginx.com     app->processes++;
2335507Smax.romanov@nginx.com     app->idle_processes++;
2336507Smax.romanov@nginx.com 
2337507Smax.romanov@nginx.com     engine = task->thread->engine;
2338507Smax.romanov@nginx.com 
2339507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2340507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2341507Smax.romanov@nginx.com 
2342507Smax.romanov@nginx.com     port->idle_start = 0;
2343507Smax.romanov@nginx.com 
2344507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2345507Smax.romanov@nginx.com 
2346507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2347507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2348507Smax.romanov@nginx.com }
2349507Smax.romanov@nginx.com 
2350507Smax.romanov@nginx.com 
2351507Smax.romanov@nginx.com static void
2352507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2353507Smax.romanov@nginx.com     void *data)
2354507Smax.romanov@nginx.com {
2355507Smax.romanov@nginx.com     nxt_app_t               *app;
2356507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2357507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2358507Smax.romanov@nginx.com 
2359507Smax.romanov@nginx.com     rpc = data;
2360507Smax.romanov@nginx.com     app = rpc->app;
2361507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2362507Smax.romanov@nginx.com 
2363507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2364507Smax.romanov@nginx.com             &app->name);
2365507Smax.romanov@nginx.com 
2366507Smax.romanov@nginx.com     app->pending_processes--;
2367507Smax.romanov@nginx.com 
2368507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2369507Smax.romanov@nginx.com }
2370507Smax.romanov@nginx.com 
2371507Smax.romanov@nginx.com 
237253Sigor@sysoev.ru static nxt_int_t
237353Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
237453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
237553Sigor@sysoev.ru {
237653Sigor@sysoev.ru     nxt_int_t                 ret;
237753Sigor@sysoev.ru     nxt_uint_t                n, threads;
237853Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
237953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
238053Sigor@sysoev.ru 
2381591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
238253Sigor@sysoev.ru 
238353Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
238453Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
238553Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
238653Sigor@sysoev.ru         return NXT_ERROR;
238753Sigor@sysoev.ru     }
238853Sigor@sysoev.ru 
238953Sigor@sysoev.ru     n = 0;
239053Sigor@sysoev.ru 
239153Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
239253Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
239353Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
239453Sigor@sysoev.ru     {
239553Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
239653Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
239753Sigor@sysoev.ru             return NXT_ERROR;
239853Sigor@sysoev.ru         }
239953Sigor@sysoev.ru 
2400115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
240153Sigor@sysoev.ru 
240253Sigor@sysoev.ru         if (n < threads) {
2403315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2404115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
240553Sigor@sysoev.ru 
240653Sigor@sysoev.ru         } else {
2407315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2408115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
240953Sigor@sysoev.ru         }
241053Sigor@sysoev.ru 
241153Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
241253Sigor@sysoev.ru             return ret;
241353Sigor@sysoev.ru         }
241453Sigor@sysoev.ru 
241553Sigor@sysoev.ru         n++;
241653Sigor@sysoev.ru     }
241753Sigor@sysoev.ru 
241853Sigor@sysoev.ru     tmcf->new_threads = n;
241953Sigor@sysoev.ru 
242053Sigor@sysoev.ru     while (n < threads) {
242153Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
242253Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
242353Sigor@sysoev.ru             return NXT_ERROR;
242453Sigor@sysoev.ru         }
242553Sigor@sysoev.ru 
2426315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2427315Sigor@sysoev.ru 
242853Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
242953Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
243053Sigor@sysoev.ru             return NXT_ERROR;
243153Sigor@sysoev.ru         }
243253Sigor@sysoev.ru 
2433115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
243453Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
243553Sigor@sysoev.ru             return ret;
243653Sigor@sysoev.ru         }
243753Sigor@sysoev.ru 
243853Sigor@sysoev.ru         n++;
243953Sigor@sysoev.ru     }
244053Sigor@sysoev.ru 
244153Sigor@sysoev.ru     return NXT_OK;
244253Sigor@sysoev.ru }
244353Sigor@sysoev.ru 
244453Sigor@sysoev.ru 
244553Sigor@sysoev.ru static nxt_int_t
2446115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2447115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
244853Sigor@sysoev.ru {
2449359Sigor@sysoev.ru     nxt_int_t  ret;
245053Sigor@sysoev.ru 
2451154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2452154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2453115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2454115Sigor@sysoev.ru         return ret;
2455115Sigor@sysoev.ru     }
2456115Sigor@sysoev.ru 
2457154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2458154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
245953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
246053Sigor@sysoev.ru         return ret;
246153Sigor@sysoev.ru     }
246253Sigor@sysoev.ru 
2463115Sigor@sysoev.ru     return ret;
246453Sigor@sysoev.ru }
246553Sigor@sysoev.ru 
246653Sigor@sysoev.ru 
246753Sigor@sysoev.ru static nxt_int_t
2468115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2469115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
247053Sigor@sysoev.ru {
2471359Sigor@sysoev.ru     nxt_int_t  ret;
247253Sigor@sysoev.ru 
2473154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating,
2474154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
247553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
247653Sigor@sysoev.ru         return ret;
247753Sigor@sysoev.ru     }
247853Sigor@sysoev.ru 
2479154Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating,
2480154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
248153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
248253Sigor@sysoev.ru         return ret;
248353Sigor@sysoev.ru     }
248453Sigor@sysoev.ru 
2485139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
2486115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2487115Sigor@sysoev.ru         return ret;
2488115Sigor@sysoev.ru     }
2489115Sigor@sysoev.ru 
2490115Sigor@sysoev.ru     return ret;
249153Sigor@sysoev.ru }
249253Sigor@sysoev.ru 
249353Sigor@sysoev.ru 
249453Sigor@sysoev.ru static nxt_int_t
2495115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2496115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
249753Sigor@sysoev.ru {
249853Sigor@sysoev.ru     nxt_int_t  ret;
249953Sigor@sysoev.ru 
2500313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2501313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2502313Sigor@sysoev.ru         return ret;
2503313Sigor@sysoev.ru     }
2504313Sigor@sysoev.ru 
2505139Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating);
250653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
250753Sigor@sysoev.ru         return ret;
250853Sigor@sysoev.ru     }
250953Sigor@sysoev.ru 
2510139Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting);
251153Sigor@sysoev.ru }
251253Sigor@sysoev.ru 
251353Sigor@sysoev.ru 
251453Sigor@sysoev.ru static nxt_int_t
2515154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2516154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
251753Sigor@sysoev.ru     nxt_work_handler_t handler)
251853Sigor@sysoev.ru {
2519153Sigor@sysoev.ru     nxt_joint_job_t          *job;
252053Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2521155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
252253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
252353Sigor@sysoev.ru 
252453Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
252553Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
252653Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
252753Sigor@sysoev.ru     {
2528154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2529153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2530139Sigor@sysoev.ru             return NXT_ERROR;
2531139Sigor@sysoev.ru         }
2532139Sigor@sysoev.ru 
2533154Sigor@sysoev.ru         job->work.next = recf->jobs;
2534154Sigor@sysoev.ru         recf->jobs = &job->work;
2535154Sigor@sysoev.ru 
2536153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2537153Sigor@sysoev.ru         job->work.handler = handler;
2538153Sigor@sysoev.ru         job->work.task = &job->task;
2539153Sigor@sysoev.ru         job->work.obj = job;
2540153Sigor@sysoev.ru         job->tmcf = tmcf;
254153Sigor@sysoev.ru 
2542154Sigor@sysoev.ru         tmcf->count++;
2543154Sigor@sysoev.ru 
2544591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2545154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
254653Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
254753Sigor@sysoev.ru             return NXT_ERROR;
254853Sigor@sysoev.ru         }
254953Sigor@sysoev.ru 
2550153Sigor@sysoev.ru         job->work.data = joint;
255153Sigor@sysoev.ru 
255253Sigor@sysoev.ru         joint->count = 1;
2553155Sigor@sysoev.ru 
2554155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2555155Sigor@sysoev.ru         skcf->count++;
2556155Sigor@sysoev.ru         joint->socket_conf = skcf;
2557155Sigor@sysoev.ru 
255888Smax.romanov@nginx.com         joint->engine = recf->engine;
255953Sigor@sysoev.ru     }
256053Sigor@sysoev.ru 
256120Sigor@sysoev.ru     return NXT_OK;
256220Sigor@sysoev.ru }
256320Sigor@sysoev.ru 
256420Sigor@sysoev.ru 
256520Sigor@sysoev.ru static nxt_int_t
2566313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2567313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2568313Sigor@sysoev.ru {
2569313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2570313Sigor@sysoev.ru 
2571313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2572313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2573313Sigor@sysoev.ru         return NXT_ERROR;
2574313Sigor@sysoev.ru     }
2575313Sigor@sysoev.ru 
2576313Sigor@sysoev.ru     job->work.next = recf->jobs;
2577313Sigor@sysoev.ru     recf->jobs = &job->work;
2578313Sigor@sysoev.ru 
2579313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2580313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2581313Sigor@sysoev.ru     job->work.task = &job->task;
2582313Sigor@sysoev.ru     job->work.obj = NULL;
2583313Sigor@sysoev.ru     job->work.data = NULL;
2584313Sigor@sysoev.ru     job->tmcf = NULL;
2585313Sigor@sysoev.ru 
2586313Sigor@sysoev.ru     return NXT_OK;
2587313Sigor@sysoev.ru }
2588313Sigor@sysoev.ru 
2589313Sigor@sysoev.ru 
2590313Sigor@sysoev.ru static nxt_int_t
2591139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2592139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
259320Sigor@sysoev.ru {
2594153Sigor@sysoev.ru     nxt_joint_job_t   *job;
259553Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
259620Sigor@sysoev.ru 
259753Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
259853Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
259953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
260053Sigor@sysoev.ru     {
2601154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2602153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2603139Sigor@sysoev.ru             return NXT_ERROR;
2604139Sigor@sysoev.ru         }
2605139Sigor@sysoev.ru 
2606154Sigor@sysoev.ru         job->work.next = recf->jobs;
2607154Sigor@sysoev.ru         recf->jobs = &job->work;
2608154Sigor@sysoev.ru 
2609153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2610153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2611153Sigor@sysoev.ru         job->work.task = &job->task;
2612153Sigor@sysoev.ru         job->work.obj = job;
2613153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2614153Sigor@sysoev.ru         job->tmcf = tmcf;
2615154Sigor@sysoev.ru 
2616154Sigor@sysoev.ru         tmcf->count++;
261720Sigor@sysoev.ru     }
261820Sigor@sysoev.ru 
261953Sigor@sysoev.ru     return NXT_OK;
262053Sigor@sysoev.ru }
262120Sigor@sysoev.ru 
262220Sigor@sysoev.ru 
262353Sigor@sysoev.ru static nxt_int_t
262453Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
262553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
262653Sigor@sysoev.ru {
262753Sigor@sysoev.ru     nxt_int_t                 ret;
262853Sigor@sysoev.ru     nxt_uint_t                i, threads;
262953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
263020Sigor@sysoev.ru 
263153Sigor@sysoev.ru     recf = tmcf->engines->elts;
2632591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
263320Sigor@sysoev.ru 
263453Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
263553Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
263653Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
263753Sigor@sysoev.ru             return ret;
263853Sigor@sysoev.ru         }
263920Sigor@sysoev.ru     }
264020Sigor@sysoev.ru 
264120Sigor@sysoev.ru     return NXT_OK;
264220Sigor@sysoev.ru }
264353Sigor@sysoev.ru 
264453Sigor@sysoev.ru 
264553Sigor@sysoev.ru static nxt_int_t
264653Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
264753Sigor@sysoev.ru     nxt_event_engine_t *engine)
264853Sigor@sysoev.ru {
264953Sigor@sysoev.ru     nxt_int_t            ret;
265053Sigor@sysoev.ru     nxt_thread_link_t    *link;
265153Sigor@sysoev.ru     nxt_thread_handle_t  handle;
265253Sigor@sysoev.ru 
265353Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
265453Sigor@sysoev.ru 
265553Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
265653Sigor@sysoev.ru         return NXT_ERROR;
265753Sigor@sysoev.ru     }
265853Sigor@sysoev.ru 
265953Sigor@sysoev.ru     link->start = nxt_router_thread_start;
266053Sigor@sysoev.ru     link->engine = engine;
266153Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
266253Sigor@sysoev.ru     link->work.task = task;
266353Sigor@sysoev.ru     link->work.data = link;
266453Sigor@sysoev.ru 
266553Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
266653Sigor@sysoev.ru 
266753Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
266853Sigor@sysoev.ru 
266953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
267053Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
267153Sigor@sysoev.ru     }
267253Sigor@sysoev.ru 
267353Sigor@sysoev.ru     return ret;
267453Sigor@sysoev.ru }
267553Sigor@sysoev.ru 
267653Sigor@sysoev.ru 
267753Sigor@sysoev.ru static void
2678343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2679343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2680133Sigor@sysoev.ru {
2681507Smax.romanov@nginx.com     nxt_app_t  *app;
2682141Smax.romanov@nginx.com 
2683141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2684133Sigor@sysoev.ru 
2685753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2686343Smax.romanov@nginx.com 
2687141Smax.romanov@nginx.com     } nxt_queue_loop;
2688133Sigor@sysoev.ru 
2689133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2690133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2691133Sigor@sysoev.ru }
2692133Sigor@sysoev.ru 
2693133Sigor@sysoev.ru 
2694133Sigor@sysoev.ru static void
2695315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
269653Sigor@sysoev.ru {
269753Sigor@sysoev.ru     nxt_uint_t                n;
2698315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
269953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
270053Sigor@sysoev.ru 
270153Sigor@sysoev.ru     recf = tmcf->engines->elts;
270253Sigor@sysoev.ru 
270353Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2704315Sigor@sysoev.ru         engine = recf->engine;
2705315Sigor@sysoev.ru 
2706315Sigor@sysoev.ru         switch (recf->action) {
2707315Sigor@sysoev.ru 
2708315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2709315Sigor@sysoev.ru             break;
2710315Sigor@sysoev.ru 
2711315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2712315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2713315Sigor@sysoev.ru             break;
2714315Sigor@sysoev.ru 
2715315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2716315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2717315Sigor@sysoev.ru             break;
2718315Sigor@sysoev.ru         }
2719315Sigor@sysoev.ru 
2720316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2721316Sigor@sysoev.ru 
272253Sigor@sysoev.ru         recf++;
272353Sigor@sysoev.ru     }
272453Sigor@sysoev.ru }
272553Sigor@sysoev.ru 
272653Sigor@sysoev.ru 
272753Sigor@sysoev.ru static void
2728315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
272953Sigor@sysoev.ru {
2730154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2731154Sigor@sysoev.ru 
2732315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2733154Sigor@sysoev.ru         next = work->next;
2734154Sigor@sysoev.ru         work->next = NULL;
2735154Sigor@sysoev.ru 
2736315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
273753Sigor@sysoev.ru     }
273853Sigor@sysoev.ru }
273953Sigor@sysoev.ru 
274053Sigor@sysoev.ru 
2741320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
2742616Smax.romanov@nginx.com     .rpc_error = nxt_port_rpc_handler,
2743616Smax.romanov@nginx.com     .mmap      = nxt_port_mmap_handler,
2744616Smax.romanov@nginx.com     .data      = nxt_port_rpc_handler,
274588Smax.romanov@nginx.com };
274688Smax.romanov@nginx.com 
274788Smax.romanov@nginx.com 
274888Smax.romanov@nginx.com static void
274953Sigor@sysoev.ru nxt_router_thread_start(void *data)
275053Sigor@sysoev.ru {
2751141Smax.romanov@nginx.com     nxt_int_t           ret;
2752141Smax.romanov@nginx.com     nxt_port_t          *port;
275388Smax.romanov@nginx.com     nxt_task_t          *task;
275453Sigor@sysoev.ru     nxt_thread_t        *thread;
275553Sigor@sysoev.ru     nxt_thread_link_t   *link;
275653Sigor@sysoev.ru     nxt_event_engine_t  *engine;
275753Sigor@sysoev.ru 
275853Sigor@sysoev.ru     link = data;
275953Sigor@sysoev.ru     engine = link->engine;
276088Smax.romanov@nginx.com     task = &engine->task;
276153Sigor@sysoev.ru 
276253Sigor@sysoev.ru     thread = nxt_thread();
276353Sigor@sysoev.ru 
2764165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2765165Smax.romanov@nginx.com 
276653Sigor@sysoev.ru     /* STUB */
276753Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
276853Sigor@sysoev.ru 
276953Sigor@sysoev.ru     engine->task.thread = thread;
277053Sigor@sysoev.ru     engine->task.log = thread->log;
277153Sigor@sysoev.ru     thread->engine = engine;
277263Sigor@sysoev.ru     thread->task = &engine->task;
2773326Svbart@nginx.com #if 0
277453Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2775326Svbart@nginx.com #endif
277653Sigor@sysoev.ru 
277763Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2778337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2779337Sigor@sysoev.ru         return;
2780337Sigor@sysoev.ru     }
278153Sigor@sysoev.ru 
2782197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2783197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2784141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2785141Smax.romanov@nginx.com         return;
2786141Smax.romanov@nginx.com     }
2787141Smax.romanov@nginx.com 
2788141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2789141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2790343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2791141Smax.romanov@nginx.com         return;
2792141Smax.romanov@nginx.com     }
2793141Smax.romanov@nginx.com 
2794141Smax.romanov@nginx.com     engine->port = port;
2795141Smax.romanov@nginx.com 
2796320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2797141Smax.romanov@nginx.com 
279853Sigor@sysoev.ru     nxt_event_engine_start(engine);
279953Sigor@sysoev.ru }
280053Sigor@sysoev.ru 
280153Sigor@sysoev.ru 
280253Sigor@sysoev.ru static void
280353Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
280453Sigor@sysoev.ru {
2805153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2806359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2807359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
280853Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2809359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
281053Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
281153Sigor@sysoev.ru 
2812153Sigor@sysoev.ru     job = obj;
281353Sigor@sysoev.ru     joint = data;
281453Sigor@sysoev.ru 
2815159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2816159Sigor@sysoev.ru 
2817359Sigor@sysoev.ru     skcf = joint->socket_conf;
2818359Sigor@sysoev.ru     ls = skcf->listen;
2819359Sigor@sysoev.ru 
2820359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2821359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2822359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
282353Sigor@sysoev.ru         return;
282453Sigor@sysoev.ru     }
282553Sigor@sysoev.ru 
2826359Sigor@sysoev.ru     lev->socket.data = joint;
2827359Sigor@sysoev.ru 
2828359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2829359Sigor@sysoev.ru 
2830359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2831359Sigor@sysoev.ru     ls->count++;
2832359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2833139Sigor@sysoev.ru 
2834153Sigor@sysoev.ru     job->work.next = NULL;
2835153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2836153Sigor@sysoev.ru 
2837153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
283853Sigor@sysoev.ru }
283953Sigor@sysoev.ru 
284053Sigor@sysoev.ru 
284153Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
284253Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
284353Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
284453Sigor@sysoev.ru {
2845115Sigor@sysoev.ru     nxt_socket_t        fd;
2846115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2847359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2848359Sigor@sysoev.ru 
2849359Sigor@sysoev.ru     fd = skcf->listen->socket;
285053Sigor@sysoev.ru 
2851115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2852115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2853115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
285453Sigor@sysoev.ru     {
2855359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2856359Sigor@sysoev.ru 
2857359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2858359Sigor@sysoev.ru             return lev;
285953Sigor@sysoev.ru         }
286053Sigor@sysoev.ru     }
286153Sigor@sysoev.ru 
286253Sigor@sysoev.ru     return NULL;
286353Sigor@sysoev.ru }
286453Sigor@sysoev.ru 
286553Sigor@sysoev.ru 
286653Sigor@sysoev.ru static void
286753Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
286853Sigor@sysoev.ru {
2869153Sigor@sysoev.ru     nxt_joint_job_t          *job;
287053Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2871359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
287253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
287353Sigor@sysoev.ru 
2874153Sigor@sysoev.ru     job = obj;
287553Sigor@sysoev.ru     joint = data;
287653Sigor@sysoev.ru 
2877139Sigor@sysoev.ru     engine = task->thread->engine;
2878139Sigor@sysoev.ru 
2879159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2880159Sigor@sysoev.ru 
2881359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2882359Sigor@sysoev.ru                                   joint->socket_conf);
2883359Sigor@sysoev.ru 
2884359Sigor@sysoev.ru     old = lev->socket.data;
2885359Sigor@sysoev.ru     lev->socket.data = joint;
2886359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
288753Sigor@sysoev.ru 
2888153Sigor@sysoev.ru     job->work.next = NULL;
2889153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2890153Sigor@sysoev.ru 
2891153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2892139Sigor@sysoev.ru 
2893181Smax.romanov@nginx.com     /*
2894181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2895181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2896181Smax.romanov@nginx.com      */
2897181Smax.romanov@nginx.com 
2898181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
289953Sigor@sysoev.ru }
290053Sigor@sysoev.ru 
290153Sigor@sysoev.ru 
290253Sigor@sysoev.ru static void
290353Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
290453Sigor@sysoev.ru {
2905153Sigor@sysoev.ru     nxt_joint_job_t     *job;
2906153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
2907359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2908153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2909153Sigor@sysoev.ru 
2910153Sigor@sysoev.ru     job = obj;
291153Sigor@sysoev.ru     skcf = data;
291253Sigor@sysoev.ru 
2913139Sigor@sysoev.ru     engine = task->thread->engine;
2914139Sigor@sysoev.ru 
2915359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
2916359Sigor@sysoev.ru 
2917359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
291853Sigor@sysoev.ru 
2919163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
2920359Sigor@sysoev.ru               lev->socket.fd);
2921359Sigor@sysoev.ru 
2922359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
2923359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
2924359Sigor@sysoev.ru 
2925359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
2926139Sigor@sysoev.ru 
2927153Sigor@sysoev.ru     job->work.next = NULL;
2928153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2929153Sigor@sysoev.ru 
2930153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
293153Sigor@sysoev.ru }
293253Sigor@sysoev.ru 
293353Sigor@sysoev.ru 
293453Sigor@sysoev.ru static void
2935313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
2936313Sigor@sysoev.ru {
2937313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
2938313Sigor@sysoev.ru 
2939313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
2940313Sigor@sysoev.ru 
2941313Sigor@sysoev.ru     engine = task->thread->engine;
2942313Sigor@sysoev.ru 
2943313Sigor@sysoev.ru     engine->shutdown = 1;
2944313Sigor@sysoev.ru 
2945313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
2946313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
2947313Sigor@sysoev.ru     }
2948313Sigor@sysoev.ru }
2949313Sigor@sysoev.ru 
2950313Sigor@sysoev.ru 
2951313Sigor@sysoev.ru static void
295253Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
295353Sigor@sysoev.ru {
295453Sigor@sysoev.ru     nxt_timer_t              *timer;
2955359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
295653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
295753Sigor@sysoev.ru 
295853Sigor@sysoev.ru     timer = obj;
2959359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
296053Sigor@sysoev.ru 
2961163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
2962359Sigor@sysoev.ru               lev->socket.fd);
2963359Sigor@sysoev.ru 
2964359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
2965359Sigor@sysoev.ru 
2966683Sigor@sysoev.ru     joint = lev->socket.data;
2967683Sigor@sysoev.ru     lev->socket.data = NULL;
2968683Sigor@sysoev.ru 
2969359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
2970123Smax.romanov@nginx.com     task = &task->thread->engine->task;
2971123Smax.romanov@nginx.com 
2972359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
2973359Sigor@sysoev.ru 
2974683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
297553Sigor@sysoev.ru }
297653Sigor@sysoev.ru 
297753Sigor@sysoev.ru 
297853Sigor@sysoev.ru static void
2979359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
298053Sigor@sysoev.ru {
2981359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
298253Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
298353Sigor@sysoev.ru 
2984359Sigor@sysoev.ru     ls = skcf->listen;
2985118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
298653Sigor@sysoev.ru 
298753Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
298853Sigor@sysoev.ru 
2989359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
2990359Sigor@sysoev.ru               task->thread->engine, ls->count);
2991359Sigor@sysoev.ru 
2992359Sigor@sysoev.ru     if (--ls->count != 0) {
2993359Sigor@sysoev.ru         ls = NULL;
299453Sigor@sysoev.ru     }
299553Sigor@sysoev.ru 
299653Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
299753Sigor@sysoev.ru 
2998359Sigor@sysoev.ru     if (ls != NULL) {
2999359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
3000359Sigor@sysoev.ru         nxt_free(ls);
300153Sigor@sysoev.ru     }
300253Sigor@sysoev.ru }
300353Sigor@sysoev.ru 
300453Sigor@sysoev.ru 
3005683Sigor@sysoev.ru void
3006683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3007683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
3008683Sigor@sysoev.ru {
3009683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3010683Sigor@sysoev.ru 
3011683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
3012683Sigor@sysoev.ru 
3013683Sigor@sysoev.ru     if (--lev->count == 0) {
3014683Sigor@sysoev.ru         nxt_free(lev);
3015683Sigor@sysoev.ru     }
3016683Sigor@sysoev.ru 
3017683Sigor@sysoev.ru     if (joint != NULL) {
3018683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
3019683Sigor@sysoev.ru     }
3020683Sigor@sysoev.ru 
3021683Sigor@sysoev.ru     engine = task->thread->engine;
3022683Sigor@sysoev.ru 
3023683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3024683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3025683Sigor@sysoev.ru     }
3026683Sigor@sysoev.ru }
3027683Sigor@sysoev.ru 
3028683Sigor@sysoev.ru 
3029683Sigor@sysoev.ru void
303053Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
303153Sigor@sysoev.ru {
303253Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
303353Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
303453Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
303553Sigor@sysoev.ru 
3036163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
303753Sigor@sysoev.ru 
303853Sigor@sysoev.ru     if (--joint->count != 0) {
303953Sigor@sysoev.ru         return;
304053Sigor@sysoev.ru     }
304153Sigor@sysoev.ru 
304253Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
304353Sigor@sysoev.ru 
3044530Sigor@sysoev.ru     /*
3045530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
3046530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
3047530Sigor@sysoev.ru      * be already destroyed by another thread.
3048530Sigor@sysoev.ru      */
304953Sigor@sysoev.ru     skcf = joint->socket_conf;
305053Sigor@sysoev.ru     rtcf = skcf->router_conf;
305153Sigor@sysoev.ru     lock = &rtcf->router->lock;
305253Sigor@sysoev.ru 
305353Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
305453Sigor@sysoev.ru 
3055163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3056163Smax.romanov@nginx.com               rtcf, rtcf->count);
3057163Smax.romanov@nginx.com 
305853Sigor@sysoev.ru     if (--skcf->count != 0) {
3059952Sigor@sysoev.ru         skcf = NULL;
306053Sigor@sysoev.ru         rtcf = NULL;
306153Sigor@sysoev.ru 
306253Sigor@sysoev.ru     } else {
306353Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
306453Sigor@sysoev.ru 
306553Sigor@sysoev.ru         if (--rtcf->count != 0) {
306653Sigor@sysoev.ru             rtcf = NULL;
306753Sigor@sysoev.ru         }
306853Sigor@sysoev.ru     }
306953Sigor@sysoev.ru 
307053Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
307153Sigor@sysoev.ru 
3072952Sigor@sysoev.ru     if (skcf != NULL) {
3073964Sigor@sysoev.ru         if (skcf->pass != NULL) {
3074964Sigor@sysoev.ru             nxt_http_pass_cleanup(task, skcf->pass);
3075964Sigor@sysoev.ru         }
3076964Sigor@sysoev.ru 
3077952Sigor@sysoev.ru #if (NXT_TLS)
3078952Sigor@sysoev.ru         if (skcf->tls != NULL) {
3079952Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
3080952Sigor@sysoev.ru         }
3081952Sigor@sysoev.ru #endif
3082952Sigor@sysoev.ru     }
3083952Sigor@sysoev.ru 
3084141Smax.romanov@nginx.com     /* TODO remove engine->port */
3085141Smax.romanov@nginx.com     /* TODO excude from connected ports */
3086141Smax.romanov@nginx.com 
308753Sigor@sysoev.ru     if (rtcf != NULL) {
3088115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
3089131Smax.romanov@nginx.com 
3090964Sigor@sysoev.ru         nxt_http_routes_cleanup(task, rtcf->routes);
3091964Sigor@sysoev.ru 
3092630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
3093630Svbart@nginx.com 
3094131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
3095131Smax.romanov@nginx.com 
309665Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
309753Sigor@sysoev.ru     }
309853Sigor@sysoev.ru }
309953Sigor@sysoev.ru 
310053Sigor@sysoev.ru 
310153Sigor@sysoev.ru static void
3102630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3103630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3104630Svbart@nginx.com {
3105630Svbart@nginx.com     size_t     size;
3106630Svbart@nginx.com     u_char     *buf, *p;
3107630Svbart@nginx.com     nxt_off_t  bytes;
3108630Svbart@nginx.com 
3109630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
3110630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
3111630Svbart@nginx.com         nxt_router_access_log_date,
3112630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3113703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
3114630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
3115630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
3116630Svbart@nginx.com     };
3117630Svbart@nginx.com 
3118630Svbart@nginx.com     size = r->remote->address_length
3119630Svbart@nginx.com            + 6                  /* ' - - [' */
3120630Svbart@nginx.com            + date_cache.size
3121630Svbart@nginx.com            + 3                  /* '] "' */
3122630Svbart@nginx.com            + r->method->length
3123630Svbart@nginx.com            + 1                  /* space */
3124630Svbart@nginx.com            + r->target.length
3125630Svbart@nginx.com            + 1                  /* space */
3126630Svbart@nginx.com            + r->version.length
3127630Svbart@nginx.com            + 2                  /* '" ' */
3128630Svbart@nginx.com            + 3                  /* status */
3129630Svbart@nginx.com            + 1                  /* space */
3130630Svbart@nginx.com            + NXT_OFF_T_LEN
3131630Svbart@nginx.com            + 2                  /* ' "' */
3132630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3133630Svbart@nginx.com            + 3                  /* '" "' */
3134630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3135630Svbart@nginx.com            + 2                  /* '"\n' */
3136630Svbart@nginx.com     ;
3137630Svbart@nginx.com 
3138630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3139630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3140630Svbart@nginx.com         return;
3141630Svbart@nginx.com     }
3142630Svbart@nginx.com 
3143630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3144630Svbart@nginx.com                    r->remote->address_length);
3145630Svbart@nginx.com 
3146630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3147630Svbart@nginx.com 
3148630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3149630Svbart@nginx.com 
3150630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3151630Svbart@nginx.com 
3152630Svbart@nginx.com     if (r->method->length != 0) {
3153630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3154630Svbart@nginx.com 
3155630Svbart@nginx.com         if (r->target.length != 0) {
3156630Svbart@nginx.com             *p++ = ' ';
3157630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3158630Svbart@nginx.com 
3159630Svbart@nginx.com             if (r->version.length != 0) {
3160630Svbart@nginx.com                 *p++ = ' ';
3161630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3162630Svbart@nginx.com             }
3163630Svbart@nginx.com         }
3164630Svbart@nginx.com 
3165630Svbart@nginx.com     } else {
3166630Svbart@nginx.com         *p++ = '-';
3167630Svbart@nginx.com     }
3168630Svbart@nginx.com 
3169630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3170630Svbart@nginx.com 
3171630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3172630Svbart@nginx.com 
3173630Svbart@nginx.com     *p++ = ' ';
3174630Svbart@nginx.com 
31751112Sigor@sysoev.ru     bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3176630Svbart@nginx.com 
3177630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3178630Svbart@nginx.com 
3179630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3180630Svbart@nginx.com 
3181630Svbart@nginx.com     if (r->referer != NULL) {
3182630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3183630Svbart@nginx.com 
3184630Svbart@nginx.com     } else {
3185630Svbart@nginx.com         *p++ = '-';
3186630Svbart@nginx.com     }
3187630Svbart@nginx.com 
3188630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3189630Svbart@nginx.com 
3190630Svbart@nginx.com     if (r->user_agent != NULL) {
3191630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3192630Svbart@nginx.com 
3193630Svbart@nginx.com     } else {
3194630Svbart@nginx.com         *p++ = '-';
3195630Svbart@nginx.com     }
3196630Svbart@nginx.com 
3197630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3198630Svbart@nginx.com 
3199630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3200630Svbart@nginx.com }
3201630Svbart@nginx.com 
3202630Svbart@nginx.com 
3203630Svbart@nginx.com static u_char *
3204630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3205630Svbart@nginx.com     size_t size, const char *format)
3206630Svbart@nginx.com {
3207630Svbart@nginx.com     u_char  sign;
3208630Svbart@nginx.com     time_t  gmtoff;
3209630Svbart@nginx.com 
3210630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3211630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3212630Svbart@nginx.com 
3213630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3214630Svbart@nginx.com 
3215630Svbart@nginx.com     if (gmtoff < 0) {
3216630Svbart@nginx.com         gmtoff = -gmtoff;
3217630Svbart@nginx.com         sign = '-';
3218630Svbart@nginx.com 
3219630Svbart@nginx.com     } else {
3220630Svbart@nginx.com         sign = '+';
3221630Svbart@nginx.com     }
3222630Svbart@nginx.com 
3223630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3224630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3225630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3226630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3227630Svbart@nginx.com }
3228630Svbart@nginx.com 
3229630Svbart@nginx.com 
3230630Svbart@nginx.com static void
3231630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3232630Svbart@nginx.com {
3233630Svbart@nginx.com     uint32_t                 stream;
3234648Svbart@nginx.com     nxt_int_t                ret;
3235630Svbart@nginx.com     nxt_buf_t                *b;
3236630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3237630Svbart@nginx.com     nxt_runtime_t            *rt;
3238630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3239630Svbart@nginx.com 
3240630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3241630Svbart@nginx.com 
3242630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3243630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3244630Svbart@nginx.com         goto fail;
3245630Svbart@nginx.com     }
3246630Svbart@nginx.com 
3247630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3248630Svbart@nginx.com     *b->mem.free++ = '\0';
3249630Svbart@nginx.com 
3250630Svbart@nginx.com     rt = task->thread->runtime;
3251630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3252630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3253630Svbart@nginx.com 
3254630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3255630Svbart@nginx.com                                            nxt_router_access_log_ready,
3256630Svbart@nginx.com                                            nxt_router_access_log_error,
3257630Svbart@nginx.com                                            -1, tmcf);
3258630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3259630Svbart@nginx.com         goto fail;
3260630Svbart@nginx.com     }
3261630Svbart@nginx.com 
3262648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3263648Svbart@nginx.com                                 stream, router_port->id, b);
3264648Svbart@nginx.com 
3265648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3266648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3267648Svbart@nginx.com         goto fail;
3268648Svbart@nginx.com     }
3269630Svbart@nginx.com 
3270630Svbart@nginx.com     return;
3271630Svbart@nginx.com 
3272630Svbart@nginx.com fail:
3273630Svbart@nginx.com 
3274630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3275630Svbart@nginx.com }
3276630Svbart@nginx.com 
3277630Svbart@nginx.com 
3278630Svbart@nginx.com static void
3279630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3280630Svbart@nginx.com     void *data)
3281630Svbart@nginx.com {
3282630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3283630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3284630Svbart@nginx.com 
3285630Svbart@nginx.com     tmcf = data;
3286630Svbart@nginx.com 
3287630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3288630Svbart@nginx.com 
3289630Svbart@nginx.com     access_log->fd = msg->fd;
3290630Svbart@nginx.com 
3291630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3292630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3293630Svbart@nginx.com }
3294630Svbart@nginx.com 
3295630Svbart@nginx.com 
3296630Svbart@nginx.com static void
3297630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3298630Svbart@nginx.com     void *data)
3299630Svbart@nginx.com {
3300630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3301630Svbart@nginx.com 
3302630Svbart@nginx.com     tmcf = data;
3303630Svbart@nginx.com 
3304630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3305630Svbart@nginx.com }
3306630Svbart@nginx.com 
3307630Svbart@nginx.com 
3308630Svbart@nginx.com static void
3309630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3310630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3311630Svbart@nginx.com {
3312630Svbart@nginx.com     if (access_log == NULL) {
3313630Svbart@nginx.com         return;
3314630Svbart@nginx.com     }
3315630Svbart@nginx.com 
3316630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3317630Svbart@nginx.com 
3318630Svbart@nginx.com     if (--access_log->count != 0) {
3319630Svbart@nginx.com         access_log = NULL;
3320630Svbart@nginx.com     }
3321630Svbart@nginx.com 
3322630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3323630Svbart@nginx.com 
3324630Svbart@nginx.com     if (access_log != NULL) {
3325630Svbart@nginx.com 
3326630Svbart@nginx.com         if (access_log->fd != -1) {
3327630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3328630Svbart@nginx.com         }
3329630Svbart@nginx.com 
3330630Svbart@nginx.com         nxt_free(access_log);
3331630Svbart@nginx.com     }
3332630Svbart@nginx.com }
3333630Svbart@nginx.com 
3334630Svbart@nginx.com 
3335631Svbart@nginx.com typedef struct {
3336631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3337631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3338631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3339631Svbart@nginx.com 
3340631Svbart@nginx.com 
3341631Svbart@nginx.com void
3342631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3343631Svbart@nginx.com {
3344631Svbart@nginx.com     nxt_mp_t                        *mp;
3345631Svbart@nginx.com     uint32_t                        stream;
3346631Svbart@nginx.com     nxt_int_t                       ret;
3347631Svbart@nginx.com     nxt_buf_t                       *b;
3348631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3349631Svbart@nginx.com     nxt_runtime_t                   *rt;
3350631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3351631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3352631Svbart@nginx.com 
3353631Svbart@nginx.com     access_log = nxt_router->access_log;
3354631Svbart@nginx.com 
3355631Svbart@nginx.com     if (access_log == NULL) {
3356631Svbart@nginx.com         return;
3357631Svbart@nginx.com     }
3358631Svbart@nginx.com 
3359631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3360631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3361631Svbart@nginx.com         return;
3362631Svbart@nginx.com     }
3363631Svbart@nginx.com 
3364631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3365631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3366631Svbart@nginx.com         goto fail;
3367631Svbart@nginx.com     }
3368631Svbart@nginx.com 
3369631Svbart@nginx.com     reopen->mem_pool = mp;
3370631Svbart@nginx.com     reopen->access_log = access_log;
3371631Svbart@nginx.com 
3372631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3373631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3374631Svbart@nginx.com         goto fail;
3375631Svbart@nginx.com     }
3376631Svbart@nginx.com 
3377651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3378651Svbart@nginx.com 
3379631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3380631Svbart@nginx.com     *b->mem.free++ = '\0';
3381631Svbart@nginx.com 
3382631Svbart@nginx.com     rt = task->thread->runtime;
3383631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3384631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3385631Svbart@nginx.com 
3386631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3387631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3388631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3389631Svbart@nginx.com                                            -1, reopen);
3390631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3391631Svbart@nginx.com         goto fail;
3392631Svbart@nginx.com     }
3393631Svbart@nginx.com 
3394631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3395631Svbart@nginx.com                                 stream, router_port->id, b);
3396631Svbart@nginx.com 
3397631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3398631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3399631Svbart@nginx.com         goto fail;
3400631Svbart@nginx.com     }
3401631Svbart@nginx.com 
3402651Svbart@nginx.com     nxt_mp_retain(mp);
3403651Svbart@nginx.com 
3404631Svbart@nginx.com     return;
3405631Svbart@nginx.com 
3406631Svbart@nginx.com fail:
3407631Svbart@nginx.com 
3408631Svbart@nginx.com     nxt_mp_destroy(mp);
3409631Svbart@nginx.com }
3410631Svbart@nginx.com 
3411631Svbart@nginx.com 
3412631Svbart@nginx.com static void
3413651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3414651Svbart@nginx.com {
3415651Svbart@nginx.com     nxt_mp_t   *mp;
3416651Svbart@nginx.com     nxt_buf_t  *b;
3417651Svbart@nginx.com 
3418651Svbart@nginx.com     b = obj;
3419651Svbart@nginx.com     mp = b->data;
3420651Svbart@nginx.com 
3421651Svbart@nginx.com     nxt_mp_release(mp);
3422651Svbart@nginx.com }
3423651Svbart@nginx.com 
3424651Svbart@nginx.com 
3425651Svbart@nginx.com static void
3426631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3427631Svbart@nginx.com     void *data)
3428631Svbart@nginx.com {
3429631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3430631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3431631Svbart@nginx.com 
3432631Svbart@nginx.com     reopen = data;
3433631Svbart@nginx.com 
3434631Svbart@nginx.com     access_log = reopen->access_log;
3435631Svbart@nginx.com 
3436631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3437631Svbart@nginx.com 
3438631Svbart@nginx.com         if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) {
3439631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3440631Svbart@nginx.com                       msg->fd, access_log->fd, nxt_errno);
3441631Svbart@nginx.com         }
3442631Svbart@nginx.com     }
3443631Svbart@nginx.com 
3444631Svbart@nginx.com     nxt_fd_close(msg->fd);
3445651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3446631Svbart@nginx.com }
3447631Svbart@nginx.com 
3448631Svbart@nginx.com 
3449631Svbart@nginx.com static void
3450631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3451631Svbart@nginx.com     void *data)
3452631Svbart@nginx.com {
3453631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3454631Svbart@nginx.com 
3455631Svbart@nginx.com     reopen = data;
3456631Svbart@nginx.com 
3457651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3458631Svbart@nginx.com }
3459631Svbart@nginx.com 
3460631Svbart@nginx.com 
3461630Svbart@nginx.com static void
346253Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
346353Sigor@sysoev.ru {
3464141Smax.romanov@nginx.com     nxt_port_t           *port;
346553Sigor@sysoev.ru     nxt_thread_link_t    *link;
346653Sigor@sysoev.ru     nxt_event_engine_t   *engine;
346753Sigor@sysoev.ru     nxt_thread_handle_t  handle;
346853Sigor@sysoev.ru 
346958Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
347053Sigor@sysoev.ru     link = data;
347153Sigor@sysoev.ru 
347253Sigor@sysoev.ru     nxt_thread_wait(handle);
347353Sigor@sysoev.ru 
347453Sigor@sysoev.ru     engine = link->engine;
347553Sigor@sysoev.ru 
347653Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
347753Sigor@sysoev.ru 
3478141Smax.romanov@nginx.com     port = engine->port;
3479141Smax.romanov@nginx.com 
3480141Smax.romanov@nginx.com     // TODO notify all apps
3481141Smax.romanov@nginx.com 
3482343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3483163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3484343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3485163Smax.romanov@nginx.com 
3486163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
348763Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
348853Sigor@sysoev.ru 
348953Sigor@sysoev.ru     nxt_event_engine_free(engine);
349053Sigor@sysoev.ru 
349153Sigor@sysoev.ru     nxt_free(link);
349253Sigor@sysoev.ru }
349353Sigor@sysoev.ru 
349453Sigor@sysoev.ru 
349553Sigor@sysoev.ru static void
3496318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3497318Smax.romanov@nginx.com     void *data)
349888Smax.romanov@nginx.com {
34991123Smax.romanov@nginx.com     nxt_int_t               ret;
35001123Smax.romanov@nginx.com     nxt_buf_t               *b;
35011131Smax.romanov@nginx.com     nxt_port_t              *app_port;
35021123Smax.romanov@nginx.com     nxt_unit_field_t        *f;
35031123Smax.romanov@nginx.com     nxt_http_field_t        *field;
35041123Smax.romanov@nginx.com     nxt_http_request_t      *r;
35051123Smax.romanov@nginx.com     nxt_unit_response_t     *resp;
35061131Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
35071123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
350888Smax.romanov@nginx.com 
350988Smax.romanov@nginx.com     b = msg->buf;
35101123Smax.romanov@nginx.com     req_rpc_data = data;
351188Smax.romanov@nginx.com 
351288Smax.romanov@nginx.com     if (msg->size == 0) {
351388Smax.romanov@nginx.com         b = NULL;
351488Smax.romanov@nginx.com     }
351588Smax.romanov@nginx.com 
35161123Smax.romanov@nginx.com     r = req_rpc_data->request;
35171007Salexander.borisov@nginx.com     if (nxt_slow_path(r == NULL)) {
3518570Smax.romanov@nginx.com         return;
3519570Smax.romanov@nginx.com     }
3520425Smax.romanov@nginx.com 
35211007Salexander.borisov@nginx.com     if (r->error) {
35221123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3523608Sigor@sysoev.ru         return;
3524608Sigor@sysoev.ru     }
3525608Sigor@sysoev.ru 
352688Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
352788Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
352888Smax.romanov@nginx.com 
35291007Salexander.borisov@nginx.com         nxt_buf_chain_add(&b, nxt_http_buf_last(r));
3530167Smax.romanov@nginx.com 
35311123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3532425Smax.romanov@nginx.com 
3533425Smax.romanov@nginx.com     } else {
35341123Smax.romanov@nginx.com         if (req_rpc_data->app != NULL && req_rpc_data->app->timeout != 0) {
35351007Salexander.borisov@nginx.com             r->timer.handler = nxt_router_app_timeout;
35361123Smax.romanov@nginx.com             r->timer_data = req_rpc_data;
35371123Smax.romanov@nginx.com             nxt_timer_add(task->thread->engine, &r->timer,
35381123Smax.romanov@nginx.com                           req_rpc_data->app->timeout);
3539425Smax.romanov@nginx.com         }
354088Smax.romanov@nginx.com     }
354188Smax.romanov@nginx.com 
354288Smax.romanov@nginx.com     if (b == NULL) {
354388Smax.romanov@nginx.com         return;
354488Smax.romanov@nginx.com     }
354588Smax.romanov@nginx.com 
3546206Smax.romanov@nginx.com     if (msg->buf == b) {
3547206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3548206Smax.romanov@nginx.com         msg->buf = NULL;
3549206Smax.romanov@nginx.com     }
3550194Smax.romanov@nginx.com 
3551431Sigor@sysoev.ru     if (r->header_sent) {
3552431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3553431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3554277Sigor@sysoev.ru 
355588Smax.romanov@nginx.com     } else {
3556743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3557743Smax.romanov@nginx.com 
3558743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3559743Smax.romanov@nginx.com             goto fail;
3560743Smax.romanov@nginx.com         }
3561743Smax.romanov@nginx.com 
3562743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3563743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3564743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3565743Smax.romanov@nginx.com             goto fail;
3566743Smax.romanov@nginx.com         }
3567743Smax.romanov@nginx.com 
35681126Smax.romanov@nginx.com         field = NULL;
35691126Smax.romanov@nginx.com 
3570743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
35711126Smax.romanov@nginx.com             if (f->skip) {
35721126Smax.romanov@nginx.com                 continue;
35731126Smax.romanov@nginx.com             }
35741126Smax.romanov@nginx.com 
35751007Salexander.borisov@nginx.com             field = nxt_list_add(r->resp.fields);
3576743Smax.romanov@nginx.com 
3577743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3578743Smax.romanov@nginx.com                 goto fail;
3579743Smax.romanov@nginx.com             }
3580743Smax.romanov@nginx.com 
3581743Smax.romanov@nginx.com             field->hash = f->hash;
35821126Smax.romanov@nginx.com             field->skip = 0;
3583743Smax.romanov@nginx.com 
3584743Smax.romanov@nginx.com             field->name_length = f->name_length;
3585743Smax.romanov@nginx.com             field->value_length = f->value_length;
3586743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3587743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3588743Smax.romanov@nginx.com 
35891126Smax.romanov@nginx.com             ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
35901126Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
35911126Smax.romanov@nginx.com                 goto fail;
35921126Smax.romanov@nginx.com             }
35931126Smax.romanov@nginx.com 
35941126Smax.romanov@nginx.com             nxt_debug(task, "header%s: %*s: %*s",
35951126Smax.romanov@nginx.com                       (field->skip ? " skipped" : ""),
3596743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3597743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
35981126Smax.romanov@nginx.com 
35991126Smax.romanov@nginx.com             if (field->skip) {
36001126Smax.romanov@nginx.com                 r->resp.fields->last->nelts--;
36011126Smax.romanov@nginx.com             }
3602743Smax.romanov@nginx.com         }
36031007Salexander.borisov@nginx.com 
3604743Smax.romanov@nginx.com         r->status = resp->status;
3605743Smax.romanov@nginx.com 
3606743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3607743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3608743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3609743Smax.romanov@nginx.com 
3610743Smax.romanov@nginx.com         } else {
3611743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3612743Smax.romanov@nginx.com         }
3613743Smax.romanov@nginx.com 
3614435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
3615435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3616435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3617507Smax.romanov@nginx.com 
3618520Smax.romanov@nginx.com             b = b->next;
3619520Smax.romanov@nginx.com         }
3620520Smax.romanov@nginx.com 
3621520Smax.romanov@nginx.com         if (b != NULL) {
3622431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3623431Sigor@sysoev.ru         }
3624431Sigor@sysoev.ru 
36251148Sigor@sysoev.ru         nxt_http_request_header_send(task, r, nxt_http_request_send_body);
36261127Smax.romanov@nginx.com 
36271131Smax.romanov@nginx.com         if (r->websocket_handshake
36281131Smax.romanov@nginx.com             && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
36291131Smax.romanov@nginx.com         {
36301131Smax.romanov@nginx.com             req_app_link = nxt_request_app_link_alloc(task,
36311131Smax.romanov@nginx.com                                                      req_rpc_data->req_app_link,
36321131Smax.romanov@nginx.com                                                      req_rpc_data);
36331131Smax.romanov@nginx.com             if (nxt_slow_path(req_app_link == NULL)) {
36341131Smax.romanov@nginx.com                 goto fail;
36351131Smax.romanov@nginx.com             }
36361131Smax.romanov@nginx.com 
36371131Smax.romanov@nginx.com             app_port = req_app_link->app_port;
36381131Smax.romanov@nginx.com 
36391131Smax.romanov@nginx.com             if (app_port == NULL && req_rpc_data->app_port != NULL) {
36401131Smax.romanov@nginx.com                 req_app_link->app_port = req_rpc_data->app_port;
36411131Smax.romanov@nginx.com                 app_port = req_app_link->app_port;
36421131Smax.romanov@nginx.com                 req_app_link->apr_action = req_rpc_data->apr_action;
36431131Smax.romanov@nginx.com 
36441131Smax.romanov@nginx.com                 req_rpc_data->app_port = NULL;
36451131Smax.romanov@nginx.com             }
36461131Smax.romanov@nginx.com 
36471131Smax.romanov@nginx.com             if (nxt_slow_path(app_port == NULL)) {
36481131Smax.romanov@nginx.com                 goto fail;
36491131Smax.romanov@nginx.com             }
36501131Smax.romanov@nginx.com 
36511131Smax.romanov@nginx.com             nxt_thread_mutex_lock(&req_rpc_data->app->mutex);
36521131Smax.romanov@nginx.com 
36531131Smax.romanov@nginx.com             nxt_queue_insert_tail(&app_port->active_websockets,
36541131Smax.romanov@nginx.com                                   &req_app_link->link_port_websockets);
36551131Smax.romanov@nginx.com 
36561131Smax.romanov@nginx.com             nxt_thread_mutex_unlock(&req_rpc_data->app->mutex);
36571131Smax.romanov@nginx.com 
36581131Smax.romanov@nginx.com             nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE);
36591131Smax.romanov@nginx.com             req_app_link->apr_action = NXT_APR_CLOSE;
36601131Smax.romanov@nginx.com 
36611131Smax.romanov@nginx.com             nxt_debug(task, "req_app_link stream #%uD upgrade",
36621131Smax.romanov@nginx.com                       req_app_link->stream);
36631131Smax.romanov@nginx.com 
36641131Smax.romanov@nginx.com             r->state = &nxt_http_websocket;
36651131Smax.romanov@nginx.com 
36661131Smax.romanov@nginx.com         } else {
36671131Smax.romanov@nginx.com             r->state = &nxt_http_request_send_state;
36681131Smax.romanov@nginx.com         }
3669431Sigor@sysoev.ru     }
3670431Sigor@sysoev.ru 
3671431Sigor@sysoev.ru     return;
3672431Sigor@sysoev.ru 
3673431Sigor@sysoev.ru fail:
3674431Sigor@sysoev.ru 
3675615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3676615Smax.romanov@nginx.com 
36771123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3678431Sigor@sysoev.ru }
3679431Sigor@sysoev.ru 
3680431Sigor@sysoev.ru 
3681431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3682431Sigor@sysoev.ru     nxt_aligned(64) =
3683431Sigor@sysoev.ru {
3684943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
3685431Sigor@sysoev.ru };
3686431Sigor@sysoev.ru 
3687431Sigor@sysoev.ru 
3688431Sigor@sysoev.ru static void
3689431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3690431Sigor@sysoev.ru {
3691431Sigor@sysoev.ru     nxt_buf_t           *out;
3692431Sigor@sysoev.ru     nxt_http_request_t  *r;
3693431Sigor@sysoev.ru 
3694431Sigor@sysoev.ru     r = obj;
3695431Sigor@sysoev.ru 
3696431Sigor@sysoev.ru     out = r->out;
3697431Sigor@sysoev.ru 
3698431Sigor@sysoev.ru     if (out != NULL) {
3699431Sigor@sysoev.ru         r->out = NULL;
3700431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
370188Smax.romanov@nginx.com     }
370288Smax.romanov@nginx.com }
370388Smax.romanov@nginx.com 
3704277Sigor@sysoev.ru 
3705318Smax.romanov@nginx.com static void
3706318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3707318Smax.romanov@nginx.com     void *data)
3708318Smax.romanov@nginx.com {
37091123Smax.romanov@nginx.com     nxt_int_t               res;
37101123Smax.romanov@nginx.com     nxt_port_t              *port;
37111123Smax.romanov@nginx.com     nxt_bool_t              cancelled;
37121123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
37131123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
37141123Smax.romanov@nginx.com 
37151123Smax.romanov@nginx.com     req_rpc_data = data;
37161123Smax.romanov@nginx.com 
37171123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
37181123Smax.romanov@nginx.com 
37191123Smax.romanov@nginx.com     if (req_app_link != NULL) {
37201123Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &req_app_link->msg_info,
37211123Smax.romanov@nginx.com                                           req_app_link->stream);
3722425Smax.romanov@nginx.com         if (cancelled) {
37231123Smax.romanov@nginx.com             nxt_request_app_link_inc_use(req_app_link);
37241123Smax.romanov@nginx.com 
37251123Smax.romanov@nginx.com             res = nxt_router_app_port(task, req_rpc_data->app, req_app_link);
3726425Smax.romanov@nginx.com 
3727425Smax.romanov@nginx.com             if (res == NXT_OK) {
37281123Smax.romanov@nginx.com                 port = req_app_link->app_port;
3729425Smax.romanov@nginx.com 
3730551Smax.romanov@nginx.com                 if (nxt_slow_path(port == NULL)) {
37311123Smax.romanov@nginx.com                     nxt_log(task, NXT_LOG_ERR,
37321123Smax.romanov@nginx.com                             "port is NULL in cancelled req_app_link");
3733551Smax.romanov@nginx.com                     return;
3734551Smax.romanov@nginx.com                 }
3735425Smax.romanov@nginx.com 
37361123Smax.romanov@nginx.com                 nxt_port_rpc_ex_set_peer(task, task->thread->engine->port,
37371123Smax.romanov@nginx.com                                          req_rpc_data, port->pid);
37381123Smax.romanov@nginx.com 
37391123Smax.romanov@nginx.com                 nxt_router_app_prepare_request(task, req_app_link);
3740425Smax.romanov@nginx.com             }
3741425Smax.romanov@nginx.com 
3742425Smax.romanov@nginx.com             msg->port_msg.last = 0;
3743425Smax.romanov@nginx.com 
3744425Smax.romanov@nginx.com             return;
3745425Smax.romanov@nginx.com         }
3746425Smax.romanov@nginx.com     }
3747425Smax.romanov@nginx.com 
37481123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
37491123Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
3750616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3751616Smax.romanov@nginx.com     }
3752318Smax.romanov@nginx.com 
37531123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3754318Smax.romanov@nginx.com }
3755318Smax.romanov@nginx.com 
3756318Smax.romanov@nginx.com 
3757141Smax.romanov@nginx.com static void
3758343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3759343Smax.romanov@nginx.com     void *data)
3760192Smax.romanov@nginx.com {
3761753Smax.romanov@nginx.com     nxt_app_t        *app;
3762753Smax.romanov@nginx.com     nxt_port_t       *port;
3763753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3764753Smax.romanov@nginx.com 
3765753Smax.romanov@nginx.com     app_joint = data;
3766347Smax.romanov@nginx.com     port = msg->u.new_port;
3767343Smax.romanov@nginx.com 
3768753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3769343Smax.romanov@nginx.com     nxt_assert(port != NULL);
3770343Smax.romanov@nginx.com 
3771753Smax.romanov@nginx.com     app = app_joint->app;
3772753Smax.romanov@nginx.com 
3773753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3774753Smax.romanov@nginx.com 
3775753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3776753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3777753Smax.romanov@nginx.com 
3778753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3779753Smax.romanov@nginx.com 
3780753Smax.romanov@nginx.com         return;
3781753Smax.romanov@nginx.com     }
3782753Smax.romanov@nginx.com 
3783343Smax.romanov@nginx.com     port->app = app;
3784343Smax.romanov@nginx.com 
3785343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3786343Smax.romanov@nginx.com 
3787507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3788507Smax.romanov@nginx.com 
3789507Smax.romanov@nginx.com     app->pending_processes--;
3790507Smax.romanov@nginx.com     app->processes++;
3791343Smax.romanov@nginx.com 
3792343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3793343Smax.romanov@nginx.com 
3794507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3795507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3796343Smax.romanov@nginx.com 
37971123Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT);
3798192Smax.romanov@nginx.com }
3799192Smax.romanov@nginx.com 
3800192Smax.romanov@nginx.com 
3801192Smax.romanov@nginx.com static void
3802343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3803343Smax.romanov@nginx.com     void *data)
3804192Smax.romanov@nginx.com {
38051123Smax.romanov@nginx.com     nxt_app_t               *app;
38061123Smax.romanov@nginx.com     nxt_app_joint_t         *app_joint;
38071123Smax.romanov@nginx.com     nxt_queue_link_t        *lnk;
38081123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
3809343Smax.romanov@nginx.com 
3810753Smax.romanov@nginx.com     app_joint = data;
3811753Smax.romanov@nginx.com 
3812753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3813753Smax.romanov@nginx.com 
3814753Smax.romanov@nginx.com     app = app_joint->app;
3815753Smax.romanov@nginx.com 
3816753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3817753Smax.romanov@nginx.com 
3818753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3819753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
3820753Smax.romanov@nginx.com 
3821753Smax.romanov@nginx.com         return;
3822753Smax.romanov@nginx.com     }
3823343Smax.romanov@nginx.com 
3824343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
3825343Smax.romanov@nginx.com 
3826343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3827343Smax.romanov@nginx.com 
3828507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3829507Smax.romanov@nginx.com 
3830507Smax.romanov@nginx.com     app->pending_processes--;
3831318Smax.romanov@nginx.com 
3832318Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->requests)) {
3833318Smax.romanov@nginx.com         lnk = nxt_queue_last(&app->requests);
3834318Smax.romanov@nginx.com         nxt_queue_remove(lnk);
3835343Smax.romanov@nginx.com         lnk->next = NULL;
3836318Smax.romanov@nginx.com 
38371123Smax.romanov@nginx.com         req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t,
38381123Smax.romanov@nginx.com                                            link_app_requests);
3839318Smax.romanov@nginx.com 
3840343Smax.romanov@nginx.com     } else {
38411123Smax.romanov@nginx.com         req_app_link = NULL;
3842343Smax.romanov@nginx.com     }
3843343Smax.romanov@nginx.com 
3844343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3845343Smax.romanov@nginx.com 
38461123Smax.romanov@nginx.com     if (req_app_link != NULL) {
3847318Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p abort next stream #%uD",
38481123Smax.romanov@nginx.com                   &app->name, app, req_app_link->stream);
38491123Smax.romanov@nginx.com 
38501123Smax.romanov@nginx.com         nxt_request_app_link_error(req_app_link, 500,
38511123Smax.romanov@nginx.com                                    "Failed to start application process");
38521123Smax.romanov@nginx.com         nxt_request_app_link_use(task, req_app_link, -1);
3853318Smax.romanov@nginx.com     }
3854192Smax.romanov@nginx.com }
3855192Smax.romanov@nginx.com 
3856753Smax.romanov@nginx.com nxt_inline nxt_port_t *
3857753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app);
3858192Smax.romanov@nginx.com 
3859343Smax.romanov@nginx.com void
3860343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
3861141Smax.romanov@nginx.com {
3862343Smax.romanov@nginx.com     int  c;
3863343Smax.romanov@nginx.com 
3864343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
3865343Smax.romanov@nginx.com 
3866343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
3867343Smax.romanov@nginx.com 
3868753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
3869753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
3870753Smax.romanov@nginx.com 
3871753Smax.romanov@nginx.com         } else {
3872753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
3873753Smax.romanov@nginx.com         }
3874163Smax.romanov@nginx.com     }
3875343Smax.romanov@nginx.com }
3876343Smax.romanov@nginx.com 
3877343Smax.romanov@nginx.com 
3878424Smax.romanov@nginx.com nxt_inline nxt_bool_t
3879424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app)
3880424Smax.romanov@nginx.com {
3881424Smax.romanov@nginx.com     nxt_port_t        *port;
3882424Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3883424Smax.romanov@nginx.com 
3884424Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3885424Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3886424Smax.romanov@nginx.com 
3887424Smax.romanov@nginx.com     return port->app_pending_responses > 0;
3888424Smax.romanov@nginx.com }
3889424Smax.romanov@nginx.com 
3890424Smax.romanov@nginx.com 
3891343Smax.romanov@nginx.com nxt_inline nxt_port_t *
3892427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app)
3893343Smax.romanov@nginx.com {
3894343Smax.romanov@nginx.com     nxt_port_t        *port;
3895343Smax.romanov@nginx.com     nxt_queue_link_t  *lnk;
3896343Smax.romanov@nginx.com 
3897343Smax.romanov@nginx.com     lnk = nxt_queue_first(&app->ports);
3898343Smax.romanov@nginx.com     nxt_queue_remove(lnk);
3899343Smax.romanov@nginx.com 
3900343Smax.romanov@nginx.com     port = nxt_queue_link_data(lnk, nxt_port_t, app_link);
3901343Smax.romanov@nginx.com 
3902424Smax.romanov@nginx.com     port->app_pending_responses++;
3903424Smax.romanov@nginx.com 
3904507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
3905507Smax.romanov@nginx.com         app->idle_processes--;
3906507Smax.romanov@nginx.com 
3907507Smax.romanov@nginx.com         if (port->idle_start == 0) {
3908507Smax.romanov@nginx.com             nxt_assert(app->idle_processes < app->spare_processes);
3909507Smax.romanov@nginx.com 
3910507Smax.romanov@nginx.com         } else {
3911507Smax.romanov@nginx.com             nxt_assert(app->idle_processes >= app->spare_processes);
3912507Smax.romanov@nginx.com 
3913507Smax.romanov@nginx.com             port->idle_start = 0;
3914507Smax.romanov@nginx.com         }
3915507Smax.romanov@nginx.com     }
3916507Smax.romanov@nginx.com 
3917428Smax.romanov@nginx.com     if ((app->max_pending_responses == 0
3918428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
3919428Smax.romanov@nginx.com         && (app->max_requests == 0
3920428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
3921428Smax.romanov@nginx.com                 < app->max_requests))
3922277Sigor@sysoev.ru     {
3923343Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, lnk);
3924343Smax.romanov@nginx.com 
3925425Smax.romanov@nginx.com         nxt_port_inc_use(port);
3926425Smax.romanov@nginx.com 
3927343Smax.romanov@nginx.com     } else {
3928343Smax.romanov@nginx.com         lnk->next = NULL;
3929167Smax.romanov@nginx.com     }
3930167Smax.romanov@nginx.com 
3931343Smax.romanov@nginx.com     return port;
3932163Smax.romanov@nginx.com }
3933163Smax.romanov@nginx.com 
3934163Smax.romanov@nginx.com 
3935507Smax.romanov@nginx.com nxt_inline nxt_port_t *
3936507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app)
3937141Smax.romanov@nginx.com {
3938343Smax.romanov@nginx.com     nxt_port_t  *port;
3939141Smax.romanov@nginx.com 
3940141Smax.romanov@nginx.com     port = NULL;
3941141Smax.romanov@nginx.com 
3942141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3943141Smax.romanov@nginx.com 
3944343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
3945343Smax.romanov@nginx.com 
3946424Smax.romanov@nginx.com         if (port->app_pending_responses > 0) {
3947343Smax.romanov@nginx.com             port = NULL;
3948343Smax.romanov@nginx.com 
3949343Smax.romanov@nginx.com             continue;
3950343Smax.romanov@nginx.com         }
3951343Smax.romanov@nginx.com 
3952507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
3953507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
3954507Smax.romanov@nginx.com 
3955507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
3956507Smax.romanov@nginx.com             app->idle_processes--;
3957507Smax.romanov@nginx.com         }
3958507Smax.romanov@nginx.com 
3959507Smax.romanov@nginx.com         port->app = NULL;
3960507Smax.romanov@nginx.com         app->processes--;
3961343Smax.romanov@nginx.com 
3962343Smax.romanov@nginx.com         break;
3963343Smax.romanov@nginx.com 
3964343Smax.romanov@nginx.com     } nxt_queue_loop;
3965141Smax.romanov@nginx.com 
3966141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3967141Smax.romanov@nginx.com 
3968141Smax.romanov@nginx.com     return port;
3969141Smax.romanov@nginx.com }
3970141Smax.romanov@nginx.com 
3971141Smax.romanov@nginx.com 
3972141Smax.romanov@nginx.com static void
3973753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
3974507Smax.romanov@nginx.com {
3975753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
3976507Smax.romanov@nginx.com 
3977507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
3978507Smax.romanov@nginx.com 
3979753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
3980507Smax.romanov@nginx.com }
3981507Smax.romanov@nginx.com 
3982507Smax.romanov@nginx.com 
3983507Smax.romanov@nginx.com static void
3984343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data)
3985141Smax.romanov@nginx.com {
39861123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
39871123Smax.romanov@nginx.com 
39881123Smax.romanov@nginx.com     req_app_link = data;
3989538Svbart@nginx.com 
3990538Svbart@nginx.com #if (NXT_DEBUG)
3991538Svbart@nginx.com     {
3992538Svbart@nginx.com     nxt_app_t  *app;
3993538Svbart@nginx.com 
3994343Smax.romanov@nginx.com     app = obj;
3995141Smax.romanov@nginx.com 
3996141Smax.romanov@nginx.com     nxt_assert(app != NULL);
39971123Smax.romanov@nginx.com     nxt_assert(req_app_link != NULL);
39981123Smax.romanov@nginx.com     nxt_assert(req_app_link->app_port != NULL);
3999343Smax.romanov@nginx.com 
4000343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p process next stream #%uD",
40011123Smax.romanov@nginx.com               &app->name, app, req_app_link->stream);
4002538Svbart@nginx.com     }
4003538Svbart@nginx.com #endif
4004343Smax.romanov@nginx.com 
40051123Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, req_app_link);
4006343Smax.romanov@nginx.com }
4007343Smax.romanov@nginx.com 
4008343Smax.romanov@nginx.com 
4009343Smax.romanov@nginx.com static void
4010343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
40111123Smax.romanov@nginx.com     nxt_apr_action_t action)
4012343Smax.romanov@nginx.com {
40131123Smax.romanov@nginx.com     int                      inc_use;
40141123Smax.romanov@nginx.com     uint32_t                 dec_pending, got_response;
4015427Smax.romanov@nginx.com     nxt_app_t                *app;
4016507Smax.romanov@nginx.com     nxt_bool_t               port_unchained;
4017507Smax.romanov@nginx.com     nxt_bool_t               send_quit, cancelled, adjust_idle_timer;
4018427Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
40191123Smax.romanov@nginx.com     nxt_request_app_link_t   *req_app_link, *pending_ra, *re_ra;
4020427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4021343Smax.romanov@nginx.com 
4022343Smax.romanov@nginx.com     nxt_assert(port != NULL);
4023343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
4024343Smax.romanov@nginx.com 
40251123Smax.romanov@nginx.com     req_app_link = NULL;
4026427Smax.romanov@nginx.com 
4027343Smax.romanov@nginx.com     app = port->app;
4028343Smax.romanov@nginx.com 
40291123Smax.romanov@nginx.com     inc_use = 0;
40301123Smax.romanov@nginx.com     dec_pending = 0;
40311123Smax.romanov@nginx.com     got_response = 0;
40321123Smax.romanov@nginx.com 
40331123Smax.romanov@nginx.com     switch (action) {
40341123Smax.romanov@nginx.com     case NXT_APR_NEW_PORT:
40351123Smax.romanov@nginx.com         break;
40361123Smax.romanov@nginx.com     case NXT_APR_REQUEST_FAILED:
40371123Smax.romanov@nginx.com         dec_pending = 1;
40381123Smax.romanov@nginx.com         inc_use = -1;
40391123Smax.romanov@nginx.com         break;
40401123Smax.romanov@nginx.com     case NXT_APR_GOT_RESPONSE:
40411123Smax.romanov@nginx.com         dec_pending = 1;
40421123Smax.romanov@nginx.com         got_response = 1;
40431123Smax.romanov@nginx.com         inc_use = -1;
40441123Smax.romanov@nginx.com         break;
40451131Smax.romanov@nginx.com     case NXT_APR_UPGRADE:
40461131Smax.romanov@nginx.com         dec_pending = 1;
40471131Smax.romanov@nginx.com         got_response = 1;
40481131Smax.romanov@nginx.com         break;
40491123Smax.romanov@nginx.com     case NXT_APR_CLOSE:
40501123Smax.romanov@nginx.com         inc_use = -1;
40511123Smax.romanov@nginx.com         break;
40521123Smax.romanov@nginx.com     }
40531123Smax.romanov@nginx.com 
4054343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4055343Smax.romanov@nginx.com 
40561123Smax.romanov@nginx.com     port->app_pending_responses -= dec_pending;
4057343Smax.romanov@nginx.com     port->app_responses += got_response;
4058343Smax.romanov@nginx.com 
4059427Smax.romanov@nginx.com     if (port->pair[1] != -1
4060426Smax.romanov@nginx.com         && (app->max_pending_responses == 0
4061428Smax.romanov@nginx.com             || port->app_pending_responses < app->max_pending_responses)
4062428Smax.romanov@nginx.com         && (app->max_requests == 0
4063428Smax.romanov@nginx.com             || port->app_responses + port->app_pending_responses
4064428Smax.romanov@nginx.com                 < app->max_requests))
4065343Smax.romanov@nginx.com     {
4066424Smax.romanov@nginx.com         if (port->app_link.next == NULL) {
4067424Smax.romanov@nginx.com             if (port->app_pending_responses > 0) {
4068424Smax.romanov@nginx.com                 nxt_queue_insert_tail(&app->ports, &port->app_link);
4069424Smax.romanov@nginx.com 
4070424Smax.romanov@nginx.com             } else {
4071424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
4072424Smax.romanov@nginx.com             }
4073424Smax.romanov@nginx.com 
4074425Smax.romanov@nginx.com             nxt_port_inc_use(port);
4075424Smax.romanov@nginx.com 
4076424Smax.romanov@nginx.com         } else {
4077424Smax.romanov@nginx.com             if (port->app_pending_responses == 0
4078424Smax.romanov@nginx.com                 && nxt_queue_first(&app->ports) != &port->app_link)
4079424Smax.romanov@nginx.com             {
4080424Smax.romanov@nginx.com                 nxt_queue_remove(&port->app_link);
4081424Smax.romanov@nginx.com                 nxt_queue_insert_head(&app->ports, &port->app_link);
4082424Smax.romanov@nginx.com             }
4083424Smax.romanov@nginx.com         }
4084141Smax.romanov@nginx.com     }
4085141Smax.romanov@nginx.com 
4086427Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&app->ports)
4087426Smax.romanov@nginx.com         && !nxt_queue_is_empty(&app->requests))
4088343Smax.romanov@nginx.com     {
4089141Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->requests);
4090141Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4091343Smax.romanov@nginx.com         lnk->next = NULL;
4092141Smax.romanov@nginx.com 
40931123Smax.romanov@nginx.com         req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t,
40941123Smax.romanov@nginx.com                                            link_app_requests);
40951123Smax.romanov@nginx.com 
40961123Smax.romanov@nginx.com         req_app_link->app_port = nxt_router_pop_first_port(app);
40971123Smax.romanov@nginx.com 
40981123Smax.romanov@nginx.com         if (req_app_link->app_port->app_pending_responses > 1) {
40991123Smax.romanov@nginx.com             nxt_request_app_link_pending(task, app, req_app_link);
4100425Smax.romanov@nginx.com         }
4101425Smax.romanov@nginx.com     }
4102425Smax.romanov@nginx.com 
4103427Smax.romanov@nginx.com     /* Pop first pending request for this port. */
41041123Smax.romanov@nginx.com     if (dec_pending > 0
4105425Smax.romanov@nginx.com         && !nxt_queue_is_empty(&port->pending_requests))
4106425Smax.romanov@nginx.com     {
4107425Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
4108425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4109425Smax.romanov@nginx.com         lnk->next = NULL;
4110425Smax.romanov@nginx.com 
41111123Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
4112427Smax.romanov@nginx.com                                          link_port_pending);
4113427Smax.romanov@nginx.com 
4114427Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
4115427Smax.romanov@nginx.com 
4116427Smax.romanov@nginx.com         nxt_queue_remove(&pending_ra->link_app_pending);
4117427Smax.romanov@nginx.com         pending_ra->link_app_pending.next = NULL;
4118425Smax.romanov@nginx.com 
4119425Smax.romanov@nginx.com     } else {
4120427Smax.romanov@nginx.com         pending_ra = NULL;
4121141Smax.romanov@nginx.com     }
4122141Smax.romanov@nginx.com 
4123427Smax.romanov@nginx.com     /* Try to cancel and re-schedule first stalled request for this app. */
4124427Smax.romanov@nginx.com     if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) {
4125427Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->pending);
4126427Smax.romanov@nginx.com 
41271123Smax.romanov@nginx.com         re_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
41281123Smax.romanov@nginx.com                                     link_app_pending);
4129427Smax.romanov@nginx.com 
4130427Smax.romanov@nginx.com         if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) {
4131427Smax.romanov@nginx.com 
4132427Smax.romanov@nginx.com             nxt_debug(task, "app '%V' stalled request #%uD detected",
4133427Smax.romanov@nginx.com                       &app->name, re_ra->stream);
4134427Smax.romanov@nginx.com 
4135427Smax.romanov@nginx.com             cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info,
4136427Smax.romanov@nginx.com                                               re_ra->stream);
4137427Smax.romanov@nginx.com 
4138427Smax.romanov@nginx.com             if (cancelled) {
41391123Smax.romanov@nginx.com                 nxt_request_app_link_inc_use(re_ra);
41401123Smax.romanov@nginx.com 
41411123Smax.romanov@nginx.com                 state.req_app_link = re_ra;
4142427Smax.romanov@nginx.com                 state.app = app;
4143427Smax.romanov@nginx.com 
4144427Smax.romanov@nginx.com                 nxt_router_port_select(task, &state);
4145427Smax.romanov@nginx.com 
4146427Smax.romanov@nginx.com                 goto re_ra_cancelled;
4147427Smax.romanov@nginx.com             }
4148427Smax.romanov@nginx.com         }
4149427Smax.romanov@nginx.com     }
4150427Smax.romanov@nginx.com 
4151427Smax.romanov@nginx.com     re_ra = NULL;
4152427Smax.romanov@nginx.com 
4153427Smax.romanov@nginx.com re_ra_cancelled:
4154427Smax.romanov@nginx.com 
4155753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
4156753Smax.romanov@nginx.com                  && port->app_pending_responses == 0
4157753Smax.romanov@nginx.com                  && port->app_responses >= app->max_requests);
4158367Smax.romanov@nginx.com 
4159507Smax.romanov@nginx.com     if (send_quit) {
4160507Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&port->app_link);
4161507Smax.romanov@nginx.com 
4162507Smax.romanov@nginx.com         port->app = NULL;
4163507Smax.romanov@nginx.com         app->processes--;
4164507Smax.romanov@nginx.com 
4165507Smax.romanov@nginx.com     } else {
4166507Smax.romanov@nginx.com         port_unchained = 0;
4167507Smax.romanov@nginx.com     }
4168507Smax.romanov@nginx.com 
4169507Smax.romanov@nginx.com     adjust_idle_timer = 0;
4170507Smax.romanov@nginx.com 
41711131Smax.romanov@nginx.com     if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0
41721131Smax.romanov@nginx.com         && nxt_queue_is_empty(&port->active_websockets)
41731131Smax.romanov@nginx.com         && port->idle_link.next == NULL)
41741131Smax.romanov@nginx.com     {
4175507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
4176507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
4177507Smax.romanov@nginx.com         {
4178507Smax.romanov@nginx.com             adjust_idle_timer = 1;
4179507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
4180507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
4181507Smax.romanov@nginx.com         }
4182507Smax.romanov@nginx.com 
4183507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
4184507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
4185507Smax.romanov@nginx.com 
4186507Smax.romanov@nginx.com         } else {
4187507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &port->idle_link);
4188507Smax.romanov@nginx.com 
4189507Smax.romanov@nginx.com             port->idle_start = task->thread->engine->timers.now;
4190507Smax.romanov@nginx.com         }
4191507Smax.romanov@nginx.com 
4192507Smax.romanov@nginx.com         app->idle_processes++;
4193507Smax.romanov@nginx.com     }
4194507Smax.romanov@nginx.com 
4195343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4196343Smax.romanov@nginx.com 
4197507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4198507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4199507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4200507Smax.romanov@nginx.com     }
4201507Smax.romanov@nginx.com 
4202427Smax.romanov@nginx.com     if (pending_ra != NULL) {
42031123Smax.romanov@nginx.com         nxt_request_app_link_use(task, pending_ra, -1);
4204427Smax.romanov@nginx.com     }
4205427Smax.romanov@nginx.com 
4206427Smax.romanov@nginx.com     if (re_ra != NULL) {
4207427Smax.romanov@nginx.com         if (nxt_router_port_post_select(task, &state) == NXT_OK) {
4208427Smax.romanov@nginx.com             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4209427Smax.romanov@nginx.com                                nxt_router_app_process_request,
4210427Smax.romanov@nginx.com                                &task->thread->engine->task, app, re_ra);
4211427Smax.romanov@nginx.com         }
4212425Smax.romanov@nginx.com     }
4213425Smax.romanov@nginx.com 
42141123Smax.romanov@nginx.com     if (req_app_link != NULL) {
42151123Smax.romanov@nginx.com         nxt_request_app_link_use(task, req_app_link, -1);
4216425Smax.romanov@nginx.com 
4217343Smax.romanov@nginx.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4218343Smax.romanov@nginx.com                            nxt_router_app_process_request,
42191123Smax.romanov@nginx.com                            &task->thread->engine->task, app, req_app_link);
4220343Smax.romanov@nginx.com 
4221343Smax.romanov@nginx.com         goto adjust_use;
4222343Smax.romanov@nginx.com     }
4223343Smax.romanov@nginx.com 
4224343Smax.romanov@nginx.com     /* ? */
4225163Smax.romanov@nginx.com     if (port->pair[1] == -1) {
4226343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4227343Smax.romanov@nginx.com                   &app->name, app, port, port->pid);
4228343Smax.romanov@nginx.com 
4229343Smax.romanov@nginx.com         goto adjust_use;
4230163Smax.romanov@nginx.com     }
4231163Smax.romanov@nginx.com 
4232367Smax.romanov@nginx.com     if (send_quit) {
4233507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port",
4234167Smax.romanov@nginx.com                   &app->name, app);
4235163Smax.romanov@nginx.com 
4236163Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
4237163Smax.romanov@nginx.com                               -1, 0, 0, NULL);
4238163Smax.romanov@nginx.com 
4239507Smax.romanov@nginx.com         if (port_unchained) {
4240507Smax.romanov@nginx.com             nxt_port_use(task, port, -1);
4241507Smax.romanov@nginx.com         }
4242507Smax.romanov@nginx.com 
4243343Smax.romanov@nginx.com         goto adjust_use;
4244163Smax.romanov@nginx.com     }
4245163Smax.romanov@nginx.com 
4246167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4247167Smax.romanov@nginx.com               &app->name, app);
4248141Smax.romanov@nginx.com 
4249343Smax.romanov@nginx.com adjust_use:
4250343Smax.romanov@nginx.com 
42511123Smax.romanov@nginx.com     nxt_port_use(task, port, inc_use);
4252141Smax.romanov@nginx.com }
4253141Smax.romanov@nginx.com 
4254141Smax.romanov@nginx.com 
4255343Smax.romanov@nginx.com void
4256343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4257141Smax.romanov@nginx.com {
4258507Smax.romanov@nginx.com     nxt_app_t         *app;
4259507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4260507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4261507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4262141Smax.romanov@nginx.com 
4263141Smax.romanov@nginx.com     app = port->app;
4264343Smax.romanov@nginx.com 
4265343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4266141Smax.romanov@nginx.com 
4267141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4268141Smax.romanov@nginx.com 
4269507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4270507Smax.romanov@nginx.com 
4271507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4272507Smax.romanov@nginx.com         app->idle_processes--;
4273507Smax.romanov@nginx.com 
4274507Smax.romanov@nginx.com         if (port->idle_start == 0
4275507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4276507Smax.romanov@nginx.com         {
4277507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4278507Smax.romanov@nginx.com 
4279507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4280507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4281507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4282507Smax.romanov@nginx.com 
4283507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4284507Smax.romanov@nginx.com 
4285507Smax.romanov@nginx.com             idle_port->idle_start = 0;
4286507Smax.romanov@nginx.com         }
4287343Smax.romanov@nginx.com     }
4288343Smax.romanov@nginx.com 
4289507Smax.romanov@nginx.com     app->processes--;
4290507Smax.romanov@nginx.com 
4291753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4292507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
4293507Smax.romanov@nginx.com                     && (!nxt_queue_is_empty(&app->requests)
4294507Smax.romanov@nginx.com                         || nxt_router_app_need_start(app));
4295507Smax.romanov@nginx.com 
4296507Smax.romanov@nginx.com     if (start_process) {
4297507Smax.romanov@nginx.com         app->pending_processes++;
4298163Smax.romanov@nginx.com     }
4299141Smax.romanov@nginx.com 
4300141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4301163Smax.romanov@nginx.com 
4302507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4303343Smax.romanov@nginx.com 
4304343Smax.romanov@nginx.com     if (unchain) {
4305343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4306163Smax.romanov@nginx.com     }
4307163Smax.romanov@nginx.com 
4308507Smax.romanov@nginx.com     if (start_process) {
4309507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4310507Smax.romanov@nginx.com     }
4311507Smax.romanov@nginx.com }
4312507Smax.romanov@nginx.com 
4313507Smax.romanov@nginx.com 
4314507Smax.romanov@nginx.com static void
4315507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4316507Smax.romanov@nginx.com {
4317507Smax.romanov@nginx.com     nxt_app_t           *app;
4318507Smax.romanov@nginx.com     nxt_bool_t          queued;
4319507Smax.romanov@nginx.com     nxt_port_t          *port;
4320507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4321507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4322507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4323507Smax.romanov@nginx.com 
4324507Smax.romanov@nginx.com     app = obj;
4325507Smax.romanov@nginx.com     queued = (data == app);
4326507Smax.romanov@nginx.com 
4327507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4328507Smax.romanov@nginx.com               &app->name, queued);
4329507Smax.romanov@nginx.com 
4330507Smax.romanov@nginx.com     engine = task->thread->engine;
4331507Smax.romanov@nginx.com 
4332507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
4333507Smax.romanov@nginx.com 
4334811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
4335507Smax.romanov@nginx.com     timeout = 0;
4336507Smax.romanov@nginx.com 
4337507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4338507Smax.romanov@nginx.com 
4339507Smax.romanov@nginx.com     if (queued) {
4340507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
4341343Smax.romanov@nginx.com     }
4342507Smax.romanov@nginx.com 
4343507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
4344507Smax.romanov@nginx.com 
4345551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4346507Smax.romanov@nginx.com 
4347507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
4348507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4349507Smax.romanov@nginx.com 
4350507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
4351507Smax.romanov@nginx.com 
4352507Smax.romanov@nginx.com         if (timeout > threshold) {
4353507Smax.romanov@nginx.com             break;
4354507Smax.romanov@nginx.com         }
4355507Smax.romanov@nginx.com 
4356507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4357507Smax.romanov@nginx.com         lnk->next = NULL;
4358507Smax.romanov@nginx.com 
4359507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4360507Smax.romanov@nginx.com 
4361507Smax.romanov@nginx.com         app->idle_processes--;
4362507Smax.romanov@nginx.com         app->processes--;
4363507Smax.romanov@nginx.com         port->app = NULL;
4364507Smax.romanov@nginx.com 
4365507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4366507Smax.romanov@nginx.com 
4367507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4368507Smax.romanov@nginx.com                   &app->name, port->pid);
4369507Smax.romanov@nginx.com 
4370507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4371507Smax.romanov@nginx.com 
4372507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4373507Smax.romanov@nginx.com 
4374507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4375507Smax.romanov@nginx.com     }
4376507Smax.romanov@nginx.com 
4377507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4378507Smax.romanov@nginx.com 
4379507Smax.romanov@nginx.com     if (timeout > threshold) {
4380753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4381507Smax.romanov@nginx.com 
4382507Smax.romanov@nginx.com     } else {
4383753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4384507Smax.romanov@nginx.com     }
4385507Smax.romanov@nginx.com 
4386507Smax.romanov@nginx.com     if (queued) {
4387507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4388507Smax.romanov@nginx.com     }
4389507Smax.romanov@nginx.com }
4390507Smax.romanov@nginx.com 
4391507Smax.romanov@nginx.com 
4392507Smax.romanov@nginx.com static void
4393507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4394507Smax.romanov@nginx.com {
4395753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4396753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4397507Smax.romanov@nginx.com 
4398507Smax.romanov@nginx.com     timer = obj;
4399753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4400753Smax.romanov@nginx.com 
4401753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4402753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4403753Smax.romanov@nginx.com     }
4404753Smax.romanov@nginx.com }
4405753Smax.romanov@nginx.com 
4406753Smax.romanov@nginx.com 
4407753Smax.romanov@nginx.com static void
4408753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4409753Smax.romanov@nginx.com {
4410753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4411753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4412753Smax.romanov@nginx.com 
4413753Smax.romanov@nginx.com     timer = obj;
4414753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4415753Smax.romanov@nginx.com 
4416753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4417507Smax.romanov@nginx.com }
4418507Smax.romanov@nginx.com 
4419507Smax.romanov@nginx.com 
4420507Smax.romanov@nginx.com static void
4421753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4422507Smax.romanov@nginx.com {
4423753Smax.romanov@nginx.com     nxt_app_t        *app;
4424753Smax.romanov@nginx.com     nxt_port_t       *port;
4425753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4426753Smax.romanov@nginx.com 
4427753Smax.romanov@nginx.com     app_joint = obj;
4428753Smax.romanov@nginx.com     app = app_joint->app;
4429753Smax.romanov@nginx.com 
4430753Smax.romanov@nginx.com     for ( ;; ) {
4431753Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(app);
4432753Smax.romanov@nginx.com         if (port == NULL) {
4433753Smax.romanov@nginx.com             break;
4434753Smax.romanov@nginx.com         }
4435753Smax.romanov@nginx.com 
4436753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4437753Smax.romanov@nginx.com 
4438753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4439753Smax.romanov@nginx.com 
4440753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4441753Smax.romanov@nginx.com     }
4442753Smax.romanov@nginx.com 
4443753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
4444753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4445753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->requests));
4446753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4447753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4448753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4449753Smax.romanov@nginx.com 
4450753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
4451753Smax.romanov@nginx.com     nxt_free(app);
4452753Smax.romanov@nginx.com 
4453753Smax.romanov@nginx.com     app_joint->app = NULL;
4454753Smax.romanov@nginx.com 
4455753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4456753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4457753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4458753Smax.romanov@nginx.com 
4459753Smax.romanov@nginx.com     } else {
4460753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4461753Smax.romanov@nginx.com     }
4462141Smax.romanov@nginx.com }
4463141Smax.romanov@nginx.com 
4464141Smax.romanov@nginx.com 
4465427Smax.romanov@nginx.com static void
4466427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state)
4467141Smax.romanov@nginx.com {
44681123Smax.romanov@nginx.com     nxt_app_t               *app;
44691123Smax.romanov@nginx.com     nxt_bool_t              can_start_process;
44701123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
44711123Smax.romanov@nginx.com 
44721123Smax.romanov@nginx.com     req_app_link = state->req_app_link;
4473427Smax.romanov@nginx.com     app = state->app;
4474427Smax.romanov@nginx.com 
4475427Smax.romanov@nginx.com     state->failed_port_use_delta = 0;
4476343Smax.romanov@nginx.com 
44771123Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&req_app_link->link_app_requests))
4478425Smax.romanov@nginx.com     {
44791123Smax.romanov@nginx.com         nxt_request_app_link_dec_use(req_app_link);
44801123Smax.romanov@nginx.com     }
44811123Smax.romanov@nginx.com 
44821123Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&req_app_link->link_port_pending))
4483425Smax.romanov@nginx.com     {
44841123Smax.romanov@nginx.com         nxt_assert(req_app_link->link_app_pending.next != NULL);
44851123Smax.romanov@nginx.com 
44861123Smax.romanov@nginx.com         nxt_queue_remove(&req_app_link->link_app_pending);
44871123Smax.romanov@nginx.com         req_app_link->link_app_pending.next = NULL;
44881123Smax.romanov@nginx.com 
44891123Smax.romanov@nginx.com         nxt_request_app_link_dec_use(req_app_link);
44901123Smax.romanov@nginx.com     }
44911123Smax.romanov@nginx.com 
44921123Smax.romanov@nginx.com     state->failed_port = req_app_link->app_port;
44931123Smax.romanov@nginx.com 
44941123Smax.romanov@nginx.com     if (req_app_link->app_port != NULL) {
4495427Smax.romanov@nginx.com         state->failed_port_use_delta--;
4496427Smax.romanov@nginx.com 
4497427Smax.romanov@nginx.com         state->failed_port->app_pending_responses--;
4498427Smax.romanov@nginx.com 
4499427Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&state->failed_port->app_link)) {
4500427Smax.romanov@nginx.com             state->failed_port_use_delta--;
4501427Smax.romanov@nginx.com         }
4502427Smax.romanov@nginx.com 
45031123Smax.romanov@nginx.com         req_app_link->app_port = NULL;
4504427Smax.romanov@nginx.com     }
4505427Smax.romanov@nginx.com 
4506507Smax.romanov@nginx.com     can_start_process = nxt_router_app_can_start(app);
4507507Smax.romanov@nginx.com 
4508427Smax.romanov@nginx.com     state->port = NULL;
4509507Smax.romanov@nginx.com     state->start_process = 0;
4510427Smax.romanov@nginx.com 
4511427Smax.romanov@nginx.com     if (nxt_queue_is_empty(&app->ports)
4512507Smax.romanov@nginx.com         || (can_start_process && nxt_router_app_first_port_busy(app)) )
4513427Smax.romanov@nginx.com     {
45141123Smax.romanov@nginx.com         req_app_link = nxt_request_app_link_alloc(task, req_app_link,
45151123Smax.romanov@nginx.com                                                   req_app_link->req_rpc_data);
45161123Smax.romanov@nginx.com         if (nxt_slow_path(req_app_link == NULL)) {
4517427Smax.romanov@nginx.com             goto fail;
4518427Smax.romanov@nginx.com         }
4519427Smax.romanov@nginx.com 
4520427Smax.romanov@nginx.com         if (nxt_slow_path(state->failed_port != NULL)) {
45211123Smax.romanov@nginx.com             nxt_queue_insert_head(&app->requests,
45221123Smax.romanov@nginx.com                                   &req_app_link->link_app_requests);
4523427Smax.romanov@nginx.com 
4524427Smax.romanov@nginx.com         } else {
45251123Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->requests,
45261123Smax.romanov@nginx.com                                   &req_app_link->link_app_requests);
4527427Smax.romanov@nginx.com         }
4528427Smax.romanov@nginx.com 
45291123Smax.romanov@nginx.com         nxt_request_app_link_inc_use(req_app_link);
45301123Smax.romanov@nginx.com 
45311123Smax.romanov@nginx.com         nxt_debug(task, "req_app_link stream #%uD enqueue to app->requests",
45321123Smax.romanov@nginx.com                   req_app_link->stream);
4533427Smax.romanov@nginx.com 
4534507Smax.romanov@nginx.com         if (can_start_process) {
4535507Smax.romanov@nginx.com             app->pending_processes++;
4536507Smax.romanov@nginx.com             state->start_process = 1;
4537425Smax.romanov@nginx.com         }
4538425Smax.romanov@nginx.com 
4539425Smax.romanov@nginx.com     } else {
4540427Smax.romanov@nginx.com         state->port = nxt_router_pop_first_port(app);
4541427Smax.romanov@nginx.com 
4542427Smax.romanov@nginx.com         if (state->port->app_pending_responses > 1) {
45431123Smax.romanov@nginx.com             req_app_link = nxt_request_app_link_alloc(task, req_app_link,
45441123Smax.romanov@nginx.com                                                     req_app_link->req_rpc_data);
45451123Smax.romanov@nginx.com             if (nxt_slow_path(req_app_link == NULL)) {
4546427Smax.romanov@nginx.com                 goto fail;
4547351Smax.romanov@nginx.com             }
4548427Smax.romanov@nginx.com 
45491123Smax.romanov@nginx.com             req_app_link->app_port = state->port;
45501123Smax.romanov@nginx.com 
45511123Smax.romanov@nginx.com             nxt_request_app_link_pending(task, app, req_app_link);
4552425Smax.romanov@nginx.com         }
4553507Smax.romanov@nginx.com 
4554507Smax.romanov@nginx.com         if (can_start_process && nxt_router_app_need_start(app)) {
4555507Smax.romanov@nginx.com             app->pending_processes++;
4556507Smax.romanov@nginx.com             state->start_process = 1;
4557507Smax.romanov@nginx.com         }
4558343Smax.romanov@nginx.com     }
4559343Smax.romanov@nginx.com 
4560427Smax.romanov@nginx.com fail:
4561427Smax.romanov@nginx.com 
45621123Smax.romanov@nginx.com     state->shared_ra = req_app_link;
4563427Smax.romanov@nginx.com }
4564427Smax.romanov@nginx.com 
4565427Smax.romanov@nginx.com 
4566427Smax.romanov@nginx.com static nxt_int_t
4567427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state)
4568427Smax.romanov@nginx.com {
45691123Smax.romanov@nginx.com     nxt_int_t               res;
45701123Smax.romanov@nginx.com     nxt_app_t               *app;
45711123Smax.romanov@nginx.com     nxt_request_app_link_t  *req_app_link;
45721123Smax.romanov@nginx.com 
45731123Smax.romanov@nginx.com     req_app_link = state->shared_ra;
4574427Smax.romanov@nginx.com     app = state->app;
4575427Smax.romanov@nginx.com 
4576427Smax.romanov@nginx.com     if (state->failed_port_use_delta != 0) {
4577427Smax.romanov@nginx.com         nxt_port_use(task, state->failed_port, state->failed_port_use_delta);
4578425Smax.romanov@nginx.com     }
4579425Smax.romanov@nginx.com 
45801123Smax.romanov@nginx.com     if (nxt_slow_path(req_app_link == NULL)) {
4581427Smax.romanov@nginx.com         if (state->port != NULL) {
4582427Smax.romanov@nginx.com             nxt_port_use(task, state->port, -1);
4583425Smax.romanov@nginx.com         }
4584425Smax.romanov@nginx.com 
45851123Smax.romanov@nginx.com         nxt_request_app_link_error(state->req_app_link, 500,
4586427Smax.romanov@nginx.com                             "Failed to allocate shared req<->app link");
45871123Smax.romanov@nginx.com         nxt_request_app_link_use(task, state->req_app_link, -1);
4588427Smax.romanov@nginx.com 
4589351Smax.romanov@nginx.com         return NXT_ERROR;
4590351Smax.romanov@nginx.com     }
4591351Smax.romanov@nginx.com 
4592427Smax.romanov@nginx.com     if (state->port != NULL) {
4593343Smax.romanov@nginx.com         nxt_debug(task, "already have port for app '%V' %p ", &app->name, app);
4594163Smax.romanov@nginx.com 
45951123Smax.romanov@nginx.com         req_app_link->app_port = state->port;
4596343Smax.romanov@nginx.com 
4597507Smax.romanov@nginx.com         if (state->start_process) {
4598507Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
4599507Smax.romanov@nginx.com         }
4600507Smax.romanov@nginx.com 
4601141Smax.romanov@nginx.com         return NXT_OK;
4602141Smax.romanov@nginx.com     }
4603141Smax.romanov@nginx.com 
4604507Smax.romanov@nginx.com     if (!state->start_process) {
4605507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p too many running or pending processes",
4606343Smax.romanov@nginx.com                   &app->name, app);
4607343Smax.romanov@nginx.com 
4608343Smax.romanov@nginx.com         return NXT_AGAIN;
4609343Smax.romanov@nginx.com     }
4610343Smax.romanov@nginx.com 
4611507Smax.romanov@nginx.com     res = nxt_router_start_app_process(task, app);
4612343Smax.romanov@nginx.com 
4613343Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
46141123Smax.romanov@nginx.com         nxt_request_app_link_error(req_app_link, 500,
46151123Smax.romanov@nginx.com                                    "Failed to start app process");
46161123Smax.romanov@nginx.com         nxt_request_app_link_use(task, req_app_link, -1);
4617343Smax.romanov@nginx.com 
4618141Smax.romanov@nginx.com         return NXT_ERROR;
4619141Smax.romanov@nginx.com     }
4620141Smax.romanov@nginx.com 
4621141Smax.romanov@nginx.com     return NXT_AGAIN;
462288Smax.romanov@nginx.com }
462388Smax.romanov@nginx.com 
462488Smax.romanov@nginx.com 
4625427Smax.romanov@nginx.com static nxt_int_t
46261123Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
46271123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
4628427Smax.romanov@nginx.com {
4629427Smax.romanov@nginx.com     nxt_port_select_state_t  state;
4630427Smax.romanov@nginx.com 
46311123Smax.romanov@nginx.com     state.req_app_link = req_app_link;
4632427Smax.romanov@nginx.com     state.app = app;
4633427Smax.romanov@nginx.com 
4634427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4635427Smax.romanov@nginx.com 
4636427Smax.romanov@nginx.com     nxt_router_port_select(task, &state);
4637427Smax.romanov@nginx.com 
4638427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4639427Smax.romanov@nginx.com 
4640427Smax.romanov@nginx.com     return nxt_router_port_post_select(task, &state);
4641427Smax.romanov@nginx.com }
4642427Smax.romanov@nginx.com 
4643427Smax.romanov@nginx.com 
4644431Sigor@sysoev.ru void
46451007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
4646964Sigor@sysoev.ru     nxt_app_t *app)
464753Sigor@sysoev.ru {
46481123Smax.romanov@nginx.com     nxt_int_t               res;
46491123Smax.romanov@nginx.com     nxt_port_t              *port;
46501123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
46511123Smax.romanov@nginx.com     nxt_request_app_link_t  ra_local, *req_app_link;
46521123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
4653431Sigor@sysoev.ru 
465488Smax.romanov@nginx.com     engine = task->thread->engine;
465588Smax.romanov@nginx.com 
46561123Smax.romanov@nginx.com     req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
4657318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4658318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
46591123Smax.romanov@nginx.com                                           sizeof(nxt_request_rpc_data_t));
46601123Smax.romanov@nginx.com     if (nxt_slow_path(req_rpc_data == NULL)) {
4661431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4662141Smax.romanov@nginx.com         return;
466388Smax.romanov@nginx.com     }
466488Smax.romanov@nginx.com 
46651123Smax.romanov@nginx.com     req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
46661123Smax.romanov@nginx.com     req_rpc_data->app = app;
4667425Smax.romanov@nginx.com 
4668425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4669425Smax.romanov@nginx.com 
46701123Smax.romanov@nginx.com     req_rpc_data->request = r;
46711131Smax.romanov@nginx.com     r->req_rpc_data = req_rpc_data;
46721123Smax.romanov@nginx.com 
46731123Smax.romanov@nginx.com     req_app_link = &ra_local;
46741123Smax.romanov@nginx.com     nxt_request_app_link_init(task, req_app_link, req_rpc_data);
46751123Smax.romanov@nginx.com 
46761123Smax.romanov@nginx.com     res = nxt_router_app_port(task, app, req_app_link);
4677141Smax.romanov@nginx.com 
4678141Smax.romanov@nginx.com     if (res != NXT_OK) {
4679141Smax.romanov@nginx.com         return;
4680141Smax.romanov@nginx.com     }
4681141Smax.romanov@nginx.com 
46821123Smax.romanov@nginx.com     req_app_link = req_rpc_data->req_app_link;
46831123Smax.romanov@nginx.com     port = req_app_link->app_port;
4684141Smax.romanov@nginx.com 
4685425Smax.romanov@nginx.com     nxt_assert(port != NULL);
4686141Smax.romanov@nginx.com 
46871123Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, port->pid);
46881123Smax.romanov@nginx.com 
46891123Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, req_app_link);
4690167Smax.romanov@nginx.com }
4691167Smax.romanov@nginx.com 
4692167Smax.romanov@nginx.com 
4693167Smax.romanov@nginx.com static void
4694423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4695423Smax.romanov@nginx.com {
4696423Smax.romanov@nginx.com }
4697423Smax.romanov@nginx.com 
4698423Smax.romanov@nginx.com 
4699423Smax.romanov@nginx.com static void
47001123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task,
47011123Smax.romanov@nginx.com     nxt_request_app_link_t *req_app_link)
4702167Smax.romanov@nginx.com {
47031123Smax.romanov@nginx.com     nxt_buf_t         *buf;
47041123Smax.romanov@nginx.com     nxt_int_t         res;
47051123Smax.romanov@nginx.com     nxt_port_t        *port, *c_port, *reply_port;
47061123Smax.romanov@nginx.com     nxt_apr_action_t  apr_action;
47071123Smax.romanov@nginx.com 
47081123Smax.romanov@nginx.com     nxt_assert(req_app_link->app_port != NULL);
47091123Smax.romanov@nginx.com 
47101123Smax.romanov@nginx.com     port = req_app_link->app_port;
47111123Smax.romanov@nginx.com     reply_port = req_app_link->reply_port;
47121123Smax.romanov@nginx.com 
47131123Smax.romanov@nginx.com     apr_action = NXT_APR_REQUEST_FAILED;
4714343Smax.romanov@nginx.com 
4715141Smax.romanov@nginx.com     c_port = nxt_process_connected_port_find(port->process, reply_port->pid,
4716141Smax.romanov@nginx.com                                              reply_port->id);
4717141Smax.romanov@nginx.com     if (nxt_slow_path(c_port != reply_port)) {
4718141Smax.romanov@nginx.com         res = nxt_port_send_port(task, port, reply_port, 0);
4719122Smax.romanov@nginx.com 
4720122Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
47211123Smax.romanov@nginx.com             nxt_request_app_link_error(req_app_link, 500,
4722345Smax.romanov@nginx.com                                 "Failed to send reply port to application");
4723343Smax.romanov@nginx.com             goto release_port;
4724122Smax.romanov@nginx.com         }
4725122Smax.romanov@nginx.com 
4726141Smax.romanov@nginx.com         nxt_process_connected_port_add(port->process, reply_port);
472788Smax.romanov@nginx.com     }
472888Smax.romanov@nginx.com 
47291123Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, req_app_link->request, port,
4730743Smax.romanov@nginx.com                                  nxt_app_msg_prefix[port->app->type]);
4731743Smax.romanov@nginx.com 
4732743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
47331123Smax.romanov@nginx.com         nxt_request_app_link_error(req_app_link, 500,
4734345Smax.romanov@nginx.com                             "Failed to prepare message for application");
4735343Smax.romanov@nginx.com         goto release_port;
4736122Smax.romanov@nginx.com     }
473788Smax.romanov@nginx.com 
4738507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4739743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4740743Smax.romanov@nginx.com                     port->socket.fd);
474188Smax.romanov@nginx.com 
47421123Smax.romanov@nginx.com     apr_action = NXT_APR_NEW_PORT;
47431123Smax.romanov@nginx.com 
47441123Smax.romanov@nginx.com     req_app_link->msg_info.buf = buf;
47451123Smax.romanov@nginx.com     req_app_link->msg_info.completion_handler = buf->completion_handler;
4746743Smax.romanov@nginx.com 
4747743Smax.romanov@nginx.com     for (; buf; buf = buf->next) {
4748743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
4749423Smax.romanov@nginx.com     }
4750423Smax.romanov@nginx.com 
47511123Smax.romanov@nginx.com     buf = req_app_link->msg_info.buf;
47521123Smax.romanov@nginx.com 
47531123Smax.romanov@nginx.com     res = nxt_port_mmap_get_tracking(task, port,
47541123Smax.romanov@nginx.com                                      &req_app_link->msg_info.tracking,
47551123Smax.romanov@nginx.com                                      req_app_link->stream);
4756423Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
47571123Smax.romanov@nginx.com         nxt_request_app_link_error(req_app_link, 500,
47581123Smax.romanov@nginx.com                                    "Failed to get tracking area");
4759423Smax.romanov@nginx.com         goto release_port;
4760423Smax.romanov@nginx.com     }
4761423Smax.romanov@nginx.com 
47621131Smax.romanov@nginx.com     res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_REQ_HEADERS,
47631123Smax.romanov@nginx.com                                  -1, req_app_link->stream, reply_port->id, buf,
47641123Smax.romanov@nginx.com                                  &req_app_link->msg_info.tracking);
4765122Smax.romanov@nginx.com 
4766122Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_OK)) {
47671123Smax.romanov@nginx.com         nxt_request_app_link_error(req_app_link, 500,
47681123Smax.romanov@nginx.com                                    "Failed to send message to application");
4769343Smax.romanov@nginx.com         goto release_port;
4770122Smax.romanov@nginx.com     }
4771343Smax.romanov@nginx.com 
4772343Smax.romanov@nginx.com release_port:
4773343Smax.romanov@nginx.com 
47741123Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, apr_action);
47751123Smax.romanov@nginx.com 
47761123Smax.romanov@nginx.com     nxt_request_app_link_update_peer(task, req_app_link);
477753Sigor@sysoev.ru }
477853Sigor@sysoev.ru 
477953Sigor@sysoev.ru 
4780743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4781743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4782743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4783743Smax.romanov@nginx.com };
4784743Smax.romanov@nginx.com 
4785743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4786743Smax.romanov@nginx.com 
4787743Smax.romanov@nginx.com 
4788743Smax.romanov@nginx.com static nxt_http_field_t *
4789743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4790216Sigor@sysoev.ru {
4791743Smax.romanov@nginx.com     if (part == NULL) {
4792743Smax.romanov@nginx.com         return NULL;
4793216Sigor@sysoev.ru     }
4794216Sigor@sysoev.ru 
4795743Smax.romanov@nginx.com     while (part->nelts == 0) {
4796743Smax.romanov@nginx.com         part = part->next;
4797743Smax.romanov@nginx.com         if (part == NULL) {
4798743Smax.romanov@nginx.com             return NULL;
4799743Smax.romanov@nginx.com         }
4800216Sigor@sysoev.ru     }
4801216Sigor@sysoev.ru 
4802743Smax.romanov@nginx.com     i->part = part;
4803743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4804743Smax.romanov@nginx.com 
4805743Smax.romanov@nginx.com     return i->field;
4806743Smax.romanov@nginx.com }
4807743Smax.romanov@nginx.com 
4808743Smax.romanov@nginx.com 
4809743Smax.romanov@nginx.com static nxt_http_field_t *
4810743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4811743Smax.romanov@nginx.com {
4812743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4813743Smax.romanov@nginx.com }
4814743Smax.romanov@nginx.com 
4815743Smax.romanov@nginx.com 
4816743Smax.romanov@nginx.com static nxt_http_field_t *
4817743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4818743Smax.romanov@nginx.com {
4819743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4820743Smax.romanov@nginx.com 
4821743Smax.romanov@nginx.com     end += i->part->nelts;
4822743Smax.romanov@nginx.com     i->field++;
4823743Smax.romanov@nginx.com 
4824743Smax.romanov@nginx.com     if (i->field < end) {
4825743Smax.romanov@nginx.com         return i->field;
4826216Sigor@sysoev.ru     }
4827216Sigor@sysoev.ru 
4828743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4829216Sigor@sysoev.ru }
4830216Sigor@sysoev.ru 
4831216Sigor@sysoev.ru 
4832743Smax.romanov@nginx.com static nxt_buf_t *
48331007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
4834743Smax.romanov@nginx.com     nxt_port_t *port, const nxt_str_t *prefix)
4835216Sigor@sysoev.ru {
48361007Salexander.borisov@nginx.com     void                *target_pos, *query_pos;
48371007Salexander.borisov@nginx.com     u_char              *pos, *end, *p, c;
48381007Salexander.borisov@nginx.com     size_t              fields_count, req_size, size, free_size;
48391007Salexander.borisov@nginx.com     size_t              copy_size;
48401007Salexander.borisov@nginx.com     nxt_off_t           content_length;
48411007Salexander.borisov@nginx.com     nxt_buf_t           *b, *buf, *out, **tail;
48421007Salexander.borisov@nginx.com     nxt_http_field_t    *field, *dup;
48431007Salexander.borisov@nginx.com     nxt_unit_field_t    *dst_field;
48441007Salexander.borisov@nginx.com     nxt_fields_iter_t   iter, dup_iter;
48451007Salexander.borisov@nginx.com     nxt_unit_request_t  *req;
4846216Sigor@sysoev.ru 
4847743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
48481007Salexander.borisov@nginx.com                + r->method->length + 1
48491007Salexander.borisov@nginx.com                + r->version.length + 1
48501007Salexander.borisov@nginx.com                + r->remote->length + 1
48511007Salexander.borisov@nginx.com                + r->local->length + 1
48521007Salexander.borisov@nginx.com                + r->server_name.length + 1
48531007Salexander.borisov@nginx.com                + r->target.length + 1
48541007Salexander.borisov@nginx.com                + (r->path->start != r->target.start ? r->path->length + 1 : 0);
48551007Salexander.borisov@nginx.com 
48561007Salexander.borisov@nginx.com     content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
4857743Smax.romanov@nginx.com     fields_count = 0;
4858743Smax.romanov@nginx.com 
48591007Salexander.borisov@nginx.com     nxt_list_each(field, r->fields) {
4860743Smax.romanov@nginx.com         fields_count++;
4861743Smax.romanov@nginx.com 
4862743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4863743Smax.romanov@nginx.com                     + field->value_length + 1;
4864743Smax.romanov@nginx.com     } nxt_list_loop;
4865743Smax.romanov@nginx.com 
4866743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4867743Smax.romanov@nginx.com 
4868743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4869743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4870743Smax.romanov@nginx.com                   (int) req_size);
4871743Smax.romanov@nginx.com 
4872743Smax.romanov@nginx.com         return NULL;
4873743Smax.romanov@nginx.com     }
4874743Smax.romanov@nginx.com 
4875743Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, port,
48761007Salexander.borisov@nginx.com               nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
4877743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4878743Smax.romanov@nginx.com         return NULL;
4879743Smax.romanov@nginx.com     }
4880743Smax.romanov@nginx.com 
4881743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4882743Smax.romanov@nginx.com     out->mem.free += req_size;
4883743Smax.romanov@nginx.com 
48841007Salexander.borisov@nginx.com     req->content_length = content_length;
4885743Smax.romanov@nginx.com 
4886743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4887743Smax.romanov@nginx.com 
4888743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4889743Smax.romanov@nginx.com 
48901007Salexander.borisov@nginx.com     req->method_length = r->method->length;
4891743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
48921007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->method->start, r->method->length);
4893743Smax.romanov@nginx.com     *p++ = '\0';
4894743Smax.romanov@nginx.com 
48951007Salexander.borisov@nginx.com     req->version_length = r->version.length;
4896743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
48971007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->version.start, r->version.length);
4898743Smax.romanov@nginx.com     *p++ = '\0';
4899743Smax.romanov@nginx.com 
49001007Salexander.borisov@nginx.com     req->remote_length = r->remote->address_length;
4901743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
49021007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
49031007Salexander.borisov@nginx.com                    r->remote->address_length);
4904743Smax.romanov@nginx.com     *p++ = '\0';
4905743Smax.romanov@nginx.com 
49061007Salexander.borisov@nginx.com     req->local_length = r->local->address_length;
4907743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
49081007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
4909743Smax.romanov@nginx.com     *p++ = '\0';
4910743Smax.romanov@nginx.com 
49111011Smax.romanov@nginx.com     req->tls = (r->tls != NULL);
49121131Smax.romanov@nginx.com     req->websocket_handshake = r->websocket_handshake;
49131011Smax.romanov@nginx.com 
49141007Salexander.borisov@nginx.com     req->server_name_length = r->server_name.length;
4915967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
49161007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
4917967Svbart@nginx.com     *p++ = '\0';
4918967Svbart@nginx.com 
4919743Smax.romanov@nginx.com     target_pos = p;
49201007Salexander.borisov@nginx.com     req->target_length = (uint32_t) r->target.length;
4921743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
49221007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->target.start, r->target.length);
4923743Smax.romanov@nginx.com     *p++ = '\0';
4924743Smax.romanov@nginx.com 
49251007Salexander.borisov@nginx.com     req->path_length = (uint32_t) r->path->length;
49261007Salexander.borisov@nginx.com     if (r->path->start == r->target.start) {
4927743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
4928277Sigor@sysoev.ru 
4929216Sigor@sysoev.ru     } else {
4930743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
49311007Salexander.borisov@nginx.com         p = nxt_cpymem(p, r->path->start, r->path->length);
4932743Smax.romanov@nginx.com         *p++ = '\0';
4933305Smax.romanov@nginx.com     }
4934216Sigor@sysoev.ru 
49351007Salexander.borisov@nginx.com     req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
49361007Salexander.borisov@nginx.com     if (r->args != NULL && r->args->start != NULL) {
4937743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
49381007Salexander.borisov@nginx.com                                    r->args->start - r->target.start);
4939743Smax.romanov@nginx.com 
4940743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
4941277Sigor@sysoev.ru 
4942216Sigor@sysoev.ru     } else {
4943743Smax.romanov@nginx.com         req->query.offset = 0;
4944216Sigor@sysoev.ru     }
4945216Sigor@sysoev.ru 
4946743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
4947743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
4948743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
4949743Smax.romanov@nginx.com 
4950743Smax.romanov@nginx.com     dst_field = req->fields;
4951743Smax.romanov@nginx.com 
49521007Salexander.borisov@nginx.com     for (field = nxt_fields_first(r->fields, &iter);
4953743Smax.romanov@nginx.com          field != NULL;
4954743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
4955743Smax.romanov@nginx.com     {
4956743Smax.romanov@nginx.com         if (field->skip) {
4957743Smax.romanov@nginx.com             continue;
4958743Smax.romanov@nginx.com         }
4959743Smax.romanov@nginx.com 
4960743Smax.romanov@nginx.com         dst_field->hash = field->hash;
4961743Smax.romanov@nginx.com         dst_field->skip = 0;
4962743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
4963743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
4964743Smax.romanov@nginx.com 
49651007Salexander.borisov@nginx.com         if (field == r->content_length) {
4966743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
4967743Smax.romanov@nginx.com 
49681007Salexander.borisov@nginx.com         } else if (field == r->content_type) {
4969743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
4970743Smax.romanov@nginx.com 
49711007Salexander.borisov@nginx.com         } else if (field == r->cookie) {
4972743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
4973743Smax.romanov@nginx.com         }
4974743Smax.romanov@nginx.com 
4975743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
4976743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
4977743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
4978743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
4979743Smax.romanov@nginx.com 
4980743Smax.romanov@nginx.com         if (prefix->length != 0) {
4981743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4982743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
4983743Smax.romanov@nginx.com 
4984743Smax.romanov@nginx.com             end = field->name + field->name_length;
4985743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
4986743Smax.romanov@nginx.com                 c = *pos;
4987743Smax.romanov@nginx.com 
4988743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
4989743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
4990743Smax.romanov@nginx.com                     continue;
4991743Smax.romanov@nginx.com                 }
4992743Smax.romanov@nginx.com 
4993743Smax.romanov@nginx.com                 if (c == '-') {
4994743Smax.romanov@nginx.com                     *p++ = '_';
4995743Smax.romanov@nginx.com                     continue;
4996743Smax.romanov@nginx.com                 }
4997743Smax.romanov@nginx.com 
4998743Smax.romanov@nginx.com                 *p++ = c;
4999743Smax.romanov@nginx.com             }
5000743Smax.romanov@nginx.com 
5001743Smax.romanov@nginx.com         } else {
5002743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
5003743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
5004743Smax.romanov@nginx.com         }
5005743Smax.romanov@nginx.com 
5006743Smax.romanov@nginx.com         *p++ = '\0';
5007743Smax.romanov@nginx.com 
5008743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
5009743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
5010743Smax.romanov@nginx.com 
5011743Smax.romanov@nginx.com         if (prefix->length != 0) {
5012743Smax.romanov@nginx.com             dup_iter = iter;
5013743Smax.romanov@nginx.com 
5014743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
5015743Smax.romanov@nginx.com                  dup != NULL;
5016743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
5017743Smax.romanov@nginx.com             {
5018743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
5019743Smax.romanov@nginx.com                     || dup->skip
5020743Smax.romanov@nginx.com                     || dup->hash != field->hash
5021743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
5022743Smax.romanov@nginx.com                 {
5023743Smax.romanov@nginx.com                     continue;
5024743Smax.romanov@nginx.com                 }
5025743Smax.romanov@nginx.com 
5026743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
5027743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
5028743Smax.romanov@nginx.com 
5029743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
5030743Smax.romanov@nginx.com 
5031743Smax.romanov@nginx.com                 dup->skip = 1;
5032743Smax.romanov@nginx.com             }
5033743Smax.romanov@nginx.com         }
5034743Smax.romanov@nginx.com 
5035743Smax.romanov@nginx.com         *p++ = '\0';
5036743Smax.romanov@nginx.com 
5037743Smax.romanov@nginx.com         dst_field++;
5038743Smax.romanov@nginx.com     }
5039743Smax.romanov@nginx.com 
50401007Salexander.borisov@nginx.com     req->fields_count = (uint32_t) (dst_field - req->fields);
5041743Smax.romanov@nginx.com 
5042743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5043743Smax.romanov@nginx.com 
5044743Smax.romanov@nginx.com     buf = out;
5045743Smax.romanov@nginx.com     tail = &buf->next;
5046216Sigor@sysoev.ru 
50471007Salexander.borisov@nginx.com     for (b = r->body; b != NULL; b = b->next) {
5048743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
5049743Smax.romanov@nginx.com         pos = b->mem.pos;
5050743Smax.romanov@nginx.com 
5051743Smax.romanov@nginx.com         while (size > 0) {
5052743Smax.romanov@nginx.com             if (buf == NULL) {
5053743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5054743Smax.romanov@nginx.com 
5055743Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, port, free_size);
5056743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
5057743Smax.romanov@nginx.com                     while (out != NULL) {
5058743Smax.romanov@nginx.com                         buf = out->next;
5059743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
5060743Smax.romanov@nginx.com                         out = buf;
5061743Smax.romanov@nginx.com                     }
5062743Smax.romanov@nginx.com                     return NULL;
5063743Smax.romanov@nginx.com                 }
5064743Smax.romanov@nginx.com 
5065743Smax.romanov@nginx.com                 *tail = buf;
5066743Smax.romanov@nginx.com                 tail = &buf->next;
5067743Smax.romanov@nginx.com 
5068743Smax.romanov@nginx.com             } else {
5069743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
5070743Smax.romanov@nginx.com                 if (free_size < size
5071743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
5072743Smax.romanov@nginx.com                        == NXT_OK)
5073743Smax.romanov@nginx.com                 {
5074743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
5075743Smax.romanov@nginx.com                 }
5076743Smax.romanov@nginx.com             }
5077743Smax.romanov@nginx.com 
5078743Smax.romanov@nginx.com             if (free_size > 0) {
5079743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
5080743Smax.romanov@nginx.com 
5081743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5082743Smax.romanov@nginx.com 
5083743Smax.romanov@nginx.com                 size -= copy_size;
5084743Smax.romanov@nginx.com                 pos += copy_size;
5085743Smax.romanov@nginx.com 
5086743Smax.romanov@nginx.com                 if (size == 0) {
5087743Smax.romanov@nginx.com                     break;
5088743Smax.romanov@nginx.com                 }
5089743Smax.romanov@nginx.com             }
5090743Smax.romanov@nginx.com 
5091743Smax.romanov@nginx.com             buf = NULL;
5092743Smax.romanov@nginx.com         }
5093216Sigor@sysoev.ru     }
5094216Sigor@sysoev.ru 
5095743Smax.romanov@nginx.com     return out;
5096584Salexander.borisov@nginx.com }
5097584Salexander.borisov@nginx.com 
5098584Salexander.borisov@nginx.com 
509953Sigor@sysoev.ru static void
5100318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5101318Smax.romanov@nginx.com {
5102615Smax.romanov@nginx.com     nxt_app_t                *app;
5103615Smax.romanov@nginx.com     nxt_bool_t               cancelled, unlinked;
5104615Smax.romanov@nginx.com     nxt_port_t               *port;
5105615Smax.romanov@nginx.com     nxt_timer_t              *timer;
5106615Smax.romanov@nginx.com     nxt_queue_link_t         *lnk;
51071007Salexander.borisov@nginx.com     nxt_http_request_t       *r;
51081123Smax.romanov@nginx.com     nxt_request_app_link_t   *pending_ra;
51091123Smax.romanov@nginx.com     nxt_request_rpc_data_t   *req_rpc_data;
5110615Smax.romanov@nginx.com     nxt_port_select_state_t  state;
5111318Smax.romanov@nginx.com 
5112318Smax.romanov@nginx.com     timer = obj;
5113318Smax.romanov@nginx.com 
5114318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
5115318Smax.romanov@nginx.com 
51161007Salexander.borisov@nginx.com     r = nxt_timer_data(timer, nxt_http_request_t, timer);
51171123Smax.romanov@nginx.com     req_rpc_data = r->timer_data;
51181123Smax.romanov@nginx.com     app = req_rpc_data->app;
5119615Smax.romanov@nginx.com 
5120615Smax.romanov@nginx.com     if (app == NULL) {
5121615Smax.romanov@nginx.com         goto generate_error;
5122615Smax.romanov@nginx.com     }
5123615Smax.romanov@nginx.com 
5124615Smax.romanov@nginx.com     port = NULL;
5125615Smax.romanov@nginx.com     pending_ra = NULL;
5126615Smax.romanov@nginx.com 
51271123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
51281123Smax.romanov@nginx.com         port = req_rpc_data->app_port;
51291123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
51301123Smax.romanov@nginx.com     }
51311123Smax.romanov@nginx.com 
51321123Smax.romanov@nginx.com     if (port == NULL && req_rpc_data->req_app_link != NULL
51331123Smax.romanov@nginx.com         && req_rpc_data->req_app_link->app_port != NULL)
51341123Smax.romanov@nginx.com     {
51351123Smax.romanov@nginx.com         port = req_rpc_data->req_app_link->app_port;
51361123Smax.romanov@nginx.com         req_rpc_data->req_app_link->app_port = NULL;
5137615Smax.romanov@nginx.com     }
5138615Smax.romanov@nginx.com 
5139615Smax.romanov@nginx.com     if (port == NULL) {
5140615Smax.romanov@nginx.com         goto generate_error;
5141431Sigor@sysoev.ru     }
5142615Smax.romanov@nginx.com 
5143615Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
5144615Smax.romanov@nginx.com 
5145615Smax.romanov@nginx.com     unlinked = nxt_queue_chk_remove(&port->app_link);
5146615Smax.romanov@nginx.com 
5147615Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&port->pending_requests)) {
5148615Smax.romanov@nginx.com         lnk = nxt_queue_first(&port->pending_requests);
5149615Smax.romanov@nginx.com 
51501123Smax.romanov@nginx.com         pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t,
5151615Smax.romanov@nginx.com                                          link_port_pending);
5152615Smax.romanov@nginx.com 
5153615Smax.romanov@nginx.com         nxt_assert(pending_ra->link_app_pending.next != NULL);
5154615Smax.romanov@nginx.com 
5155615Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pending request #%uD found",
5156615Smax.romanov@nginx.com                   &app->name, pending_ra->stream);
5157615Smax.romanov@nginx.com 
5158615Smax.romanov@nginx.com         cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info,
5159615Smax.romanov@nginx.com                                           pending_ra->stream);
5160615Smax.romanov@nginx.com 
5161615Smax.romanov@nginx.com         if (cancelled) {
51621123Smax.romanov@nginx.com             nxt_request_app_link_inc_use(pending_ra);
51631123Smax.romanov@nginx.com 
51641123Smax.romanov@nginx.com             state.req_app_link = pending_ra;
5165615Smax.romanov@nginx.com             state.app = app;
5166615Smax.romanov@nginx.com 
5167615Smax.romanov@nginx.com             nxt_router_port_select(task, &state);
5168615Smax.romanov@nginx.com 
5169615Smax.romanov@nginx.com         } else {
5170615Smax.romanov@nginx.com             pending_ra = NULL;
5171615Smax.romanov@nginx.com         }
5172615Smax.romanov@nginx.com     }
5173615Smax.romanov@nginx.com 
5174615Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
5175615Smax.romanov@nginx.com 
5176615Smax.romanov@nginx.com     if (pending_ra != NULL
5177615Smax.romanov@nginx.com         && nxt_router_port_post_select(task, &state) == NXT_OK)
5178615Smax.romanov@nginx.com     {
5179615Smax.romanov@nginx.com         nxt_router_app_prepare_request(task, pending_ra);
5180615Smax.romanov@nginx.com     }
5181615Smax.romanov@nginx.com 
5182615Smax.romanov@nginx.com     nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid);
5183615Smax.romanov@nginx.com 
5184615Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
5185615Smax.romanov@nginx.com 
5186615Smax.romanov@nginx.com     nxt_port_use(task, port, unlinked ? -2 : -1);
5187615Smax.romanov@nginx.com 
5188615Smax.romanov@nginx.com generate_error:
5189615Smax.romanov@nginx.com 
51901007Salexander.borisov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5191615Smax.romanov@nginx.com 
51921123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
5193318Smax.romanov@nginx.com }
51941007Salexander.borisov@nginx.com 
51951007Salexander.borisov@nginx.com 
51961007Salexander.borisov@nginx.com static nxt_int_t
51971007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r)
51981007Salexander.borisov@nginx.com {
51991007Salexander.borisov@nginx.com     r->timer.handler = nxt_router_http_request_release;
52001007Salexander.borisov@nginx.com     nxt_timer_add(task->thread->engine, &r->timer, 0);
52011007Salexander.borisov@nginx.com 
52021007Salexander.borisov@nginx.com     return NXT_OK;
52031007Salexander.borisov@nginx.com }
52041007Salexander.borisov@nginx.com 
52051007Salexander.borisov@nginx.com 
52061007Salexander.borisov@nginx.com static void
52071007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
52081007Salexander.borisov@nginx.com {
52091007Salexander.borisov@nginx.com     nxt_http_request_t  *r;
52101007Salexander.borisov@nginx.com 
52111007Salexander.borisov@nginx.com     nxt_debug(task, "http app release");
52121007Salexander.borisov@nginx.com 
52131007Salexander.borisov@nginx.com     r = nxt_timer_data(obj, nxt_http_request_t, timer);
52141007Salexander.borisov@nginx.com 
52151007Salexander.borisov@nginx.com     nxt_mp_release(r->mem_pool);
52161007Salexander.borisov@nginx.com }
5217