xref: /unit/src/nxt_router.c (revision 1558)
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>
181555Smax.romanov@nginx.com #include <nxt_app_queue.h>
191555Smax.romanov@nginx.com #include <nxt_port_queue.h>
2020Sigor@sysoev.ru 
21115Sigor@sysoev.ru typedef struct {
22318Smax.romanov@nginx.com     nxt_str_t         type;
23507Smax.romanov@nginx.com     uint32_t          processes;
24507Smax.romanov@nginx.com     uint32_t          max_processes;
25507Smax.romanov@nginx.com     uint32_t          spare_processes;
26318Smax.romanov@nginx.com     nxt_msec_t        timeout;
27427Smax.romanov@nginx.com     nxt_msec_t        res_timeout;
28507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
29318Smax.romanov@nginx.com     uint32_t          requests;
30318Smax.romanov@nginx.com     nxt_conf_value_t  *limits_value;
31507Smax.romanov@nginx.com     nxt_conf_value_t  *processes_value;
321473Svbart@nginx.com     nxt_conf_value_t  *targets_value;
33133Sigor@sysoev.ru } nxt_router_app_conf_t;
34133Sigor@sysoev.ru 
35133Sigor@sysoev.ru 
36133Sigor@sysoev.ru typedef struct {
37964Sigor@sysoev.ru     nxt_str_t         pass;
38964Sigor@sysoev.ru     nxt_str_t         application;
39115Sigor@sysoev.ru } nxt_router_listener_conf_t;
40115Sigor@sysoev.ru 
41115Sigor@sysoev.ru 
42774Svbart@nginx.com #if (NXT_TLS)
43774Svbart@nginx.com 
44774Svbart@nginx.com typedef struct {
45774Svbart@nginx.com     nxt_str_t          name;
46774Svbart@nginx.com     nxt_socket_conf_t  *conf;
47774Svbart@nginx.com 
48774Svbart@nginx.com     nxt_queue_link_t   link;  /* for nxt_socket_conf_t.tls */
49774Svbart@nginx.com } nxt_router_tlssock_t;
50774Svbart@nginx.com 
51774Svbart@nginx.com #endif
52774Svbart@nginx.com 
53774Svbart@nginx.com 
54198Sigor@sysoev.ru typedef struct {
55198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
56198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
57198Sigor@sysoev.ru } nxt_socket_rpc_t;
58198Sigor@sysoev.ru 
59198Sigor@sysoev.ru 
60507Smax.romanov@nginx.com typedef struct {
61507Smax.romanov@nginx.com     nxt_app_t               *app;
62507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
63507Smax.romanov@nginx.com } nxt_app_rpc_t;
64507Smax.romanov@nginx.com 
65507Smax.romanov@nginx.com 
661488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process,
671488St.nateldemoura@f5.com     nxt_mp_t *mp);
681488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data);
69662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task,
70662Smax.romanov@nginx.com     nxt_port_t *controller_port);
71662Smax.romanov@nginx.com 
72507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
73425Smax.romanov@nginx.com 
741552Smax.romanov@nginx.com static void nxt_router_new_port_handler(nxt_task_t *task,
751552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
761552Smax.romanov@nginx.com static void nxt_router_conf_data_handler(nxt_task_t *task,
771552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
781552Smax.romanov@nginx.com static void nxt_router_remove_pid_handler(nxt_task_t *task,
791552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
801552Smax.romanov@nginx.com static void nxt_router_access_log_reopen_handler(nxt_task_t *task,
811552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
821552Smax.romanov@nginx.com 
83139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
84198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
85198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
86139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
87139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
88139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
89139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
90193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
9153Sigor@sysoev.ru 
92115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
93115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
941183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
951183Svbart@nginx.com     nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
96133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
971555Smax.romanov@nginx.com static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task,
981555Smax.romanov@nginx.com     nxt_port_t *port);
991555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task,
1001555Smax.romanov@nginx.com     nxt_port_t *port);
1011555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task,
1021555Smax.romanov@nginx.com     nxt_port_t *port, nxt_fd_t fd);
103198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
104198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
105198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
106198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
107198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
108198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
109774Svbart@nginx.com #if (NXT_TLS)
110774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task,
111774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls);
112774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task,
113774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
114774Svbart@nginx.com #endif
115507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
116507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
117507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
118507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
119507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
120507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
121359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
122359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
123359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
124359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
12553Sigor@sysoev.ru 
12653Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
12753Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
12853Sigor@sysoev.ru     const nxt_event_interface_t *interface);
129115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
130115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
131115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
132115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
133115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
134115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
135154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
136154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
137154Sigor@sysoev.ru     nxt_work_handler_t handler);
138313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
139313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
140139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
141139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
14253Sigor@sysoev.ru 
14353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
14453Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
14553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
14653Sigor@sysoev.ru     nxt_event_engine_t *engine);
147343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
148133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
14953Sigor@sysoev.ru 
150315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
151315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
152315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
153315Sigor@sysoev.ru     nxt_work_t *jobs);
15453Sigor@sysoev.ru 
15553Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
1561545Smax.romanov@nginx.com static void nxt_router_rt_add_port(nxt_task_t *task, void *obj,
1571545Smax.romanov@nginx.com     void *data);
15853Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
15953Sigor@sysoev.ru     void *data);
16053Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
16153Sigor@sysoev.ru     void *data);
16253Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
16353Sigor@sysoev.ru     void *data);
164313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
165313Sigor@sysoev.ru     void *data);
16653Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
16753Sigor@sysoev.ru     void *data);
16853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
16953Sigor@sysoev.ru     void *data);
1701547Smax.romanov@nginx.com static void nxt_router_req_headers_ack_handler(nxt_task_t *task,
1711547Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data);
172359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
173359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
17453Sigor@sysoev.ru 
175630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task,
176630Svbart@nginx.com     nxt_http_request_t *r, nxt_router_access_log_t *access_log);
177630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
178630Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
179630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task,
180630Svbart@nginx.com     nxt_router_temp_conf_t *tmcf);
181630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task,
182630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
183630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task,
184630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
185630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task,
186630Svbart@nginx.com     nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
187651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
188651Svbart@nginx.com     void *data);
189631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
190631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
191631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task,
192631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
193630Svbart@nginx.com 
194343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
195343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
1961547Smax.romanov@nginx.com static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task,
1971547Smax.romanov@nginx.com     nxt_port_t *app_port);
198343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
199343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
200343Smax.romanov@nginx.com 
201753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
2021123Smax.romanov@nginx.com 
203343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
2041123Smax.romanov@nginx.com     nxt_apr_action_t action);
2051547Smax.romanov@nginx.com static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
2061547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data);
2071547Smax.romanov@nginx.com static void nxt_router_http_request_done(nxt_task_t *task, void *obj,
2081547Smax.romanov@nginx.com     void *data);
209141Smax.romanov@nginx.com 
210425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
2111547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data);
2121007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
2131547Smax.romanov@nginx.com     nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix);
214510Salexander.borisov@nginx.com 
215318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
216507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
217507Smax.romanov@nginx.com     void *data);
218507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
219507Smax.romanov@nginx.com     void *data);
220753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
221507Smax.romanov@nginx.com     void *data);
222753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
223431Sigor@sysoev.ru 
224431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
225431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
226141Smax.romanov@nginx.com 
227753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task,
228753Smax.romanov@nginx.com     nxt_app_joint_t *app_joint, int i);
229753Smax.romanov@nginx.com 
2301547Smax.romanov@nginx.com static void nxt_router_http_request_release_post(nxt_task_t *task,
2311007Salexander.borisov@nginx.com     nxt_http_request_t *r);
2321007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
2331007Salexander.borisov@nginx.com     void *data);
2341321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
2351545Smax.romanov@nginx.com static void nxt_router_get_port_handler(nxt_task_t *task,
2361545Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
2371546Smax.romanov@nginx.com static void nxt_router_get_mmap_handler(nxt_task_t *task,
2381546Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
2391007Salexander.borisov@nginx.com 
2401149Smax.romanov@nginx.com extern const nxt_http_request_state_t  nxt_http_websocket;
2411131Smax.romanov@nginx.com 
242119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
24320Sigor@sysoev.ru 
244743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
245743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
246743Smax.romanov@nginx.com 
247743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
248804Svbart@nginx.com     &empty_prefix,
249743Smax.romanov@nginx.com     &http_prefix,
250743Smax.romanov@nginx.com     &http_prefix,
251743Smax.romanov@nginx.com     &http_prefix,
252743Smax.romanov@nginx.com     &http_prefix,
253977Smax.romanov@gmail.com     &empty_prefix,
254216Sigor@sysoev.ru };
255216Sigor@sysoev.ru 
256216Sigor@sysoev.ru 
2571488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_router_process_port_handlers = {
2581488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
259662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
2601545Smax.romanov@nginx.com     .get_port     = nxt_router_get_port_handler,
261662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
262662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
2631546Smax.romanov@nginx.com     .get_mmap     = nxt_router_get_mmap_handler,
264662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
265662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
266662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
267662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
268662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
2691321Smax.romanov@nginx.com     .oosm         = nxt_router_oosm_handler,
270662Smax.romanov@nginx.com };
271662Smax.romanov@nginx.com 
272662Smax.romanov@nginx.com 
2731488St.nateldemoura@f5.com const nxt_process_init_t  nxt_router_process = {
2741488St.nateldemoura@f5.com     .name           = "router",
2751488St.nateldemoura@f5.com     .type           = NXT_PROCESS_ROUTER,
2761488St.nateldemoura@f5.com     .prefork        = nxt_router_prefork,
2771488St.nateldemoura@f5.com     .restart        = 1,
2781488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
2791488St.nateldemoura@f5.com     .start          = nxt_router_start,
2801488St.nateldemoura@f5.com     .port_handlers  = &nxt_router_process_port_handlers,
2811488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
2821488St.nateldemoura@f5.com };
2831488St.nateldemoura@f5.com 
2841488St.nateldemoura@f5.com 
2851509Sigor@sysoev.ru /* Queues of nxt_socket_conf_t */
2861509Sigor@sysoev.ru nxt_queue_t  creating_sockets;
2871509Sigor@sysoev.ru nxt_queue_t  pending_sockets;
2881509Sigor@sysoev.ru nxt_queue_t  updating_sockets;
2891509Sigor@sysoev.ru nxt_queue_t  keeping_sockets;
2901509Sigor@sysoev.ru nxt_queue_t  deleting_sockets;
2911509Sigor@sysoev.ru 
2921509Sigor@sysoev.ru 
2931488St.nateldemoura@f5.com static nxt_int_t
2941488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
2951488St.nateldemoura@f5.com {
2961488St.nateldemoura@f5.com     nxt_runtime_stop_app_processes(task, task->thread->runtime);
2971488St.nateldemoura@f5.com 
2981488St.nateldemoura@f5.com     return NXT_OK;
2991488St.nateldemoura@f5.com }
3001488St.nateldemoura@f5.com 
3011488St.nateldemoura@f5.com 
3021488St.nateldemoura@f5.com static nxt_int_t
3031488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data)
30420Sigor@sysoev.ru {
305141Smax.romanov@nginx.com     nxt_int_t      ret;
306662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
307141Smax.romanov@nginx.com     nxt_router_t   *router;
308141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
309141Smax.romanov@nginx.com 
310141Smax.romanov@nginx.com     rt = task->thread->runtime;
31153Sigor@sysoev.ru 
3121488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "router started");
3131488St.nateldemoura@f5.com 
314771Sigor@sysoev.ru #if (NXT_TLS)
315771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
316771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
317771Sigor@sysoev.ru         return NXT_ERROR;
318771Sigor@sysoev.ru     }
319771Sigor@sysoev.ru 
320771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
321771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
322771Sigor@sysoev.ru         return ret;
323771Sigor@sysoev.ru     }
324771Sigor@sysoev.ru #endif
325771Sigor@sysoev.ru 
3261459Smax.romanov@nginx.com     ret = nxt_http_init(task);
32788Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
32888Smax.romanov@nginx.com         return ret;
32988Smax.romanov@nginx.com     }
33088Smax.romanov@nginx.com 
33153Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
33253Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
33353Sigor@sysoev.ru         return NXT_ERROR;
33453Sigor@sysoev.ru     }
33553Sigor@sysoev.ru 
33653Sigor@sysoev.ru     nxt_queue_init(&router->engines);
33753Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
338133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
33953Sigor@sysoev.ru 
340119Smax.romanov@nginx.com     nxt_router = router;
341119Smax.romanov@nginx.com 
342662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
343662Smax.romanov@nginx.com     if (controller_port != NULL) {
344662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
345662Smax.romanov@nginx.com     }
346662Smax.romanov@nginx.com 
347115Sigor@sysoev.ru     return NXT_OK;
348115Sigor@sysoev.ru }
349115Sigor@sysoev.ru 
350115Sigor@sysoev.ru 
351343Smax.romanov@nginx.com static void
352662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
353662Smax.romanov@nginx.com {
354662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
355662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
356662Smax.romanov@nginx.com }
357662Smax.romanov@nginx.com 
358662Smax.romanov@nginx.com 
359662Smax.romanov@nginx.com static void
360507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
361507Smax.romanov@nginx.com     void *data)
362167Smax.romanov@nginx.com {
363343Smax.romanov@nginx.com     size_t         size;
364343Smax.romanov@nginx.com     uint32_t       stream;
365430Sigor@sysoev.ru     nxt_mp_t       *mp;
366648Svbart@nginx.com     nxt_int_t      ret;
367343Smax.romanov@nginx.com     nxt_app_t      *app;
368343Smax.romanov@nginx.com     nxt_buf_t      *b;
369343Smax.romanov@nginx.com     nxt_port_t     *main_port;
370343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
371343Smax.romanov@nginx.com 
372343Smax.romanov@nginx.com     app = data;
373167Smax.romanov@nginx.com 
374167Smax.romanov@nginx.com     rt = task->thread->runtime;
375240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
376167Smax.romanov@nginx.com 
377507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start process", &app->name, app);
378343Smax.romanov@nginx.com 
379343Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
380343Smax.romanov@nginx.com 
381343Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
382343Smax.romanov@nginx.com 
383343Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
384343Smax.romanov@nginx.com         goto failed;
385167Smax.romanov@nginx.com     }
386167Smax.romanov@nginx.com 
387343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
388343Smax.romanov@nginx.com     *b->mem.free++ = '\0';
389343Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
390343Smax.romanov@nginx.com 
391753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
392753Smax.romanov@nginx.com 
393343Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, port,
394343Smax.romanov@nginx.com                                            nxt_router_app_port_ready,
395343Smax.romanov@nginx.com                                            nxt_router_app_port_error,
396753Smax.romanov@nginx.com                                            -1, app->joint);
397343Smax.romanov@nginx.com 
398343Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
399753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
400753Smax.romanov@nginx.com 
401343Smax.romanov@nginx.com         goto failed;
402343Smax.romanov@nginx.com     }
403343Smax.romanov@nginx.com 
4041488St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
4051488St.nateldemoura@f5.com                                 -1, stream, port->id, b);
406648Svbart@nginx.com 
407648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
408648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
409753Smax.romanov@nginx.com 
410753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app->joint, -1);
411753Smax.romanov@nginx.com 
412648Svbart@nginx.com         goto failed;
413648Svbart@nginx.com     }
414343Smax.romanov@nginx.com 
415753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
416753Smax.romanov@nginx.com 
417343Smax.romanov@nginx.com     return;
418343Smax.romanov@nginx.com 
419343Smax.romanov@nginx.com failed:
420343Smax.romanov@nginx.com 
421648Svbart@nginx.com     if (b != NULL) {
422648Svbart@nginx.com         mp = b->data;
423648Svbart@nginx.com         nxt_mp_free(mp, b);
424648Svbart@nginx.com         nxt_mp_release(mp);
425648Svbart@nginx.com     }
426648Svbart@nginx.com 
427343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
428343Smax.romanov@nginx.com 
429507Smax.romanov@nginx.com     app->pending_processes--;
430343Smax.romanov@nginx.com 
431343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
432343Smax.romanov@nginx.com 
433343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
434167Smax.romanov@nginx.com }
435167Smax.romanov@nginx.com 
436167Smax.romanov@nginx.com 
437753Smax.romanov@nginx.com static void
438753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
439753Smax.romanov@nginx.com {
440753Smax.romanov@nginx.com     app_joint->use_count += i;
441753Smax.romanov@nginx.com 
442753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
443753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
444753Smax.romanov@nginx.com 
445753Smax.romanov@nginx.com         nxt_free(app_joint);
446753Smax.romanov@nginx.com     }
447753Smax.romanov@nginx.com }
448753Smax.romanov@nginx.com 
449753Smax.romanov@nginx.com 
450343Smax.romanov@nginx.com static nxt_int_t
451507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
452141Smax.romanov@nginx.com {
453343Smax.romanov@nginx.com     nxt_int_t      res;
454343Smax.romanov@nginx.com     nxt_port_t     *router_port;
455343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
456343Smax.romanov@nginx.com 
4571549Smax.romanov@nginx.com     nxt_debug(task, "app '%V' start process", &app->name);
4581549Smax.romanov@nginx.com 
459343Smax.romanov@nginx.com     rt = task->thread->runtime;
460343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
461343Smax.romanov@nginx.com 
462343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
463343Smax.romanov@nginx.com 
464507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
465343Smax.romanov@nginx.com                         app);
466343Smax.romanov@nginx.com 
467343Smax.romanov@nginx.com     if (res == NXT_OK) {
468343Smax.romanov@nginx.com         return res;
469318Smax.romanov@nginx.com     }
470318Smax.romanov@nginx.com 
471343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
472343Smax.romanov@nginx.com 
473507Smax.romanov@nginx.com     app->pending_processes--;
474343Smax.romanov@nginx.com 
475343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
476343Smax.romanov@nginx.com 
477343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
478343Smax.romanov@nginx.com 
479343Smax.romanov@nginx.com     return NXT_ERROR;
480318Smax.romanov@nginx.com }
481318Smax.romanov@nginx.com 
482318Smax.romanov@nginx.com 
483423Smax.romanov@nginx.com nxt_inline nxt_bool_t
4841555Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
485423Smax.romanov@nginx.com {
4861555Smax.romanov@nginx.com     nxt_buf_t       *b, *next;
4871555Smax.romanov@nginx.com     nxt_bool_t      cancelled;
4881555Smax.romanov@nginx.com     nxt_msg_info_t  *msg_info;
4891555Smax.romanov@nginx.com 
4901555Smax.romanov@nginx.com     msg_info = &req_rpc_data->msg_info;
491423Smax.romanov@nginx.com 
492423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
493423Smax.romanov@nginx.com         return 0;
494423Smax.romanov@nginx.com     }
495423Smax.romanov@nginx.com 
4961555Smax.romanov@nginx.com     cancelled = nxt_app_queue_cancel(req_rpc_data->app->shared_port->queue,
4971555Smax.romanov@nginx.com                                      msg_info->tracking_cookie,
4981555Smax.romanov@nginx.com                                      req_rpc_data->stream);
499423Smax.romanov@nginx.com 
500423Smax.romanov@nginx.com     if (cancelled) {
5011555Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: cancelled by router",
5021555Smax.romanov@nginx.com                   req_rpc_data->stream);
503423Smax.romanov@nginx.com     }
504423Smax.romanov@nginx.com 
505423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
506423Smax.romanov@nginx.com         next = b->next;
5071269Sigor@sysoev.ru         b->next = NULL;
508423Smax.romanov@nginx.com 
509423Smax.romanov@nginx.com         b->completion_handler = msg_info->completion_handler;
510423Smax.romanov@nginx.com 
511423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
512423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
513423Smax.romanov@nginx.com             b->completion_handler(task, b, b->parent);
514423Smax.romanov@nginx.com         }
515423Smax.romanov@nginx.com     }
516423Smax.romanov@nginx.com 
517423Smax.romanov@nginx.com     msg_info->buf = NULL;
518423Smax.romanov@nginx.com 
519423Smax.romanov@nginx.com     return cancelled;
520423Smax.romanov@nginx.com }
521423Smax.romanov@nginx.com 
522423Smax.romanov@nginx.com 
523425Smax.romanov@nginx.com nxt_inline nxt_bool_t
524425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
525425Smax.romanov@nginx.com {
526425Smax.romanov@nginx.com     if (lnk->next != NULL) {
527425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
528425Smax.romanov@nginx.com 
529425Smax.romanov@nginx.com         lnk->next = NULL;
530425Smax.romanov@nginx.com 
531425Smax.romanov@nginx.com         return 1;
532425Smax.romanov@nginx.com     }
533425Smax.romanov@nginx.com 
534425Smax.romanov@nginx.com     return 0;
535425Smax.romanov@nginx.com }
536425Smax.romanov@nginx.com 
537425Smax.romanov@nginx.com 
538343Smax.romanov@nginx.com nxt_inline void
5391123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task,
5401123Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
541343Smax.romanov@nginx.com {
5421547Smax.romanov@nginx.com     nxt_http_request_t  *r;
5431547Smax.romanov@nginx.com 
5441555Smax.romanov@nginx.com     nxt_router_msg_cancel(task, req_rpc_data);
5451123Smax.romanov@nginx.com 
5461123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
5471123Smax.romanov@nginx.com         nxt_router_app_port_release(task, req_rpc_data->app_port,
5481123Smax.romanov@nginx.com                                     req_rpc_data->apr_action);
5491123Smax.romanov@nginx.com 
5501123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
5511123Smax.romanov@nginx.com     }
5521123Smax.romanov@nginx.com 
5531123Smax.romanov@nginx.com     if (req_rpc_data->app != NULL) {
5541123Smax.romanov@nginx.com         nxt_router_app_use(task, req_rpc_data->app, -1);
5551123Smax.romanov@nginx.com 
5561123Smax.romanov@nginx.com         req_rpc_data->app = NULL;
5571123Smax.romanov@nginx.com     }
5581123Smax.romanov@nginx.com 
5591547Smax.romanov@nginx.com     r = req_rpc_data->request;
5601547Smax.romanov@nginx.com 
5611547Smax.romanov@nginx.com     if (r != NULL) {
5621547Smax.romanov@nginx.com         r->timer_data = NULL;
5631547Smax.romanov@nginx.com 
5641547Smax.romanov@nginx.com         nxt_router_http_request_release_post(task, r);
5651547Smax.romanov@nginx.com 
5661547Smax.romanov@nginx.com         r->req_rpc_data = NULL;
5671123Smax.romanov@nginx.com         req_rpc_data->request = NULL;
568346Smax.romanov@nginx.com     }
5691547Smax.romanov@nginx.com 
5701547Smax.romanov@nginx.com     if (req_rpc_data->msg_info.body_fd != -1) {
5711547Smax.romanov@nginx.com         nxt_fd_close(req_rpc_data->msg_info.body_fd);
5721547Smax.romanov@nginx.com 
5731547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = -1;
5741547Smax.romanov@nginx.com     }
5751547Smax.romanov@nginx.com 
5761547Smax.romanov@nginx.com     if (req_rpc_data->rpc_cancel) {
5771547Smax.romanov@nginx.com         req_rpc_data->rpc_cancel = 0;
5781547Smax.romanov@nginx.com 
5791547Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port,
5801547Smax.romanov@nginx.com                             req_rpc_data->stream);
5811547Smax.romanov@nginx.com     }
582343Smax.romanov@nginx.com }
583343Smax.romanov@nginx.com 
584343Smax.romanov@nginx.com 
5851552Smax.romanov@nginx.com static void
586141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
587141Smax.romanov@nginx.com {
5881555Smax.romanov@nginx.com     nxt_int_t      res;
5891547Smax.romanov@nginx.com     nxt_app_t      *app;
5901547Smax.romanov@nginx.com     nxt_port_t     *port, *main_app_port;
5911547Smax.romanov@nginx.com     nxt_runtime_t  *rt;
5921547Smax.romanov@nginx.com 
593141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
594141Smax.romanov@nginx.com 
5951547Smax.romanov@nginx.com     port = msg->u.new_port;
5961547Smax.romanov@nginx.com 
5971547Smax.romanov@nginx.com     if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) {
598662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
599662Smax.romanov@nginx.com     }
600662Smax.romanov@nginx.com 
6011547Smax.romanov@nginx.com     if (port == NULL || port->type != NXT_PROCESS_APP) {
6021547Smax.romanov@nginx.com 
6031547Smax.romanov@nginx.com         if (msg->port_msg.stream == 0) {
6041547Smax.romanov@nginx.com             return;
6051547Smax.romanov@nginx.com         }
6061547Smax.romanov@nginx.com 
6071547Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
6081555Smax.romanov@nginx.com 
6091555Smax.romanov@nginx.com     } else {
610*1558Smax.romanov@nginx.com         if (msg->fd[1] != -1) {
611*1558Smax.romanov@nginx.com             res = nxt_router_port_queue_map(task, port, msg->fd[1]);
6121555Smax.romanov@nginx.com             if (nxt_slow_path(res != NXT_OK)) {
6131555Smax.romanov@nginx.com                 return;
6141555Smax.romanov@nginx.com             }
6151555Smax.romanov@nginx.com 
616*1558Smax.romanov@nginx.com             nxt_fd_close(msg->fd[1]);
617*1558Smax.romanov@nginx.com             msg->fd[1] = -1;
6181555Smax.romanov@nginx.com         }
6191547Smax.romanov@nginx.com     }
6201547Smax.romanov@nginx.com 
6211547Smax.romanov@nginx.com     if (msg->port_msg.stream != 0) {
6221547Smax.romanov@nginx.com         nxt_port_rpc_handler(task, msg);
623141Smax.romanov@nginx.com         return;
624141Smax.romanov@nginx.com     }
625141Smax.romanov@nginx.com 
6261547Smax.romanov@nginx.com     /*
6271547Smax.romanov@nginx.com      * Port with "id == 0" is application 'main' port and it always
6281547Smax.romanov@nginx.com      * should come with non-zero stream.
6291547Smax.romanov@nginx.com      */
6301547Smax.romanov@nginx.com     nxt_assert(port->id != 0);
6311547Smax.romanov@nginx.com 
6321547Smax.romanov@nginx.com     /* Find 'main' app port and get app reference. */
6331547Smax.romanov@nginx.com     rt = task->thread->runtime;
6341547Smax.romanov@nginx.com 
6351547Smax.romanov@nginx.com     /*
6361547Smax.romanov@nginx.com      * It is safe to access 'runtime->ports' hash because 'NEW_PORT'
6371547Smax.romanov@nginx.com      * sent to main port (with id == 0) and processed in main thread.
6381547Smax.romanov@nginx.com      */
6391547Smax.romanov@nginx.com     main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0);
6401547Smax.romanov@nginx.com     nxt_assert(main_app_port != NULL);
6411547Smax.romanov@nginx.com 
6421547Smax.romanov@nginx.com     app = main_app_port->app;
6431547Smax.romanov@nginx.com     nxt_assert(app != NULL);
6441547Smax.romanov@nginx.com 
6451547Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
6461547Smax.romanov@nginx.com 
6471547Smax.romanov@nginx.com     /* TODO here should be find-and-add code because there can be
6481547Smax.romanov@nginx.com        port waiters in port_hash */
6491547Smax.romanov@nginx.com     nxt_port_hash_add(&app->port_hash, port);
6501547Smax.romanov@nginx.com     app->port_hash_count++;
6511547Smax.romanov@nginx.com 
6521547Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
6531547Smax.romanov@nginx.com 
6541547Smax.romanov@nginx.com     port->app = app;
6551547Smax.romanov@nginx.com     port->main_app_port = main_app_port;
656141Smax.romanov@nginx.com }
657141Smax.romanov@nginx.com 
658141Smax.romanov@nginx.com 
6591552Smax.romanov@nginx.com static void
660139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
661115Sigor@sysoev.ru {
6621526Smax.romanov@nginx.com     void                    *p;
6631526Smax.romanov@nginx.com     size_t                  size;
664198Sigor@sysoev.ru     nxt_int_t               ret;
665139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
666139Sigor@sysoev.ru 
667139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
668139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
669139Sigor@sysoev.ru         return;
67053Sigor@sysoev.ru     }
67153Sigor@sysoev.ru 
672*1558Smax.romanov@nginx.com     if (nxt_slow_path(msg->fd[0] == -1)) {
6731526Smax.romanov@nginx.com         nxt_alert(task, "conf_data_handler: invalid file shm fd");
6741526Smax.romanov@nginx.com         return;
6751526Smax.romanov@nginx.com     }
6761526Smax.romanov@nginx.com 
6771526Smax.romanov@nginx.com     if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
6781526Smax.romanov@nginx.com         nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)",
6791526Smax.romanov@nginx.com                   (int) nxt_buf_mem_used_size(&msg->buf->mem));
6801526Smax.romanov@nginx.com 
681*1558Smax.romanov@nginx.com         nxt_fd_close(msg->fd[0]);
682*1558Smax.romanov@nginx.com         msg->fd[0] = -1;
6831526Smax.romanov@nginx.com 
6841526Smax.romanov@nginx.com         return;
6851526Smax.romanov@nginx.com     }
6861526Smax.romanov@nginx.com 
6871526Smax.romanov@nginx.com     nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
6881526Smax.romanov@nginx.com 
689*1558Smax.romanov@nginx.com     p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
690*1558Smax.romanov@nginx.com 
691*1558Smax.romanov@nginx.com     nxt_fd_close(msg->fd[0]);
692*1558Smax.romanov@nginx.com     msg->fd[0] = -1;
6931526Smax.romanov@nginx.com 
6941526Smax.romanov@nginx.com     if (nxt_slow_path(p == MAP_FAILED)) {
6951526Smax.romanov@nginx.com         return;
6961526Smax.romanov@nginx.com     }
6971526Smax.romanov@nginx.com 
6981526Smax.romanov@nginx.com     nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p);
699423Smax.romanov@nginx.com 
700591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
701139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
702139Sigor@sysoev.ru     tmcf->port = nxt_runtime_port_find(task->thread->runtime,
703198Sigor@sysoev.ru                                        msg->port_msg.pid,
704198Sigor@sysoev.ru                                        msg->port_msg.reply_port);
705198Sigor@sysoev.ru 
706779Smax.romanov@nginx.com     if (nxt_slow_path(tmcf->port == NULL)) {
707779Smax.romanov@nginx.com         nxt_alert(task, "reply port not found");
708779Smax.romanov@nginx.com 
7091526Smax.romanov@nginx.com         goto fail;
710779Smax.romanov@nginx.com     }
711779Smax.romanov@nginx.com 
712779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
713779Smax.romanov@nginx.com 
7141526Smax.romanov@nginx.com     ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size));
715198Sigor@sysoev.ru 
716198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
717198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
718198Sigor@sysoev.ru 
719198Sigor@sysoev.ru     } else {
720198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
721139Sigor@sysoev.ru     }
7221526Smax.romanov@nginx.com 
7231526Smax.romanov@nginx.com fail:
7241526Smax.romanov@nginx.com 
7251526Smax.romanov@nginx.com     nxt_mem_munmap(p, size);
72653Sigor@sysoev.ru }
72753Sigor@sysoev.ru 
72853Sigor@sysoev.ru 
729347Smax.romanov@nginx.com static void
730507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
731507Smax.romanov@nginx.com     void *data)
732347Smax.romanov@nginx.com {
733347Smax.romanov@nginx.com     union {
734347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
735347Smax.romanov@nginx.com         void       *data;
736347Smax.romanov@nginx.com     } u;
737347Smax.romanov@nginx.com 
738347Smax.romanov@nginx.com     u.data = data;
739347Smax.romanov@nginx.com 
740347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
741347Smax.romanov@nginx.com }
742347Smax.romanov@nginx.com 
743347Smax.romanov@nginx.com 
7441552Smax.romanov@nginx.com static void
745192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
746192Smax.romanov@nginx.com {
747347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
748318Smax.romanov@nginx.com 
749192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
750192Smax.romanov@nginx.com 
751318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
752318Smax.romanov@nginx.com     {
7531486Smax.romanov@nginx.com         if (nxt_fast_path(engine->port != NULL)) {
7541486Smax.romanov@nginx.com             nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
7551486Smax.romanov@nginx.com                           msg->u.data);
7561486Smax.romanov@nginx.com         }
757318Smax.romanov@nginx.com     }
758318Smax.romanov@nginx.com     nxt_queue_loop;
759318Smax.romanov@nginx.com 
7601085Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
7611085Smax.romanov@nginx.com         return;
7621085Smax.romanov@nginx.com     }
7631085Smax.romanov@nginx.com 
764192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
765192Smax.romanov@nginx.com 
766192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
767192Smax.romanov@nginx.com }
768192Smax.romanov@nginx.com 
769192Smax.romanov@nginx.com 
77053Sigor@sysoev.ru static nxt_router_temp_conf_t *
771139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
77253Sigor@sysoev.ru {
77365Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
77453Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
77553Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
77653Sigor@sysoev.ru 
77765Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
77853Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
77953Sigor@sysoev.ru         return NULL;
78053Sigor@sysoev.ru     }
78153Sigor@sysoev.ru 
78265Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
78353Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
78453Sigor@sysoev.ru         goto fail;
78553Sigor@sysoev.ru     }
78653Sigor@sysoev.ru 
78753Sigor@sysoev.ru     rtcf->mem_pool = mp;
78853Sigor@sysoev.ru 
78965Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
79053Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
79153Sigor@sysoev.ru         goto fail;
79253Sigor@sysoev.ru     }
79353Sigor@sysoev.ru 
79465Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
79553Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
79653Sigor@sysoev.ru         goto temp_fail;
79753Sigor@sysoev.ru     }
79853Sigor@sysoev.ru 
79953Sigor@sysoev.ru     tmcf->mem_pool = tmp;
800591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
801139Sigor@sysoev.ru     tmcf->count = 1;
802139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
80353Sigor@sysoev.ru 
80453Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
80553Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
80653Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
80753Sigor@sysoev.ru         goto temp_fail;
80853Sigor@sysoev.ru     }
80953Sigor@sysoev.ru 
8101509Sigor@sysoev.ru     nxt_queue_init(&creating_sockets);
8111509Sigor@sysoev.ru     nxt_queue_init(&pending_sockets);
8121509Sigor@sysoev.ru     nxt_queue_init(&updating_sockets);
8131509Sigor@sysoev.ru     nxt_queue_init(&keeping_sockets);
8141509Sigor@sysoev.ru     nxt_queue_init(&deleting_sockets);
815416Smax.romanov@nginx.com 
816774Svbart@nginx.com #if (NXT_TLS)
817774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
818774Svbart@nginx.com #endif
819774Svbart@nginx.com 
820133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
821133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
82253Sigor@sysoev.ru 
82353Sigor@sysoev.ru     return tmcf;
82453Sigor@sysoev.ru 
82553Sigor@sysoev.ru temp_fail:
82653Sigor@sysoev.ru 
82765Sigor@sysoev.ru     nxt_mp_destroy(tmp);
82853Sigor@sysoev.ru 
82953Sigor@sysoev.ru fail:
83053Sigor@sysoev.ru 
83165Sigor@sysoev.ru     nxt_mp_destroy(mp);
83253Sigor@sysoev.ru 
83353Sigor@sysoev.ru     return NULL;
83453Sigor@sysoev.ru }
83553Sigor@sysoev.ru 
83653Sigor@sysoev.ru 
837507Smax.romanov@nginx.com nxt_inline nxt_bool_t
838507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
839507Smax.romanov@nginx.com {
840507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
841507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
842507Smax.romanov@nginx.com }
843507Smax.romanov@nginx.com 
844507Smax.romanov@nginx.com 
845507Smax.romanov@nginx.com nxt_inline nxt_bool_t
846507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
847507Smax.romanov@nginx.com {
8481547Smax.romanov@nginx.com     return (app->active_requests
8491547Smax.romanov@nginx.com               > app->port_hash_count + app->pending_processes)
8501547Smax.romanov@nginx.com            || (app->spare_processes
8511547Smax.romanov@nginx.com                 > app->idle_processes + app->pending_processes);
852507Smax.romanov@nginx.com }
853507Smax.romanov@nginx.com 
854507Smax.romanov@nginx.com 
855198Sigor@sysoev.ru static void
856198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
857139Sigor@sysoev.ru {
858139Sigor@sysoev.ru     nxt_int_t                    ret;
859507Smax.romanov@nginx.com     nxt_app_t                    *app;
860139Sigor@sysoev.ru     nxt_router_t                 *router;
861139Sigor@sysoev.ru     nxt_runtime_t                *rt;
862198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
863198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
864630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
865198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
866139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
867774Svbart@nginx.com #if (NXT_TLS)
868774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
869774Svbart@nginx.com #endif
870139Sigor@sysoev.ru 
871198Sigor@sysoev.ru     tmcf = obj;
872198Sigor@sysoev.ru 
8731509Sigor@sysoev.ru     qlk = nxt_queue_first(&pending_sockets);
8741509Sigor@sysoev.ru 
8751509Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&pending_sockets)) {
876198Sigor@sysoev.ru         nxt_queue_remove(qlk);
8771509Sigor@sysoev.ru         nxt_queue_insert_tail(&creating_sockets, qlk);
878198Sigor@sysoev.ru 
879198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
880198Sigor@sysoev.ru 
881198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
882198Sigor@sysoev.ru 
883198Sigor@sysoev.ru         return;
884139Sigor@sysoev.ru     }
885139Sigor@sysoev.ru 
886774Svbart@nginx.com #if (NXT_TLS)
887774Svbart@nginx.com     qlk = nxt_queue_first(&tmcf->tls);
888774Svbart@nginx.com 
889774Svbart@nginx.com     if (qlk != nxt_queue_tail(&tmcf->tls)) {
890774Svbart@nginx.com         nxt_queue_remove(qlk);
891774Svbart@nginx.com 
892774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
893774Svbart@nginx.com 
894774Svbart@nginx.com         nxt_router_tls_rpc_create(task, tmcf, tls);
895774Svbart@nginx.com         return;
896774Svbart@nginx.com     }
897774Svbart@nginx.com #endif
898774Svbart@nginx.com 
899507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
900507Smax.romanov@nginx.com 
901507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
902507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
903507Smax.romanov@nginx.com             return;
904507Smax.romanov@nginx.com         }
905507Smax.romanov@nginx.com 
906507Smax.romanov@nginx.com     } nxt_queue_loop;
907507Smax.romanov@nginx.com 
908630Svbart@nginx.com     rtcf = tmcf->router_conf;
909630Svbart@nginx.com 
910630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
911630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
912630Svbart@nginx.com         return;
913630Svbart@nginx.com     }
914630Svbart@nginx.com 
915139Sigor@sysoev.ru     rt = task->thread->runtime;
916139Sigor@sysoev.ru 
917139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
918139Sigor@sysoev.ru 
919630Svbart@nginx.com     router = rtcf->router;
920198Sigor@sysoev.ru 
921139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
922139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
923198Sigor@sysoev.ru         goto fail;
924139Sigor@sysoev.ru     }
925139Sigor@sysoev.ru 
926139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
927139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
928198Sigor@sysoev.ru         goto fail;
929139Sigor@sysoev.ru     }
930139Sigor@sysoev.ru 
931343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
932139Sigor@sysoev.ru 
933315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
934139Sigor@sysoev.ru 
9351509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &updating_sockets);
9361509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &creating_sockets);
937139Sigor@sysoev.ru 
938630Svbart@nginx.com     router->access_log = rtcf->access_log;
939630Svbart@nginx.com 
940198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
941198Sigor@sysoev.ru 
942198Sigor@sysoev.ru     return;
943198Sigor@sysoev.ru 
944198Sigor@sysoev.ru fail:
945198Sigor@sysoev.ru 
946198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
947198Sigor@sysoev.ru 
948198Sigor@sysoev.ru     return;
949139Sigor@sysoev.ru }
950139Sigor@sysoev.ru 
951139Sigor@sysoev.ru 
952139Sigor@sysoev.ru static void
953139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
954139Sigor@sysoev.ru {
955153Sigor@sysoev.ru     nxt_joint_job_t  *job;
956153Sigor@sysoev.ru 
957153Sigor@sysoev.ru     job = obj;
958153Sigor@sysoev.ru 
959198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
960139Sigor@sysoev.ru }
961139Sigor@sysoev.ru 
962139Sigor@sysoev.ru 
963139Sigor@sysoev.ru static void
964198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
965139Sigor@sysoev.ru {
9661542Smax.romanov@nginx.com     uint32_t               count;
9671542Smax.romanov@nginx.com     nxt_router_conf_t      *rtcf;
9681542Smax.romanov@nginx.com     nxt_thread_spinlock_t  *lock;
9691542Smax.romanov@nginx.com 
9701542Smax.romanov@nginx.com     nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count);
9711542Smax.romanov@nginx.com 
9721542Smax.romanov@nginx.com     if (--tmcf->count > 0) {
9731542Smax.romanov@nginx.com         return;
9741542Smax.romanov@nginx.com     }
9751542Smax.romanov@nginx.com 
9761542Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
9771542Smax.romanov@nginx.com 
9781542Smax.romanov@nginx.com     rtcf = tmcf->router_conf;
9791542Smax.romanov@nginx.com 
9801542Smax.romanov@nginx.com     lock = &rtcf->router->lock;
9811542Smax.romanov@nginx.com 
9821542Smax.romanov@nginx.com     nxt_thread_spin_lock(lock);
9831542Smax.romanov@nginx.com 
9841542Smax.romanov@nginx.com     count = rtcf->count;
9851542Smax.romanov@nginx.com 
9861542Smax.romanov@nginx.com     nxt_thread_spin_unlock(lock);
9871542Smax.romanov@nginx.com 
9881542Smax.romanov@nginx.com     nxt_debug(task, "rtcf %p: %D", rtcf, count);
9891542Smax.romanov@nginx.com 
9901542Smax.romanov@nginx.com     if (count == 0) {
9911542Smax.romanov@nginx.com         nxt_http_routes_cleanup(task, rtcf->routes);
9921542Smax.romanov@nginx.com 
9931542Smax.romanov@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
9941542Smax.romanov@nginx.com 
9951542Smax.romanov@nginx.com         nxt_mp_destroy(rtcf->mem_pool);
9961542Smax.romanov@nginx.com     }
9971542Smax.romanov@nginx.com 
9981542Smax.romanov@nginx.com     nxt_mp_destroy(tmcf->mem_pool);
999139Sigor@sysoev.ru }
1000139Sigor@sysoev.ru 
1001139Sigor@sysoev.ru 
1002139Sigor@sysoev.ru static void
1003139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1004139Sigor@sysoev.ru {
1005507Smax.romanov@nginx.com     nxt_app_t          *app;
1006568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1007148Sigor@sysoev.ru     nxt_socket_t       s;
1008149Sigor@sysoev.ru     nxt_router_t       *router;
1009148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1010148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1011630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1012148Sigor@sysoev.ru 
1013564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1014198Sigor@sysoev.ru 
10151509Sigor@sysoev.ru     for (qlk = nxt_queue_first(&creating_sockets);
10161509Sigor@sysoev.ru          qlk != nxt_queue_tail(&creating_sockets);
1017148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1018148Sigor@sysoev.ru     {
1019148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1020359Sigor@sysoev.ru         s = skcf->listen->socket;
1021148Sigor@sysoev.ru 
1022148Sigor@sysoev.ru         if (s != -1) {
1023148Sigor@sysoev.ru             nxt_socket_close(task, s);
1024148Sigor@sysoev.ru         }
1025148Sigor@sysoev.ru 
1026359Sigor@sysoev.ru         nxt_free(skcf->listen);
1027148Sigor@sysoev.ru     }
1028148Sigor@sysoev.ru 
1029568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
10301509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &updating_sockets);
10311509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &pending_sockets);
10321509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &creating_sockets);
1033568Smax.romanov@nginx.com 
1034964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1035964Sigor@sysoev.ru 
1036964Sigor@sysoev.ru     nxt_http_routes_cleanup(task, rtcf->routes);
1037964Sigor@sysoev.ru 
1038568Smax.romanov@nginx.com     nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
1039568Smax.romanov@nginx.com 
10401264Sigor@sysoev.ru         if (skcf->action != NULL) {
10411264Sigor@sysoev.ru             nxt_http_action_cleanup(task, skcf->action);
1042568Smax.romanov@nginx.com         }
1043568Smax.romanov@nginx.com 
1044568Smax.romanov@nginx.com     } nxt_queue_loop;
1045568Smax.romanov@nginx.com 
1046507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1047507Smax.romanov@nginx.com 
1048753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1049507Smax.romanov@nginx.com 
1050507Smax.romanov@nginx.com     } nxt_queue_loop;
1051507Smax.romanov@nginx.com 
1052630Svbart@nginx.com     router = rtcf->router;
1053149Sigor@sysoev.ru 
10541509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &keeping_sockets);
10551509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &deleting_sockets);
1056149Sigor@sysoev.ru 
1057416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1058416Smax.romanov@nginx.com 
1059148Sigor@sysoev.ru     // TODO: new engines and threads
1060148Sigor@sysoev.ru 
1061630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1062630Svbart@nginx.com 
1063630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1064139Sigor@sysoev.ru 
1065193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
10661509Sigor@sysoev.ru 
10671509Sigor@sysoev.ru     nxt_mp_destroy(tmcf->mem_pool);
1068139Sigor@sysoev.ru }
1069139Sigor@sysoev.ru 
1070139Sigor@sysoev.ru 
1071139Sigor@sysoev.ru static void
1072139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1073193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1074139Sigor@sysoev.ru {
1075193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1076779Smax.romanov@nginx.com 
1077779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1078779Smax.romanov@nginx.com 
1079779Smax.romanov@nginx.com     tmcf->port = NULL;
1080139Sigor@sysoev.ru }
1081139Sigor@sysoev.ru 
1082139Sigor@sysoev.ru 
1083115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1084115Sigor@sysoev.ru     {
1085133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1086115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1087115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1088115Sigor@sysoev.ru     },
1089115Sigor@sysoev.ru };
1090115Sigor@sysoev.ru 
1091115Sigor@sysoev.ru 
1092133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1093115Sigor@sysoev.ru     {
1094133Sigor@sysoev.ru         nxt_string("type"),
1095115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1096133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1097115Sigor@sysoev.ru     },
1098115Sigor@sysoev.ru 
1099115Sigor@sysoev.ru     {
1100507Smax.romanov@nginx.com         nxt_string("limits"),
1101507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1102507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1103133Sigor@sysoev.ru     },
1104318Smax.romanov@nginx.com 
1105318Smax.romanov@nginx.com     {
1106507Smax.romanov@nginx.com         nxt_string("processes"),
1107507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1108507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1109507Smax.romanov@nginx.com     },
1110507Smax.romanov@nginx.com 
1111507Smax.romanov@nginx.com     {
1112507Smax.romanov@nginx.com         nxt_string("processes"),
1113318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1114507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1115318Smax.romanov@nginx.com     },
11161473Svbart@nginx.com 
11171473Svbart@nginx.com     {
11181473Svbart@nginx.com         nxt_string("targets"),
11191473Svbart@nginx.com         NXT_CONF_MAP_PTR,
11201473Svbart@nginx.com         offsetof(nxt_router_app_conf_t, targets_value),
11211473Svbart@nginx.com     },
1122318Smax.romanov@nginx.com };
1123318Smax.romanov@nginx.com 
1124318Smax.romanov@nginx.com 
1125318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1126318Smax.romanov@nginx.com     {
1127318Smax.romanov@nginx.com         nxt_string("timeout"),
1128318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1129318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1130318Smax.romanov@nginx.com     },
1131318Smax.romanov@nginx.com 
1132318Smax.romanov@nginx.com     {
1133427Smax.romanov@nginx.com         nxt_string("reschedule_timeout"),
1134427Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1135427Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, res_timeout),
1136427Smax.romanov@nginx.com     },
1137427Smax.romanov@nginx.com 
1138427Smax.romanov@nginx.com     {
1139318Smax.romanov@nginx.com         nxt_string("requests"),
1140318Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1141318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, requests),
1142318Smax.romanov@nginx.com     },
1143133Sigor@sysoev.ru };
1144133Sigor@sysoev.ru 
1145133Sigor@sysoev.ru 
1146507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1147507Smax.romanov@nginx.com     {
1148507Smax.romanov@nginx.com         nxt_string("spare"),
1149507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1150507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1151507Smax.romanov@nginx.com     },
1152507Smax.romanov@nginx.com 
1153507Smax.romanov@nginx.com     {
1154507Smax.romanov@nginx.com         nxt_string("max"),
1155507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1156507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1157507Smax.romanov@nginx.com     },
1158507Smax.romanov@nginx.com 
1159507Smax.romanov@nginx.com     {
1160507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1161507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1162507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1163507Smax.romanov@nginx.com     },
1164507Smax.romanov@nginx.com };
1165507Smax.romanov@nginx.com 
1166507Smax.romanov@nginx.com 
1167133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1168133Sigor@sysoev.ru     {
1169964Sigor@sysoev.ru         nxt_string("pass"),
1170964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1171964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1172964Sigor@sysoev.ru     },
1173964Sigor@sysoev.ru 
1174964Sigor@sysoev.ru     {
1175133Sigor@sysoev.ru         nxt_string("application"),
1176964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1177133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1178115Sigor@sysoev.ru     },
1179115Sigor@sysoev.ru };
1180115Sigor@sysoev.ru 
1181115Sigor@sysoev.ru 
1182115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1183115Sigor@sysoev.ru     {
1184115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1185115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1186115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1187115Sigor@sysoev.ru     },
1188115Sigor@sysoev.ru 
1189115Sigor@sysoev.ru     {
1190115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1191115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1192115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1193115Sigor@sysoev.ru     },
1194115Sigor@sysoev.ru 
1195115Sigor@sysoev.ru     {
1196206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1197206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1198206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1199206Smax.romanov@nginx.com     },
1200206Smax.romanov@nginx.com 
1201206Smax.romanov@nginx.com     {
1202206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1203206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1204206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1205206Smax.romanov@nginx.com     },
1206206Smax.romanov@nginx.com 
1207206Smax.romanov@nginx.com     {
1208206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1209206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1210206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1211206Smax.romanov@nginx.com     },
1212206Smax.romanov@nginx.com 
1213206Smax.romanov@nginx.com     {
1214431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1215431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1216431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1217431Sigor@sysoev.ru     },
1218431Sigor@sysoev.ru 
1219431Sigor@sysoev.ru     {
1220115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1221115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1222115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1223115Sigor@sysoev.ru     },
1224206Smax.romanov@nginx.com 
1225206Smax.romanov@nginx.com     {
1226206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1227206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1228206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1229206Smax.romanov@nginx.com     },
1230431Sigor@sysoev.ru 
1231431Sigor@sysoev.ru     {
1232431Sigor@sysoev.ru         nxt_string("send_timeout"),
1233431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1234431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1235431Sigor@sysoev.ru     },
12361403Smax.romanov@nginx.com 
12371403Smax.romanov@nginx.com     {
12381403Smax.romanov@nginx.com         nxt_string("body_temp_path"),
12391403Smax.romanov@nginx.com         NXT_CONF_MAP_STR,
12401403Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_temp_path),
12411403Smax.romanov@nginx.com     },
1242115Sigor@sysoev.ru };
1243115Sigor@sysoev.ru 
1244115Sigor@sysoev.ru 
12451131Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_websocket_conf[] = {
12461131Smax.romanov@nginx.com     {
12471131Smax.romanov@nginx.com         nxt_string("max_frame_size"),
12481131Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
12491131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, max_frame_size),
12501131Smax.romanov@nginx.com     },
12511131Smax.romanov@nginx.com 
12521131Smax.romanov@nginx.com     {
12531131Smax.romanov@nginx.com         nxt_string("read_timeout"),
12541131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
12551131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, read_timeout),
12561131Smax.romanov@nginx.com     },
12571131Smax.romanov@nginx.com 
12581131Smax.romanov@nginx.com     {
12591131Smax.romanov@nginx.com         nxt_string("keepalive_interval"),
12601131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
12611131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, keepalive_interval),
12621131Smax.romanov@nginx.com     },
12631131Smax.romanov@nginx.com 
12641131Smax.romanov@nginx.com };
12651131Smax.romanov@nginx.com 
12661131Smax.romanov@nginx.com 
126753Sigor@sysoev.ru static nxt_int_t
1268115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1269115Sigor@sysoev.ru     u_char *start, u_char *end)
127053Sigor@sysoev.ru {
1271133Sigor@sysoev.ru     u_char                      *p;
1272133Sigor@sysoev.ru     size_t                      size;
12731473Svbart@nginx.com     nxt_mp_t                    *mp, *app_mp;
12741473Svbart@nginx.com     uint32_t                    next, next_target;
1275115Sigor@sysoev.ru     nxt_int_t                   ret;
12761473Svbart@nginx.com     nxt_str_t                   name, path, target;
1277133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
12781473Svbart@nginx.com     nxt_str_t                   *t, *s, *targets;
12791473Svbart@nginx.com     nxt_uint_t                  n, i;
12801547Smax.romanov@nginx.com     nxt_port_t                  *port;
1281359Sigor@sysoev.ru     nxt_router_t                *router;
1282753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
12831131Smax.romanov@nginx.com     nxt_conf_value_t            *conf, *http, *value, *websocket;
1284133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1285133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
12861183Svbart@nginx.com     nxt_conf_value_t            *routes_conf, *static_conf;
1287115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1288964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1289507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1290216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1291133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1292630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1293115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1294774Svbart@nginx.com #if (NXT_TLS)
1295774Svbart@nginx.com     nxt_router_tlssock_t        *tls;
1296774Svbart@nginx.com #endif
1297115Sigor@sysoev.ru 
1298716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1299133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1300115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1301964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1302630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1303774Svbart@nginx.com #if (NXT_TLS)
1304774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1305774Svbart@nginx.com #endif
13061183Svbart@nginx.com     static nxt_str_t  static_path = nxt_string("/settings/http/static");
13071131Smax.romanov@nginx.com     static nxt_str_t  websocket_path = nxt_string("/settings/http/websocket");
1308115Sigor@sysoev.ru 
1309208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1310115Sigor@sysoev.ru     if (conf == NULL) {
1311564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1312115Sigor@sysoev.ru         return NXT_ERROR;
1313115Sigor@sysoev.ru     }
1314115Sigor@sysoev.ru 
1315591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1316213Svbart@nginx.com 
1317213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1318591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1319115Sigor@sysoev.ru     if (ret != NXT_OK) {
1320564Svbart@nginx.com         nxt_alert(task, "root map error");
1321115Sigor@sysoev.ru         return NXT_ERROR;
1322115Sigor@sysoev.ru     }
1323115Sigor@sysoev.ru 
1324591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1325591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1326117Sigor@sysoev.ru     }
1327117Sigor@sysoev.ru 
13281183Svbart@nginx.com     static_conf = nxt_conf_get_path(conf, &static_path);
13291183Svbart@nginx.com 
13301183Svbart@nginx.com     ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
13311183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
13321183Svbart@nginx.com         return NXT_ERROR;
13331183Svbart@nginx.com     }
13341183Svbart@nginx.com 
13351115Svbart@nginx.com     router = tmcf->router_conf->router;
13361115Svbart@nginx.com 
1337133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
13381115Svbart@nginx.com 
13391115Svbart@nginx.com     if (applications != NULL) {
13401115Svbart@nginx.com         next = 0;
13411115Svbart@nginx.com 
13421115Svbart@nginx.com         for ( ;; ) {
13431235Sigor@sysoev.ru             application = nxt_conf_next_object_member(applications,
13441235Sigor@sysoev.ru                                                       &name, &next);
13451115Svbart@nginx.com             if (application == NULL) {
13461115Svbart@nginx.com                 break;
13471115Svbart@nginx.com             }
13481115Svbart@nginx.com 
13491115Svbart@nginx.com             nxt_debug(task, "application \"%V\"", &name);
13501115Svbart@nginx.com 
13511115Svbart@nginx.com             size = nxt_conf_json_length(application, NULL);
13521115Svbart@nginx.com 
13531473Svbart@nginx.com             app_mp = nxt_mp_create(4096, 128, 1024, 64);
13541473Svbart@nginx.com             if (nxt_slow_path(app_mp == NULL)) {
13551473Svbart@nginx.com                 goto fail;
13561473Svbart@nginx.com             }
13571473Svbart@nginx.com 
13581473Svbart@nginx.com             app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size);
13591115Svbart@nginx.com             if (app == NULL) {
13601473Svbart@nginx.com                 goto app_fail;
13611115Svbart@nginx.com             }
13621115Svbart@nginx.com 
13631115Svbart@nginx.com             nxt_memzero(app, sizeof(nxt_app_t));
13641115Svbart@nginx.com 
13651473Svbart@nginx.com             app->mem_pool = app_mp;
13661473Svbart@nginx.com 
13671115Svbart@nginx.com             app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
13681115Svbart@nginx.com             app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
13691115Svbart@nginx.com                                                   + name.length);
13701115Svbart@nginx.com 
13711115Svbart@nginx.com             p = nxt_conf_json_print(app->conf.start, application, NULL);
13721115Svbart@nginx.com             app->conf.length = p - app->conf.start;
13731115Svbart@nginx.com 
13741115Svbart@nginx.com             nxt_assert(app->conf.length <= size);
13751115Svbart@nginx.com 
13761115Svbart@nginx.com             nxt_debug(task, "application conf \"%V\"", &app->conf);
13771115Svbart@nginx.com 
13781115Svbart@nginx.com             prev = nxt_router_app_find(&router->apps, &name);
13791115Svbart@nginx.com 
13801115Svbart@nginx.com             if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
13811473Svbart@nginx.com                 nxt_mp_destroy(app_mp);
13821115Svbart@nginx.com 
13831115Svbart@nginx.com                 nxt_queue_remove(&prev->link);
13841115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
13851115Svbart@nginx.com                 continue;
13861115Svbart@nginx.com             }
13871115Svbart@nginx.com 
13881115Svbart@nginx.com             apcf.processes = 1;
13891115Svbart@nginx.com             apcf.max_processes = 1;
13901115Svbart@nginx.com             apcf.spare_processes = 0;
13911115Svbart@nginx.com             apcf.timeout = 0;
13921115Svbart@nginx.com             apcf.res_timeout = 1000;
13931115Svbart@nginx.com             apcf.idle_timeout = 15000;
13941115Svbart@nginx.com             apcf.requests = 0;
13951115Svbart@nginx.com             apcf.limits_value = NULL;
13961115Svbart@nginx.com             apcf.processes_value = NULL;
13971473Svbart@nginx.com             apcf.targets_value = NULL;
13981115Svbart@nginx.com 
13991115Svbart@nginx.com             app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
14001115Svbart@nginx.com             if (nxt_slow_path(app_joint == NULL)) {
1401318Smax.romanov@nginx.com                 goto app_fail;
1402318Smax.romanov@nginx.com             }
1403318Smax.romanov@nginx.com 
14041115Svbart@nginx.com             nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
14051115Svbart@nginx.com 
14061115Svbart@nginx.com             ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
14071115Svbart@nginx.com                                       nxt_nitems(nxt_router_app_conf), &apcf);
1408318Smax.romanov@nginx.com             if (ret != NXT_OK) {
14091115Svbart@nginx.com                 nxt_alert(task, "application map error");
1410318Smax.romanov@nginx.com                 goto app_fail;
1411318Smax.romanov@nginx.com             }
14121115Svbart@nginx.com 
14131115Svbart@nginx.com             if (apcf.limits_value != NULL) {
14141115Svbart@nginx.com 
14151115Svbart@nginx.com                 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
14161115Svbart@nginx.com                     nxt_alert(task, "application limits is not object");
14171115Svbart@nginx.com                     goto app_fail;
14181115Svbart@nginx.com                 }
14191115Svbart@nginx.com 
14201115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.limits_value,
14211115Svbart@nginx.com                                         nxt_router_app_limits_conf,
14221115Svbart@nginx.com                                         nxt_nitems(nxt_router_app_limits_conf),
14231115Svbart@nginx.com                                         &apcf);
14241115Svbart@nginx.com                 if (ret != NXT_OK) {
14251115Svbart@nginx.com                     nxt_alert(task, "application limits map error");
14261115Svbart@nginx.com                     goto app_fail;
14271115Svbart@nginx.com                 }
14281115Svbart@nginx.com             }
14291115Svbart@nginx.com 
14301115Svbart@nginx.com             if (apcf.processes_value != NULL
14311115Svbart@nginx.com                 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
14321115Svbart@nginx.com             {
14331115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.processes_value,
14341115Svbart@nginx.com                                      nxt_router_app_processes_conf,
14351115Svbart@nginx.com                                      nxt_nitems(nxt_router_app_processes_conf),
14361115Svbart@nginx.com                                      &apcf);
14371115Svbart@nginx.com                 if (ret != NXT_OK) {
14381115Svbart@nginx.com                     nxt_alert(task, "application processes map error");
14391115Svbart@nginx.com                     goto app_fail;
14401115Svbart@nginx.com                 }
14411115Svbart@nginx.com 
14421115Svbart@nginx.com             } else {
14431115Svbart@nginx.com                 apcf.max_processes = apcf.processes;
14441115Svbart@nginx.com                 apcf.spare_processes = apcf.processes;
14451115Svbart@nginx.com             }
14461115Svbart@nginx.com 
14471473Svbart@nginx.com             if (apcf.targets_value != NULL) {
14481473Svbart@nginx.com                 n = nxt_conf_object_members_count(apcf.targets_value);
14491473Svbart@nginx.com 
14501473Svbart@nginx.com                 targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n);
14511473Svbart@nginx.com                 if (nxt_slow_path(targets == NULL)) {
14521473Svbart@nginx.com                     goto app_fail;
14531473Svbart@nginx.com                 }
14541473Svbart@nginx.com 
14551473Svbart@nginx.com                 next_target = 0;
14561473Svbart@nginx.com 
14571473Svbart@nginx.com                 for (i = 0; i < n; i++) {
14581480Svbart@nginx.com                     (void) nxt_conf_next_object_member(apcf.targets_value,
14591480Svbart@nginx.com                                                        &target, &next_target);
14601473Svbart@nginx.com 
14611473Svbart@nginx.com                     s = nxt_str_dup(app_mp, &targets[i], &target);
14621473Svbart@nginx.com                     if (nxt_slow_path(s == NULL)) {
14631473Svbart@nginx.com                         goto app_fail;
14641473Svbart@nginx.com                     }
14651473Svbart@nginx.com                 }
14661473Svbart@nginx.com 
14671473Svbart@nginx.com             } else {
14681473Svbart@nginx.com                 targets = NULL;
14691473Svbart@nginx.com             }
14701473Svbart@nginx.com 
14711115Svbart@nginx.com             nxt_debug(task, "application type: %V", &apcf.type);
14721115Svbart@nginx.com             nxt_debug(task, "application processes: %D", apcf.processes);
14731115Svbart@nginx.com             nxt_debug(task, "application request timeout: %M", apcf.timeout);
14741115Svbart@nginx.com             nxt_debug(task, "application reschedule timeout: %M",
14751115Svbart@nginx.com                       apcf.res_timeout);
14761115Svbart@nginx.com             nxt_debug(task, "application requests: %D", apcf.requests);
14771115Svbart@nginx.com 
14781115Svbart@nginx.com             lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
14791115Svbart@nginx.com 
14801115Svbart@nginx.com             if (lang == NULL) {
14811115Svbart@nginx.com                 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1482507Smax.romanov@nginx.com                 goto app_fail;
1483507Smax.romanov@nginx.com             }
1484507Smax.romanov@nginx.com 
14851115Svbart@nginx.com             nxt_debug(task, "application language module: \"%s\"", lang->file);
14861115Svbart@nginx.com 
14871115Svbart@nginx.com             ret = nxt_thread_mutex_create(&app->mutex);
14881115Svbart@nginx.com             if (ret != NXT_OK) {
14891115Svbart@nginx.com                 goto app_fail;
14901115Svbart@nginx.com             }
14911115Svbart@nginx.com 
14921115Svbart@nginx.com             nxt_queue_init(&app->ports);
14931115Svbart@nginx.com             nxt_queue_init(&app->spare_ports);
14941115Svbart@nginx.com             nxt_queue_init(&app->idle_ports);
14951115Svbart@nginx.com 
14961115Svbart@nginx.com             app->name.length = name.length;
14971115Svbart@nginx.com             nxt_memcpy(app->name.start, name.start, name.length);
14981115Svbart@nginx.com 
14991115Svbart@nginx.com             app->type = lang->type;
15001115Svbart@nginx.com             app->max_processes = apcf.max_processes;
15011115Svbart@nginx.com             app->spare_processes = apcf.spare_processes;
15021115Svbart@nginx.com             app->max_pending_processes = apcf.spare_processes
15031115Svbart@nginx.com                                          ? apcf.spare_processes : 1;
15041115Svbart@nginx.com             app->timeout = apcf.timeout;
15051115Svbart@nginx.com             app->res_timeout = apcf.res_timeout * 1000000;
15061115Svbart@nginx.com             app->idle_timeout = apcf.idle_timeout;
15071115Svbart@nginx.com             app->max_requests = apcf.requests;
15081115Svbart@nginx.com 
15091473Svbart@nginx.com             app->targets = targets;
15101473Svbart@nginx.com 
15111115Svbart@nginx.com             engine = task->thread->engine;
15121115Svbart@nginx.com 
15131115Svbart@nginx.com             app->engine = engine;
15141115Svbart@nginx.com 
15151115Svbart@nginx.com             app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
15161115Svbart@nginx.com             app->adjust_idle_work.task = &engine->task;
15171115Svbart@nginx.com             app->adjust_idle_work.obj = app;
15181115Svbart@nginx.com 
15191115Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->apps, &app->link);
15201115Svbart@nginx.com 
15211115Svbart@nginx.com             nxt_router_app_use(task, app, 1);
15221115Svbart@nginx.com 
15231115Svbart@nginx.com             app->joint = app_joint;
15241115Svbart@nginx.com 
15251115Svbart@nginx.com             app_joint->use_count = 1;
15261115Svbart@nginx.com             app_joint->app = app;
15271115Svbart@nginx.com 
15281115Svbart@nginx.com             app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
15291115Svbart@nginx.com             app_joint->idle_timer.work_queue = &engine->fast_work_queue;
15301115Svbart@nginx.com             app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
15311115Svbart@nginx.com             app_joint->idle_timer.task = &engine->task;
15321115Svbart@nginx.com             app_joint->idle_timer.log = app_joint->idle_timer.task->log;
15331115Svbart@nginx.com 
15341115Svbart@nginx.com             app_joint->free_app_work.handler = nxt_router_free_app;
15351115Svbart@nginx.com             app_joint->free_app_work.task = &engine->task;
15361115Svbart@nginx.com             app_joint->free_app_work.obj = app_joint;
15371547Smax.romanov@nginx.com 
15381547Smax.romanov@nginx.com             port = nxt_port_new(task, (nxt_port_id_t) -1, nxt_pid,
15391547Smax.romanov@nginx.com                                 NXT_PROCESS_APP);
15401547Smax.romanov@nginx.com             if (nxt_slow_path(port == NULL)) {
15411547Smax.romanov@nginx.com                 return NXT_ERROR;
15421547Smax.romanov@nginx.com             }
15431547Smax.romanov@nginx.com 
15441547Smax.romanov@nginx.com             ret = nxt_port_socket_init(task, port, 0);
15451547Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
15461547Smax.romanov@nginx.com                 nxt_port_use(task, port, -1);
15471547Smax.romanov@nginx.com                 return NXT_ERROR;
15481547Smax.romanov@nginx.com             }
15491547Smax.romanov@nginx.com 
15501555Smax.romanov@nginx.com             ret = nxt_router_app_queue_init(task, port);
15511555Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
15521555Smax.romanov@nginx.com                 nxt_port_use(task, port, -1);
15531555Smax.romanov@nginx.com                 return NXT_ERROR;
15541555Smax.romanov@nginx.com             }
15551555Smax.romanov@nginx.com 
15561547Smax.romanov@nginx.com             nxt_port_write_enable(task, port);
15571547Smax.romanov@nginx.com             port->app = app;
15581547Smax.romanov@nginx.com 
15591547Smax.romanov@nginx.com             app->shared_port = port;
15601547Smax.romanov@nginx.com 
15611547Smax.romanov@nginx.com             nxt_thread_mutex_create(&app->outgoing.mutex);
1562133Sigor@sysoev.ru         }
1563133Sigor@sysoev.ru     }
1564133Sigor@sysoev.ru 
1565964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1566964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1567964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1568964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1569964Sigor@sysoev.ru             return NXT_ERROR;
1570964Sigor@sysoev.ru         }
1571964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1572964Sigor@sysoev.ru     }
1573964Sigor@sysoev.ru 
15741394Sigor@sysoev.ru     ret = nxt_upstreams_create(task, tmcf, conf);
15751394Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
15761394Sigor@sysoev.ru         return ret;
15771394Sigor@sysoev.ru     }
15781394Sigor@sysoev.ru 
1579133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1580133Sigor@sysoev.ru #if 0
1581133Sigor@sysoev.ru     if (http == NULL) {
1582564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1583133Sigor@sysoev.ru         return NXT_ERROR;
1584133Sigor@sysoev.ru     }
1585133Sigor@sysoev.ru #endif
1586133Sigor@sysoev.ru 
15871131Smax.romanov@nginx.com     websocket = nxt_conf_get_path(conf, &websocket_path);
15881131Smax.romanov@nginx.com 
1589133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
15901115Svbart@nginx.com 
15911115Svbart@nginx.com     if (listeners != NULL) {
15921115Svbart@nginx.com         next = 0;
15931115Svbart@nginx.com 
15941115Svbart@nginx.com         for ( ;; ) {
15951115Svbart@nginx.com             listener = nxt_conf_next_object_member(listeners, &name, &next);
15961115Svbart@nginx.com             if (listener == NULL) {
15971115Svbart@nginx.com                 break;
15981115Svbart@nginx.com             }
15991115Svbart@nginx.com 
16001115Svbart@nginx.com             skcf = nxt_router_socket_conf(task, tmcf, &name);
16011115Svbart@nginx.com             if (skcf == NULL) {
16021115Svbart@nginx.com                 goto fail;
16031115Svbart@nginx.com             }
16041115Svbart@nginx.com 
16051115Svbart@nginx.com             nxt_memzero(&lscf, sizeof(lscf));
16061115Svbart@nginx.com 
16071115Svbart@nginx.com             ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
16081115Svbart@nginx.com                                       nxt_nitems(nxt_router_listener_conf),
16091115Svbart@nginx.com                                       &lscf);
1610133Sigor@sysoev.ru             if (ret != NXT_OK) {
16111115Svbart@nginx.com                 nxt_alert(task, "listener map error");
1612133Sigor@sysoev.ru                 goto fail;
1613133Sigor@sysoev.ru             }
16141115Svbart@nginx.com 
16151115Svbart@nginx.com             nxt_debug(task, "application: %V", &lscf.application);
16161115Svbart@nginx.com 
16171115Svbart@nginx.com             // STUB, default values if http block is not defined.
16181115Svbart@nginx.com             skcf->header_buffer_size = 2048;
16191115Svbart@nginx.com             skcf->large_header_buffer_size = 8192;
16201115Svbart@nginx.com             skcf->large_header_buffers = 4;
16211115Svbart@nginx.com             skcf->body_buffer_size = 16 * 1024;
16221115Svbart@nginx.com             skcf->max_body_size = 8 * 1024 * 1024;
16231270Sigor@sysoev.ru             skcf->proxy_header_buffer_size = 64 * 1024;
16241270Sigor@sysoev.ru             skcf->proxy_buffer_size = 4096;
16251270Sigor@sysoev.ru             skcf->proxy_buffers = 256;
16261115Svbart@nginx.com             skcf->idle_timeout = 180 * 1000;
16271115Svbart@nginx.com             skcf->header_read_timeout = 30 * 1000;
16281115Svbart@nginx.com             skcf->body_read_timeout = 30 * 1000;
16291115Svbart@nginx.com             skcf->send_timeout = 30 * 1000;
16301270Sigor@sysoev.ru             skcf->proxy_timeout = 60 * 1000;
16311270Sigor@sysoev.ru             skcf->proxy_send_timeout = 30 * 1000;
16321270Sigor@sysoev.ru             skcf->proxy_read_timeout = 30 * 1000;
16331115Svbart@nginx.com 
16341131Smax.romanov@nginx.com             skcf->websocket_conf.max_frame_size = 1024 * 1024;
16351131Smax.romanov@nginx.com             skcf->websocket_conf.read_timeout = 60 * 1000;
16361131Smax.romanov@nginx.com             skcf->websocket_conf.keepalive_interval = 30 * 1000;
16371131Smax.romanov@nginx.com 
16381403Smax.romanov@nginx.com             nxt_str_null(&skcf->body_temp_path);
16391403Smax.romanov@nginx.com 
16401115Svbart@nginx.com             if (http != NULL) {
16411115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
16421115Svbart@nginx.com                                           nxt_nitems(nxt_router_http_conf),
16431115Svbart@nginx.com                                           skcf);
16441115Svbart@nginx.com                 if (ret != NXT_OK) {
16451115Svbart@nginx.com                     nxt_alert(task, "http map error");
16461115Svbart@nginx.com                     goto fail;
16471115Svbart@nginx.com                 }
16481115Svbart@nginx.com             }
1649115Sigor@sysoev.ru 
16501131Smax.romanov@nginx.com             if (websocket != NULL) {
16511131Smax.romanov@nginx.com                 ret = nxt_conf_map_object(mp, websocket,
16521131Smax.romanov@nginx.com                                           nxt_router_websocket_conf,
16531131Smax.romanov@nginx.com                                           nxt_nitems(nxt_router_websocket_conf),
16541131Smax.romanov@nginx.com                                           &skcf->websocket_conf);
16551131Smax.romanov@nginx.com                 if (ret != NXT_OK) {
16561131Smax.romanov@nginx.com                     nxt_alert(task, "websocket map error");
16571131Smax.romanov@nginx.com                     goto fail;
16581131Smax.romanov@nginx.com                 }
16591131Smax.romanov@nginx.com             }
16601131Smax.romanov@nginx.com 
16611403Smax.romanov@nginx.com             t = &skcf->body_temp_path;
16621403Smax.romanov@nginx.com 
16631403Smax.romanov@nginx.com             if (t->length == 0) {
16641403Smax.romanov@nginx.com                 t->start = (u_char *) task->thread->runtime->tmp;
16651403Smax.romanov@nginx.com                 t->length = nxt_strlen(t->start);
16661403Smax.romanov@nginx.com             }
16671403Smax.romanov@nginx.com 
1668774Svbart@nginx.com #if (NXT_TLS)
16691115Svbart@nginx.com             value = nxt_conf_get_path(listener, &certificate_path);
16701115Svbart@nginx.com 
16711115Svbart@nginx.com             if (value != NULL) {
16721115Svbart@nginx.com                 nxt_conf_get_string(value, &name);
16731115Svbart@nginx.com 
16741115Svbart@nginx.com                 tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
16751115Svbart@nginx.com                 if (nxt_slow_path(tls == NULL)) {
16761115Svbart@nginx.com                     goto fail;
16771115Svbart@nginx.com                 }
16781115Svbart@nginx.com 
16791115Svbart@nginx.com                 tls->name = name;
16801115Svbart@nginx.com                 tls->conf = skcf;
16811115Svbart@nginx.com 
16821115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1683774Svbart@nginx.com             }
1684774Svbart@nginx.com #endif
1685774Svbart@nginx.com 
16861115Svbart@nginx.com             skcf->listen->handler = nxt_http_conn_init;
16871115Svbart@nginx.com             skcf->router_conf = tmcf->router_conf;
16881115Svbart@nginx.com             skcf->router_conf->count++;
16891115Svbart@nginx.com 
16901115Svbart@nginx.com             if (lscf.pass.length != 0) {
16911264Sigor@sysoev.ru                 skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass);
16921115Svbart@nginx.com 
16931115Svbart@nginx.com             /* COMPATIBILITY: listener application. */
16941115Svbart@nginx.com             } else if (lscf.application.length > 0) {
16951264Sigor@sysoev.ru                 skcf->action = nxt_http_pass_application(task, tmcf,
16961264Sigor@sysoev.ru                                                          &lscf.application);
16971115Svbart@nginx.com             }
1698770Smax.romanov@nginx.com         }
1699115Sigor@sysoev.ru     }
170053Sigor@sysoev.ru 
17011472Svbart@nginx.com     ret = nxt_http_routes_resolve(task, tmcf);
17021472Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
17031472Svbart@nginx.com         goto fail;
17041472Svbart@nginx.com     }
17051472Svbart@nginx.com 
1706630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1707630Svbart@nginx.com 
1708630Svbart@nginx.com     if (value != NULL) {
1709630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1710630Svbart@nginx.com 
1711630Svbart@nginx.com         access_log = router->access_log;
1712630Svbart@nginx.com 
1713630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1714630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1715630Svbart@nginx.com             access_log->count++;
1716630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1717630Svbart@nginx.com 
1718630Svbart@nginx.com         } else {
1719630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1720630Svbart@nginx.com                                     + path.length);
1721630Svbart@nginx.com             if (access_log == NULL) {
1722630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1723630Svbart@nginx.com                 goto fail;
1724630Svbart@nginx.com             }
1725630Svbart@nginx.com 
1726630Svbart@nginx.com             access_log->fd = -1;
1727630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1728630Svbart@nginx.com             access_log->count = 1;
1729630Svbart@nginx.com 
1730630Svbart@nginx.com             access_log->path.length = path.length;
1731630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1732630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1733630Svbart@nginx.com 
1734630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1735630Svbart@nginx.com         }
1736630Svbart@nginx.com 
1737630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1738630Svbart@nginx.com     }
1739630Svbart@nginx.com 
17401509Sigor@sysoev.ru     nxt_queue_add(&deleting_sockets, &router->sockets);
1741359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
1742198Sigor@sysoev.ru 
174353Sigor@sysoev.ru     return NXT_OK;
1744133Sigor@sysoev.ru 
1745133Sigor@sysoev.ru app_fail:
1746133Sigor@sysoev.ru 
17471473Svbart@nginx.com     nxt_mp_destroy(app_mp);
1748133Sigor@sysoev.ru 
1749133Sigor@sysoev.ru fail:
1750133Sigor@sysoev.ru 
1751141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1752141Smax.romanov@nginx.com 
1753141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
1754133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
17551473Svbart@nginx.com         nxt_mp_destroy(app->mem_pool);
1756141Smax.romanov@nginx.com 
1757141Smax.romanov@nginx.com     } nxt_queue_loop;
1758133Sigor@sysoev.ru 
1759133Sigor@sysoev.ru     return NXT_ERROR;
1760133Sigor@sysoev.ru }
1761133Sigor@sysoev.ru 
1762133Sigor@sysoev.ru 
17631183Svbart@nginx.com static nxt_int_t
17641183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
17651183Svbart@nginx.com     nxt_conf_value_t *conf)
17661183Svbart@nginx.com {
17671183Svbart@nginx.com     uint32_t          next, i;
17681183Svbart@nginx.com     nxt_mp_t          *mp;
17691183Svbart@nginx.com     nxt_str_t         *type, extension, str;
17701183Svbart@nginx.com     nxt_int_t         ret;
17711183Svbart@nginx.com     nxt_uint_t        exts;
17721183Svbart@nginx.com     nxt_conf_value_t  *mtypes_conf, *ext_conf, *value;
17731183Svbart@nginx.com 
17741183Svbart@nginx.com     static nxt_str_t  mtypes_path = nxt_string("/mime_types");
17751183Svbart@nginx.com 
17761183Svbart@nginx.com     mp = rtcf->mem_pool;
17771183Svbart@nginx.com 
17781183Svbart@nginx.com     ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
17791183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
17801183Svbart@nginx.com         return NXT_ERROR;
17811183Svbart@nginx.com     }
17821183Svbart@nginx.com 
17831183Svbart@nginx.com     if (conf == NULL) {
17841183Svbart@nginx.com         return NXT_OK;
17851183Svbart@nginx.com     }
17861183Svbart@nginx.com 
17871183Svbart@nginx.com     mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
17881183Svbart@nginx.com 
17891183Svbart@nginx.com     if (mtypes_conf != NULL) {
17901183Svbart@nginx.com         next = 0;
17911183Svbart@nginx.com 
17921183Svbart@nginx.com         for ( ;; ) {
17931183Svbart@nginx.com             ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
17941183Svbart@nginx.com 
17951183Svbart@nginx.com             if (ext_conf == NULL) {
17961183Svbart@nginx.com                 break;
17971183Svbart@nginx.com             }
17981183Svbart@nginx.com 
17991183Svbart@nginx.com             type = nxt_str_dup(mp, NULL, &str);
18001183Svbart@nginx.com             if (nxt_slow_path(type == NULL)) {
18011183Svbart@nginx.com                 return NXT_ERROR;
18021183Svbart@nginx.com             }
18031183Svbart@nginx.com 
18041183Svbart@nginx.com             if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
18051183Svbart@nginx.com                 nxt_conf_get_string(ext_conf, &str);
18061183Svbart@nginx.com 
18071183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
18081183Svbart@nginx.com                     return NXT_ERROR;
18091183Svbart@nginx.com                 }
18101183Svbart@nginx.com 
18111183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
18121183Svbart@nginx.com                                                       &extension, type);
18131183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
18141183Svbart@nginx.com                     return NXT_ERROR;
18151183Svbart@nginx.com                 }
18161183Svbart@nginx.com 
18171183Svbart@nginx.com                 continue;
18181183Svbart@nginx.com             }
18191183Svbart@nginx.com 
18201183Svbart@nginx.com             exts = nxt_conf_array_elements_count(ext_conf);
18211183Svbart@nginx.com 
18221183Svbart@nginx.com             for (i = 0; i < exts; i++) {
18231183Svbart@nginx.com                 value = nxt_conf_get_array_element(ext_conf, i);
18241183Svbart@nginx.com 
18251183Svbart@nginx.com                 nxt_conf_get_string(value, &str);
18261183Svbart@nginx.com 
18271183Svbart@nginx.com                 if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
18281183Svbart@nginx.com                     return NXT_ERROR;
18291183Svbart@nginx.com                 }
18301183Svbart@nginx.com 
18311183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
18321183Svbart@nginx.com                                                       &extension, type);
18331183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
18341183Svbart@nginx.com                     return NXT_ERROR;
18351183Svbart@nginx.com                 }
18361183Svbart@nginx.com             }
18371183Svbart@nginx.com         }
18381183Svbart@nginx.com     }
18391183Svbart@nginx.com 
18401183Svbart@nginx.com     return NXT_OK;
18411183Svbart@nginx.com }
18421183Svbart@nginx.com 
18431183Svbart@nginx.com 
1844133Sigor@sysoev.ru static nxt_app_t *
1845133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1846133Sigor@sysoev.ru {
1847141Smax.romanov@nginx.com     nxt_app_t  *app;
1848141Smax.romanov@nginx.com 
1849141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
1850133Sigor@sysoev.ru 
1851133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
1852133Sigor@sysoev.ru             return app;
1853133Sigor@sysoev.ru         }
1854141Smax.romanov@nginx.com 
1855141Smax.romanov@nginx.com     } nxt_queue_loop;
1856133Sigor@sysoev.ru 
1857133Sigor@sysoev.ru     return NULL;
1858133Sigor@sysoev.ru }
1859133Sigor@sysoev.ru 
1860133Sigor@sysoev.ru 
18611555Smax.romanov@nginx.com static nxt_int_t
18621555Smax.romanov@nginx.com nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port)
18631555Smax.romanov@nginx.com {
18641555Smax.romanov@nginx.com     void       *mem;
18651555Smax.romanov@nginx.com     nxt_int_t  fd;
18661555Smax.romanov@nginx.com 
18671555Smax.romanov@nginx.com     fd = nxt_shm_open(task, sizeof(nxt_app_queue_t));
18681555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
18691555Smax.romanov@nginx.com         return NXT_ERROR;
18701555Smax.romanov@nginx.com     }
18711555Smax.romanov@nginx.com 
18721555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t),
18731555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
18741555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
18751555Smax.romanov@nginx.com         nxt_fd_close(fd);
18761555Smax.romanov@nginx.com 
18771555Smax.romanov@nginx.com         return NXT_ERROR;
18781555Smax.romanov@nginx.com     }
18791555Smax.romanov@nginx.com 
18801555Smax.romanov@nginx.com     nxt_app_queue_init(mem);
18811555Smax.romanov@nginx.com 
18821555Smax.romanov@nginx.com     port->queue_fd = fd;
18831555Smax.romanov@nginx.com     port->queue = mem;
18841555Smax.romanov@nginx.com 
18851555Smax.romanov@nginx.com     return NXT_OK;
18861555Smax.romanov@nginx.com }
18871555Smax.romanov@nginx.com 
18881555Smax.romanov@nginx.com 
18891555Smax.romanov@nginx.com static nxt_int_t
18901555Smax.romanov@nginx.com nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port)
18911555Smax.romanov@nginx.com {
18921555Smax.romanov@nginx.com     void       *mem;
18931555Smax.romanov@nginx.com     nxt_int_t  fd;
18941555Smax.romanov@nginx.com 
18951555Smax.romanov@nginx.com     fd = nxt_shm_open(task, sizeof(nxt_port_queue_t));
18961555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
18971555Smax.romanov@nginx.com         return NXT_ERROR;
18981555Smax.romanov@nginx.com     }
18991555Smax.romanov@nginx.com 
19001555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
19011555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
19021555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
19031555Smax.romanov@nginx.com         nxt_fd_close(fd);
19041555Smax.romanov@nginx.com 
19051555Smax.romanov@nginx.com         return NXT_ERROR;
19061555Smax.romanov@nginx.com     }
19071555Smax.romanov@nginx.com 
19081555Smax.romanov@nginx.com     nxt_port_queue_init(mem);
19091555Smax.romanov@nginx.com 
19101555Smax.romanov@nginx.com     port->queue_fd = fd;
19111555Smax.romanov@nginx.com     port->queue = mem;
19121555Smax.romanov@nginx.com 
19131555Smax.romanov@nginx.com     return NXT_OK;
19141555Smax.romanov@nginx.com }
19151555Smax.romanov@nginx.com 
19161555Smax.romanov@nginx.com 
19171555Smax.romanov@nginx.com static nxt_int_t
19181555Smax.romanov@nginx.com nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd)
19191555Smax.romanov@nginx.com {
19201555Smax.romanov@nginx.com     void  *mem;
19211555Smax.romanov@nginx.com 
19221555Smax.romanov@nginx.com     nxt_assert(fd != -1);
19231555Smax.romanov@nginx.com 
19241555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
19251555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
19261555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
19271555Smax.romanov@nginx.com 
19281555Smax.romanov@nginx.com         return NXT_ERROR;
19291555Smax.romanov@nginx.com     }
19301555Smax.romanov@nginx.com 
19311555Smax.romanov@nginx.com     port->queue = mem;
19321555Smax.romanov@nginx.com 
19331555Smax.romanov@nginx.com     return NXT_OK;
19341555Smax.romanov@nginx.com }
19351555Smax.romanov@nginx.com 
19361555Smax.romanov@nginx.com 
19371392Sigor@sysoev.ru void
19381392Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name,
19391392Sigor@sysoev.ru     nxt_http_action_t *action)
1940133Sigor@sysoev.ru {
1941133Sigor@sysoev.ru     nxt_app_t  *app;
1942133Sigor@sysoev.ru 
1943133Sigor@sysoev.ru     app = nxt_router_app_find(&tmcf->apps, name);
1944133Sigor@sysoev.ru 
1945133Sigor@sysoev.ru     if (app == NULL) {
1946134Sigor@sysoev.ru         app = nxt_router_app_find(&tmcf->previous, name);
1947133Sigor@sysoev.ru     }
1948133Sigor@sysoev.ru 
19491392Sigor@sysoev.ru     action->u.application = app;
19501392Sigor@sysoev.ru     action->handler = nxt_http_application_handler;
195153Sigor@sysoev.ru }
195253Sigor@sysoev.ru 
195353Sigor@sysoev.ru 
195453Sigor@sysoev.ru static nxt_socket_conf_t *
1955359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1956359Sigor@sysoev.ru     nxt_str_t *name)
195753Sigor@sysoev.ru {
1958359Sigor@sysoev.ru     size_t               size;
1959359Sigor@sysoev.ru     nxt_int_t            ret;
1960359Sigor@sysoev.ru     nxt_bool_t           wildcard;
1961359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
1962359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
1963359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
1964359Sigor@sysoev.ru 
1965359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
1966359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
1967564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
1968359Sigor@sysoev.ru         return NULL;
1969359Sigor@sysoev.ru     }
1970359Sigor@sysoev.ru 
1971359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
1972359Sigor@sysoev.ru 
1973359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
1974493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
1975359Sigor@sysoev.ru 
1976591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
1977163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
197853Sigor@sysoev.ru         return NULL;
197953Sigor@sysoev.ru     }
198053Sigor@sysoev.ru 
1981359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
1982359Sigor@sysoev.ru 
1983359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
1984359Sigor@sysoev.ru 
1985359Sigor@sysoev.ru     if (ret != NXT_OK) {
1986359Sigor@sysoev.ru 
1987359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
1988359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
1989359Sigor@sysoev.ru             return NULL;
1990359Sigor@sysoev.ru         }
1991359Sigor@sysoev.ru 
1992359Sigor@sysoev.ru         skcf->listen = ls;
1993359Sigor@sysoev.ru 
1994359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
1995359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
1996359Sigor@sysoev.ru 
1997359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
1998359Sigor@sysoev.ru 
1999359Sigor@sysoev.ru         ls->socket = -1;
2000359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
2001359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
2002359Sigor@sysoev.ru         ls->read_after_accept = 1;
2003359Sigor@sysoev.ru     }
2004359Sigor@sysoev.ru 
2005359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
2006359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
2007359Sigor@sysoev.ru     case AF_UNIX:
2008359Sigor@sysoev.ru         wildcard = 0;
2009359Sigor@sysoev.ru         break;
2010359Sigor@sysoev.ru #endif
2011359Sigor@sysoev.ru #if (NXT_INET6)
2012359Sigor@sysoev.ru     case AF_INET6:
2013359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
2014359Sigor@sysoev.ru         break;
2015359Sigor@sysoev.ru #endif
2016359Sigor@sysoev.ru     case AF_INET:
2017359Sigor@sysoev.ru     default:
2018359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
2019359Sigor@sysoev.ru         break;
2020359Sigor@sysoev.ru     }
2021359Sigor@sysoev.ru 
2022359Sigor@sysoev.ru     if (!wildcard) {
2023591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
2024359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
2025359Sigor@sysoev.ru             return NULL;
2026359Sigor@sysoev.ru         }
2027359Sigor@sysoev.ru 
2028359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
2029359Sigor@sysoev.ru     }
2030163Smax.romanov@nginx.com 
2031163Smax.romanov@nginx.com     return skcf;
203253Sigor@sysoev.ru }
203353Sigor@sysoev.ru 
203453Sigor@sysoev.ru 
2035359Sigor@sysoev.ru static nxt_int_t
2036359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
2037359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
203853Sigor@sysoev.ru {
2039359Sigor@sysoev.ru     nxt_router_t       *router;
2040359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
2041359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
2042359Sigor@sysoev.ru 
2043591Sigor@sysoev.ru     router = tmcf->router_conf->router;
2044359Sigor@sysoev.ru 
2045359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
2046359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
2047359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
204853Sigor@sysoev.ru     {
2049359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2050359Sigor@sysoev.ru 
2051359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2052359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
2053359Sigor@sysoev.ru 
2054359Sigor@sysoev.ru             nxt_queue_remove(qlk);
20551509Sigor@sysoev.ru             nxt_queue_insert_tail(&keeping_sockets, qlk);
20561509Sigor@sysoev.ru 
20571509Sigor@sysoev.ru             nxt_queue_insert_tail(&updating_sockets, &nskcf->link);
2058359Sigor@sysoev.ru 
2059359Sigor@sysoev.ru             return NXT_OK;
206053Sigor@sysoev.ru         }
206153Sigor@sysoev.ru     }
206253Sigor@sysoev.ru 
20631509Sigor@sysoev.ru     nxt_queue_insert_tail(&pending_sockets, &nskcf->link);
2064359Sigor@sysoev.ru 
2065359Sigor@sysoev.ru     return NXT_DECLINED;
206653Sigor@sysoev.ru }
206753Sigor@sysoev.ru 
206853Sigor@sysoev.ru 
2069198Sigor@sysoev.ru static void
2070198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2071198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2072198Sigor@sysoev.ru {
2073358Sigor@sysoev.ru     size_t            size;
2074198Sigor@sysoev.ru     uint32_t          stream;
2075648Svbart@nginx.com     nxt_int_t         ret;
2076198Sigor@sysoev.ru     nxt_buf_t         *b;
2077198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
2078198Sigor@sysoev.ru     nxt_runtime_t     *rt;
2079198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
2080198Sigor@sysoev.ru 
2081198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2082198Sigor@sysoev.ru     if (rpc == NULL) {
2083198Sigor@sysoev.ru         goto fail;
2084198Sigor@sysoev.ru     }
2085198Sigor@sysoev.ru 
2086198Sigor@sysoev.ru     rpc->socket_conf = skcf;
2087198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
2088198Sigor@sysoev.ru 
2089359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
2090358Sigor@sysoev.ru 
2091358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2092198Sigor@sysoev.ru     if (b == NULL) {
2093198Sigor@sysoev.ru         goto fail;
2094198Sigor@sysoev.ru     }
2095198Sigor@sysoev.ru 
2096359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2097198Sigor@sysoev.ru 
2098198Sigor@sysoev.ru     rt = task->thread->runtime;
2099240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2100198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2101198Sigor@sysoev.ru 
2102198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
2103198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
2104198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
2105198Sigor@sysoev.ru                                            main_port->pid, rpc);
2106645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
2107198Sigor@sysoev.ru         goto fail;
2108198Sigor@sysoev.ru     }
2109198Sigor@sysoev.ru 
2110648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2111648Svbart@nginx.com                                 stream, router_port->id, b);
2112648Svbart@nginx.com 
2113648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2114648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2115648Svbart@nginx.com         goto fail;
2116648Svbart@nginx.com     }
2117198Sigor@sysoev.ru 
2118198Sigor@sysoev.ru     return;
2119198Sigor@sysoev.ru 
2120198Sigor@sysoev.ru fail:
2121198Sigor@sysoev.ru 
2122198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
2123198Sigor@sysoev.ru }
2124198Sigor@sysoev.ru 
2125198Sigor@sysoev.ru 
2126198Sigor@sysoev.ru static void
2127198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2128198Sigor@sysoev.ru     void *data)
212953Sigor@sysoev.ru {
2130359Sigor@sysoev.ru     nxt_int_t         ret;
2131359Sigor@sysoev.ru     nxt_socket_t      s;
2132359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
213353Sigor@sysoev.ru 
2134198Sigor@sysoev.ru     rpc = data;
2135198Sigor@sysoev.ru 
2136*1558Smax.romanov@nginx.com     s = msg->fd[0];
2137198Sigor@sysoev.ru 
2138198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
2139198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2140198Sigor@sysoev.ru         goto fail;
214153Sigor@sysoev.ru     }
214253Sigor@sysoev.ru 
2143359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2144198Sigor@sysoev.ru 
2145198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2146198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2147198Sigor@sysoev.ru         goto fail;
2148198Sigor@sysoev.ru     }
2149198Sigor@sysoev.ru 
2150359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
2151198Sigor@sysoev.ru 
2152198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2153198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2154198Sigor@sysoev.ru 
2155198Sigor@sysoev.ru     return;
2156148Sigor@sysoev.ru 
2157148Sigor@sysoev.ru fail:
2158148Sigor@sysoev.ru 
2159148Sigor@sysoev.ru     nxt_socket_close(task, s);
2160148Sigor@sysoev.ru 
2161198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2162198Sigor@sysoev.ru }
2163198Sigor@sysoev.ru 
2164198Sigor@sysoev.ru 
2165198Sigor@sysoev.ru static void
2166198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2167198Sigor@sysoev.ru     void *data)
2168198Sigor@sysoev.ru {
2169955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2170955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2171955Svbart@nginx.com 
2172955Svbart@nginx.com     rpc = data;
2173955Svbart@nginx.com     tmcf = rpc->temp_conf;
2174955Svbart@nginx.com 
2175955Svbart@nginx.com #if 0
2176198Sigor@sysoev.ru     u_char                  *p;
2177198Sigor@sysoev.ru     size_t                  size;
2178198Sigor@sysoev.ru     uint8_t                 error;
2179198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2180198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2181198Sigor@sysoev.ru 
2182198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2183198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2184198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2185198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2186198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2187198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2188198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2189198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2190198Sigor@sysoev.ru     };
2191198Sigor@sysoev.ru 
2192359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2193352Smax.romanov@nginx.com 
2194352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2195352Smax.romanov@nginx.com 
2196551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2197551Smax.romanov@nginx.com         return;
2198551Smax.romanov@nginx.com     }
2199352Smax.romanov@nginx.com 
2200198Sigor@sysoev.ru     p = in->mem.pos;
2201198Sigor@sysoev.ru 
2202198Sigor@sysoev.ru     error = *p++;
2203198Sigor@sysoev.ru 
2204703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2205703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2206198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2207198Sigor@sysoev.ru 
2208198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2209198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2210198Sigor@sysoev.ru         return;
2211198Sigor@sysoev.ru     }
2212198Sigor@sysoev.ru 
2213198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2214198Sigor@sysoev.ru                         "listen socket error: "
2215198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2216493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2217198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2218198Sigor@sysoev.ru 
2219198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2220955Svbart@nginx.com #endif
2221198Sigor@sysoev.ru 
2222198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
222353Sigor@sysoev.ru }
222453Sigor@sysoev.ru 
222553Sigor@sysoev.ru 
2226774Svbart@nginx.com #if (NXT_TLS)
2227774Svbart@nginx.com 
2228774Svbart@nginx.com static void
2229774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2230774Svbart@nginx.com     nxt_router_tlssock_t *tls)
2231774Svbart@nginx.com {
2232774Svbart@nginx.com     nxt_socket_rpc_t  *rpc;
2233774Svbart@nginx.com 
2234774Svbart@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2235774Svbart@nginx.com     if (rpc == NULL) {
2236774Svbart@nginx.com         nxt_router_conf_error(task, tmcf);
2237774Svbart@nginx.com         return;
2238774Svbart@nginx.com     }
2239774Svbart@nginx.com 
2240774Svbart@nginx.com     rpc->socket_conf = tls->conf;
2241774Svbart@nginx.com     rpc->temp_conf = tmcf;
2242774Svbart@nginx.com 
2243774Svbart@nginx.com     nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
2244774Svbart@nginx.com                        nxt_router_tls_rpc_handler, rpc);
2245774Svbart@nginx.com }
2246774Svbart@nginx.com 
2247774Svbart@nginx.com 
2248774Svbart@nginx.com static void
2249774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2250774Svbart@nginx.com     void *data)
2251774Svbart@nginx.com {
2252774Svbart@nginx.com     nxt_mp_t               *mp;
2253774Svbart@nginx.com     nxt_int_t              ret;
2254774Svbart@nginx.com     nxt_tls_conf_t         *tlscf;
2255774Svbart@nginx.com     nxt_socket_rpc_t       *rpc;
2256774Svbart@nginx.com     nxt_router_temp_conf_t *tmcf;
2257774Svbart@nginx.com 
2258774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2259774Svbart@nginx.com 
2260774Svbart@nginx.com     rpc = data;
2261774Svbart@nginx.com     tmcf = rpc->temp_conf;
2262774Svbart@nginx.com 
2263774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2264774Svbart@nginx.com         goto fail;
2265774Svbart@nginx.com     }
2266774Svbart@nginx.com 
2267774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2268774Svbart@nginx.com 
2269774Svbart@nginx.com     tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2270774Svbart@nginx.com     if (nxt_slow_path(tlscf == NULL)) {
2271774Svbart@nginx.com         goto fail;
2272774Svbart@nginx.com     }
2273774Svbart@nginx.com 
2274*1558Smax.romanov@nginx.com     tlscf->chain_file = msg->fd[0];
2275774Svbart@nginx.com 
2276774Svbart@nginx.com     ret = task->thread->runtime->tls->server_init(task, tlscf);
2277774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2278774Svbart@nginx.com         goto fail;
2279774Svbart@nginx.com     }
2280774Svbart@nginx.com 
2281774Svbart@nginx.com     rpc->socket_conf->tls = tlscf;
2282774Svbart@nginx.com 
2283774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2284774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2285774Svbart@nginx.com     return;
2286774Svbart@nginx.com 
2287774Svbart@nginx.com fail:
2288774Svbart@nginx.com 
2289774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2290774Svbart@nginx.com }
2291774Svbart@nginx.com 
2292774Svbart@nginx.com #endif
2293774Svbart@nginx.com 
2294774Svbart@nginx.com 
2295507Smax.romanov@nginx.com static void
2296507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2297507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2298507Smax.romanov@nginx.com {
2299507Smax.romanov@nginx.com     size_t         size;
2300507Smax.romanov@nginx.com     uint32_t       stream;
2301648Svbart@nginx.com     nxt_int_t      ret;
2302507Smax.romanov@nginx.com     nxt_buf_t      *b;
2303507Smax.romanov@nginx.com     nxt_port_t     *main_port, *router_port;
2304507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2305507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2306507Smax.romanov@nginx.com 
2307507Smax.romanov@nginx.com     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2308507Smax.romanov@nginx.com     if (rpc == NULL) {
2309507Smax.romanov@nginx.com         goto fail;
2310507Smax.romanov@nginx.com     }
2311507Smax.romanov@nginx.com 
2312507Smax.romanov@nginx.com     rpc->app = app;
2313507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2314507Smax.romanov@nginx.com 
2315507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' prefork", &app->name);
2316507Smax.romanov@nginx.com 
2317507Smax.romanov@nginx.com     size = app->name.length + 1 + app->conf.length;
2318507Smax.romanov@nginx.com 
2319507Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2320507Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
2321507Smax.romanov@nginx.com         goto fail;
2322507Smax.romanov@nginx.com     }
2323507Smax.romanov@nginx.com 
2324507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->name);
2325507Smax.romanov@nginx.com     *b->mem.free++ = '\0';
2326507Smax.romanov@nginx.com     nxt_buf_cpystr(b, &app->conf);
2327507Smax.romanov@nginx.com 
2328507Smax.romanov@nginx.com     rt = task->thread->runtime;
2329507Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2330507Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2331507Smax.romanov@nginx.com 
2332507Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
2333507Smax.romanov@nginx.com                                            nxt_router_app_prefork_ready,
2334507Smax.romanov@nginx.com                                            nxt_router_app_prefork_error,
2335507Smax.romanov@nginx.com                                            -1, rpc);
2336507Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
2337507Smax.romanov@nginx.com         goto fail;
2338507Smax.romanov@nginx.com     }
2339507Smax.romanov@nginx.com 
23401488St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
23411488St.nateldemoura@f5.com                                 -1, stream, router_port->id, b);
2342648Svbart@nginx.com 
2343648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2344648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2345648Svbart@nginx.com         goto fail;
2346648Svbart@nginx.com     }
2347648Svbart@nginx.com 
2348507Smax.romanov@nginx.com     app->pending_processes++;
2349507Smax.romanov@nginx.com 
2350507Smax.romanov@nginx.com     return;
2351507Smax.romanov@nginx.com 
2352507Smax.romanov@nginx.com fail:
2353507Smax.romanov@nginx.com 
2354507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2355507Smax.romanov@nginx.com }
2356507Smax.romanov@nginx.com 
2357507Smax.romanov@nginx.com 
2358507Smax.romanov@nginx.com static void
2359507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2360507Smax.romanov@nginx.com     void *data)
2361507Smax.romanov@nginx.com {
2362507Smax.romanov@nginx.com     nxt_app_t           *app;
2363507Smax.romanov@nginx.com     nxt_port_t          *port;
2364507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2365507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2366507Smax.romanov@nginx.com 
2367507Smax.romanov@nginx.com     rpc = data;
2368507Smax.romanov@nginx.com     app = rpc->app;
2369507Smax.romanov@nginx.com 
2370507Smax.romanov@nginx.com     port = msg->u.new_port;
23711547Smax.romanov@nginx.com 
23721547Smax.romanov@nginx.com     nxt_assert(port != NULL);
23731547Smax.romanov@nginx.com     nxt_assert(port->type == NXT_PROCESS_APP);
23741547Smax.romanov@nginx.com     nxt_assert(port->id == 0);
23751547Smax.romanov@nginx.com 
2376507Smax.romanov@nginx.com     port->app = app;
23771547Smax.romanov@nginx.com     port->main_app_port = port;
2378507Smax.romanov@nginx.com 
2379507Smax.romanov@nginx.com     app->pending_processes--;
2380507Smax.romanov@nginx.com     app->processes++;
2381507Smax.romanov@nginx.com     app->idle_processes++;
2382507Smax.romanov@nginx.com 
2383507Smax.romanov@nginx.com     engine = task->thread->engine;
2384507Smax.romanov@nginx.com 
2385507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2386507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
23871549Smax.romanov@nginx.com 
23881549Smax.romanov@nginx.com     nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports",
23891549Smax.romanov@nginx.com               &app->name, port->pid, port->id);
23901549Smax.romanov@nginx.com 
23911547Smax.romanov@nginx.com     nxt_port_hash_add(&app->port_hash, port);
23921547Smax.romanov@nginx.com     app->port_hash_count++;
2393507Smax.romanov@nginx.com 
2394507Smax.romanov@nginx.com     port->idle_start = 0;
2395507Smax.romanov@nginx.com 
2396507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2397507Smax.romanov@nginx.com 
23981547Smax.romanov@nginx.com     nxt_router_app_shared_port_send(task, port);
23991547Smax.romanov@nginx.com 
2400507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2401507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2402507Smax.romanov@nginx.com }
2403507Smax.romanov@nginx.com 
2404507Smax.romanov@nginx.com 
2405507Smax.romanov@nginx.com static void
2406507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2407507Smax.romanov@nginx.com     void *data)
2408507Smax.romanov@nginx.com {
2409507Smax.romanov@nginx.com     nxt_app_t               *app;
2410507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2411507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2412507Smax.romanov@nginx.com 
2413507Smax.romanov@nginx.com     rpc = data;
2414507Smax.romanov@nginx.com     app = rpc->app;
2415507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2416507Smax.romanov@nginx.com 
2417507Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2418507Smax.romanov@nginx.com             &app->name);
2419507Smax.romanov@nginx.com 
2420507Smax.romanov@nginx.com     app->pending_processes--;
2421507Smax.romanov@nginx.com 
2422507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2423507Smax.romanov@nginx.com }
2424507Smax.romanov@nginx.com 
2425507Smax.romanov@nginx.com 
242653Sigor@sysoev.ru static nxt_int_t
242753Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
242853Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
242953Sigor@sysoev.ru {
243053Sigor@sysoev.ru     nxt_int_t                 ret;
243153Sigor@sysoev.ru     nxt_uint_t                n, threads;
243253Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
243353Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
243453Sigor@sysoev.ru 
2435591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
243653Sigor@sysoev.ru 
243753Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
243853Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
243953Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
244053Sigor@sysoev.ru         return NXT_ERROR;
244153Sigor@sysoev.ru     }
244253Sigor@sysoev.ru 
244353Sigor@sysoev.ru     n = 0;
244453Sigor@sysoev.ru 
244553Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
244653Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
244753Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
244853Sigor@sysoev.ru     {
244953Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
245053Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
245153Sigor@sysoev.ru             return NXT_ERROR;
245253Sigor@sysoev.ru         }
245353Sigor@sysoev.ru 
2454115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
245553Sigor@sysoev.ru 
245653Sigor@sysoev.ru         if (n < threads) {
2457315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2458115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
245953Sigor@sysoev.ru 
246053Sigor@sysoev.ru         } else {
2461315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2462115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
246353Sigor@sysoev.ru         }
246453Sigor@sysoev.ru 
246553Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
246653Sigor@sysoev.ru             return ret;
246753Sigor@sysoev.ru         }
246853Sigor@sysoev.ru 
246953Sigor@sysoev.ru         n++;
247053Sigor@sysoev.ru     }
247153Sigor@sysoev.ru 
247253Sigor@sysoev.ru     tmcf->new_threads = n;
247353Sigor@sysoev.ru 
247453Sigor@sysoev.ru     while (n < threads) {
247553Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
247653Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
247753Sigor@sysoev.ru             return NXT_ERROR;
247853Sigor@sysoev.ru         }
247953Sigor@sysoev.ru 
2480315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2481315Sigor@sysoev.ru 
248253Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
248353Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
248453Sigor@sysoev.ru             return NXT_ERROR;
248553Sigor@sysoev.ru         }
248653Sigor@sysoev.ru 
2487115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
248853Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
248953Sigor@sysoev.ru             return ret;
249053Sigor@sysoev.ru         }
249153Sigor@sysoev.ru 
249253Sigor@sysoev.ru         n++;
249353Sigor@sysoev.ru     }
249453Sigor@sysoev.ru 
249553Sigor@sysoev.ru     return NXT_OK;
249653Sigor@sysoev.ru }
249753Sigor@sysoev.ru 
249853Sigor@sysoev.ru 
249953Sigor@sysoev.ru static nxt_int_t
2500115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2501115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
250253Sigor@sysoev.ru {
2503359Sigor@sysoev.ru     nxt_int_t  ret;
250453Sigor@sysoev.ru 
25051509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2506154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
2507115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2508115Sigor@sysoev.ru         return ret;
2509115Sigor@sysoev.ru     }
2510115Sigor@sysoev.ru 
25111509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2512154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
251353Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
251453Sigor@sysoev.ru         return ret;
251553Sigor@sysoev.ru     }
251653Sigor@sysoev.ru 
2517115Sigor@sysoev.ru     return ret;
251853Sigor@sysoev.ru }
251953Sigor@sysoev.ru 
252053Sigor@sysoev.ru 
252153Sigor@sysoev.ru static nxt_int_t
2522115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2523115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
252453Sigor@sysoev.ru {
2525359Sigor@sysoev.ru     nxt_int_t  ret;
252653Sigor@sysoev.ru 
25271509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2528154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
252953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
253053Sigor@sysoev.ru         return ret;
253153Sigor@sysoev.ru     }
253253Sigor@sysoev.ru 
25331509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2534154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
253553Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
253653Sigor@sysoev.ru         return ret;
253753Sigor@sysoev.ru     }
253853Sigor@sysoev.ru 
25391509Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
2540115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2541115Sigor@sysoev.ru         return ret;
2542115Sigor@sysoev.ru     }
2543115Sigor@sysoev.ru 
2544115Sigor@sysoev.ru     return ret;
254553Sigor@sysoev.ru }
254653Sigor@sysoev.ru 
254753Sigor@sysoev.ru 
254853Sigor@sysoev.ru static nxt_int_t
2549115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2550115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
255153Sigor@sysoev.ru {
255253Sigor@sysoev.ru     nxt_int_t  ret;
255353Sigor@sysoev.ru 
2554313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
2555313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2556313Sigor@sysoev.ru         return ret;
2557313Sigor@sysoev.ru     }
2558313Sigor@sysoev.ru 
25591509Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets);
256053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
256153Sigor@sysoev.ru         return ret;
256253Sigor@sysoev.ru     }
256353Sigor@sysoev.ru 
25641509Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
256553Sigor@sysoev.ru }
256653Sigor@sysoev.ru 
256753Sigor@sysoev.ru 
256853Sigor@sysoev.ru static nxt_int_t
2569154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2570154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
257153Sigor@sysoev.ru     nxt_work_handler_t handler)
257253Sigor@sysoev.ru {
25731394Sigor@sysoev.ru     nxt_int_t                ret;
2574153Sigor@sysoev.ru     nxt_joint_job_t          *job;
257553Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
2576155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
257753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
257853Sigor@sysoev.ru 
257953Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
258053Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
258153Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
258253Sigor@sysoev.ru     {
2583154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2584153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2585139Sigor@sysoev.ru             return NXT_ERROR;
2586139Sigor@sysoev.ru         }
2587139Sigor@sysoev.ru 
2588154Sigor@sysoev.ru         job->work.next = recf->jobs;
2589154Sigor@sysoev.ru         recf->jobs = &job->work;
2590154Sigor@sysoev.ru 
2591153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2592153Sigor@sysoev.ru         job->work.handler = handler;
2593153Sigor@sysoev.ru         job->work.task = &job->task;
2594153Sigor@sysoev.ru         job->work.obj = job;
2595153Sigor@sysoev.ru         job->tmcf = tmcf;
259653Sigor@sysoev.ru 
2597154Sigor@sysoev.ru         tmcf->count++;
2598154Sigor@sysoev.ru 
2599591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2600154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
260153Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
260253Sigor@sysoev.ru             return NXT_ERROR;
260353Sigor@sysoev.ru         }
260453Sigor@sysoev.ru 
2605153Sigor@sysoev.ru         job->work.data = joint;
260653Sigor@sysoev.ru 
26071394Sigor@sysoev.ru         ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams);
26081394Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
26091394Sigor@sysoev.ru             return ret;
26101394Sigor@sysoev.ru         }
26111394Sigor@sysoev.ru 
261253Sigor@sysoev.ru         joint->count = 1;
2613155Sigor@sysoev.ru 
2614155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2615155Sigor@sysoev.ru         skcf->count++;
2616155Sigor@sysoev.ru         joint->socket_conf = skcf;
2617155Sigor@sysoev.ru 
261888Smax.romanov@nginx.com         joint->engine = recf->engine;
261953Sigor@sysoev.ru     }
262053Sigor@sysoev.ru 
262120Sigor@sysoev.ru     return NXT_OK;
262220Sigor@sysoev.ru }
262320Sigor@sysoev.ru 
262420Sigor@sysoev.ru 
262520Sigor@sysoev.ru static nxt_int_t
2626313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2627313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
2628313Sigor@sysoev.ru {
2629313Sigor@sysoev.ru     nxt_joint_job_t  *job;
2630313Sigor@sysoev.ru 
2631313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2632313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
2633313Sigor@sysoev.ru         return NXT_ERROR;
2634313Sigor@sysoev.ru     }
2635313Sigor@sysoev.ru 
2636313Sigor@sysoev.ru     job->work.next = recf->jobs;
2637313Sigor@sysoev.ru     recf->jobs = &job->work;
2638313Sigor@sysoev.ru 
2639313Sigor@sysoev.ru     job->task = tmcf->engine->task;
2640313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
2641313Sigor@sysoev.ru     job->work.task = &job->task;
2642313Sigor@sysoev.ru     job->work.obj = NULL;
2643313Sigor@sysoev.ru     job->work.data = NULL;
2644313Sigor@sysoev.ru     job->tmcf = NULL;
2645313Sigor@sysoev.ru 
2646313Sigor@sysoev.ru     return NXT_OK;
2647313Sigor@sysoev.ru }
2648313Sigor@sysoev.ru 
2649313Sigor@sysoev.ru 
2650313Sigor@sysoev.ru static nxt_int_t
2651139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2652139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
265320Sigor@sysoev.ru {
2654153Sigor@sysoev.ru     nxt_joint_job_t   *job;
265553Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
265620Sigor@sysoev.ru 
265753Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
265853Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
265953Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
266053Sigor@sysoev.ru     {
2661154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2662153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
2663139Sigor@sysoev.ru             return NXT_ERROR;
2664139Sigor@sysoev.ru         }
2665139Sigor@sysoev.ru 
2666154Sigor@sysoev.ru         job->work.next = recf->jobs;
2667154Sigor@sysoev.ru         recf->jobs = &job->work;
2668154Sigor@sysoev.ru 
2669153Sigor@sysoev.ru         job->task = tmcf->engine->task;
2670153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
2671153Sigor@sysoev.ru         job->work.task = &job->task;
2672153Sigor@sysoev.ru         job->work.obj = job;
2673153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2674153Sigor@sysoev.ru         job->tmcf = tmcf;
2675154Sigor@sysoev.ru 
2676154Sigor@sysoev.ru         tmcf->count++;
267720Sigor@sysoev.ru     }
267820Sigor@sysoev.ru 
267953Sigor@sysoev.ru     return NXT_OK;
268053Sigor@sysoev.ru }
268120Sigor@sysoev.ru 
268220Sigor@sysoev.ru 
268353Sigor@sysoev.ru static nxt_int_t
268453Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
268553Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
268653Sigor@sysoev.ru {
268753Sigor@sysoev.ru     nxt_int_t                 ret;
268853Sigor@sysoev.ru     nxt_uint_t                i, threads;
268953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
269020Sigor@sysoev.ru 
269153Sigor@sysoev.ru     recf = tmcf->engines->elts;
2692591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
269320Sigor@sysoev.ru 
269453Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
269553Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
269653Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
269753Sigor@sysoev.ru             return ret;
269853Sigor@sysoev.ru         }
269920Sigor@sysoev.ru     }
270020Sigor@sysoev.ru 
270120Sigor@sysoev.ru     return NXT_OK;
270220Sigor@sysoev.ru }
270353Sigor@sysoev.ru 
270453Sigor@sysoev.ru 
270553Sigor@sysoev.ru static nxt_int_t
270653Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
270753Sigor@sysoev.ru     nxt_event_engine_t *engine)
270853Sigor@sysoev.ru {
270953Sigor@sysoev.ru     nxt_int_t            ret;
271053Sigor@sysoev.ru     nxt_thread_link_t    *link;
271153Sigor@sysoev.ru     nxt_thread_handle_t  handle;
271253Sigor@sysoev.ru 
271353Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
271453Sigor@sysoev.ru 
271553Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
271653Sigor@sysoev.ru         return NXT_ERROR;
271753Sigor@sysoev.ru     }
271853Sigor@sysoev.ru 
271953Sigor@sysoev.ru     link->start = nxt_router_thread_start;
272053Sigor@sysoev.ru     link->engine = engine;
272153Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
272253Sigor@sysoev.ru     link->work.task = task;
272353Sigor@sysoev.ru     link->work.data = link;
272453Sigor@sysoev.ru 
272553Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
272653Sigor@sysoev.ru 
272753Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
272853Sigor@sysoev.ru 
272953Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
273053Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
273153Sigor@sysoev.ru     }
273253Sigor@sysoev.ru 
273353Sigor@sysoev.ru     return ret;
273453Sigor@sysoev.ru }
273553Sigor@sysoev.ru 
273653Sigor@sysoev.ru 
273753Sigor@sysoev.ru static void
2738343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2739343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
2740133Sigor@sysoev.ru {
2741507Smax.romanov@nginx.com     nxt_app_t  *app;
2742141Smax.romanov@nginx.com 
2743141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
2744133Sigor@sysoev.ru 
2745753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
2746343Smax.romanov@nginx.com 
2747141Smax.romanov@nginx.com     } nxt_queue_loop;
2748133Sigor@sysoev.ru 
2749133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
2750133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
2751133Sigor@sysoev.ru }
2752133Sigor@sysoev.ru 
2753133Sigor@sysoev.ru 
2754133Sigor@sysoev.ru static void
2755315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
275653Sigor@sysoev.ru {
275753Sigor@sysoev.ru     nxt_uint_t                n;
2758315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
275953Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
276053Sigor@sysoev.ru 
276153Sigor@sysoev.ru     recf = tmcf->engines->elts;
276253Sigor@sysoev.ru 
276353Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
2764315Sigor@sysoev.ru         engine = recf->engine;
2765315Sigor@sysoev.ru 
2766315Sigor@sysoev.ru         switch (recf->action) {
2767315Sigor@sysoev.ru 
2768315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
2769315Sigor@sysoev.ru             break;
2770315Sigor@sysoev.ru 
2771315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
2772315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
2773315Sigor@sysoev.ru             break;
2774315Sigor@sysoev.ru 
2775315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
2776315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
2777315Sigor@sysoev.ru             break;
2778315Sigor@sysoev.ru         }
2779315Sigor@sysoev.ru 
2780316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
2781316Sigor@sysoev.ru 
278253Sigor@sysoev.ru         recf++;
278353Sigor@sysoev.ru     }
278453Sigor@sysoev.ru }
278553Sigor@sysoev.ru 
278653Sigor@sysoev.ru 
278753Sigor@sysoev.ru static void
2788315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
278953Sigor@sysoev.ru {
2790154Sigor@sysoev.ru     nxt_work_t  *work, *next;
2791154Sigor@sysoev.ru 
2792315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
2793154Sigor@sysoev.ru         next = work->next;
2794154Sigor@sysoev.ru         work->next = NULL;
2795154Sigor@sysoev.ru 
2796315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
279753Sigor@sysoev.ru     }
279853Sigor@sysoev.ru }
279953Sigor@sysoev.ru 
280053Sigor@sysoev.ru 
2801320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
28021547Smax.romanov@nginx.com     .rpc_error       = nxt_port_rpc_handler,
28031547Smax.romanov@nginx.com     .mmap            = nxt_port_mmap_handler,
28041547Smax.romanov@nginx.com     .data            = nxt_port_rpc_handler,
28051547Smax.romanov@nginx.com     .oosm            = nxt_router_oosm_handler,
28061547Smax.romanov@nginx.com     .req_headers_ack = nxt_port_rpc_handler,
280788Smax.romanov@nginx.com };
280888Smax.romanov@nginx.com 
280988Smax.romanov@nginx.com 
281088Smax.romanov@nginx.com static void
281153Sigor@sysoev.ru nxt_router_thread_start(void *data)
281253Sigor@sysoev.ru {
2813141Smax.romanov@nginx.com     nxt_int_t           ret;
2814141Smax.romanov@nginx.com     nxt_port_t          *port;
281588Smax.romanov@nginx.com     nxt_task_t          *task;
28161545Smax.romanov@nginx.com     nxt_work_t          *work;
281753Sigor@sysoev.ru     nxt_thread_t        *thread;
281853Sigor@sysoev.ru     nxt_thread_link_t   *link;
281953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
282053Sigor@sysoev.ru 
282153Sigor@sysoev.ru     link = data;
282253Sigor@sysoev.ru     engine = link->engine;
282388Smax.romanov@nginx.com     task = &engine->task;
282453Sigor@sysoev.ru 
282553Sigor@sysoev.ru     thread = nxt_thread();
282653Sigor@sysoev.ru 
2827165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
2828165Smax.romanov@nginx.com 
282953Sigor@sysoev.ru     /* STUB */
283053Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
283153Sigor@sysoev.ru 
283253Sigor@sysoev.ru     engine->task.thread = thread;
283353Sigor@sysoev.ru     engine->task.log = thread->log;
283453Sigor@sysoev.ru     thread->engine = engine;
283563Sigor@sysoev.ru     thread->task = &engine->task;
2836326Svbart@nginx.com #if 0
283753Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
2838326Svbart@nginx.com #endif
283953Sigor@sysoev.ru 
284063Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
2841337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
2842337Sigor@sysoev.ru         return;
2843337Sigor@sysoev.ru     }
284453Sigor@sysoev.ru 
2845197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
2846197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
2847141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
2848141Smax.romanov@nginx.com         return;
2849141Smax.romanov@nginx.com     }
2850141Smax.romanov@nginx.com 
2851141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
2852141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2853343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
2854141Smax.romanov@nginx.com         return;
2855141Smax.romanov@nginx.com     }
2856141Smax.romanov@nginx.com 
28571555Smax.romanov@nginx.com     ret = nxt_router_port_queue_init(task, port);
28581555Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
28591555Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
28601555Smax.romanov@nginx.com         return;
28611555Smax.romanov@nginx.com     }
28621555Smax.romanov@nginx.com 
2863141Smax.romanov@nginx.com     engine->port = port;
2864141Smax.romanov@nginx.com 
2865320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
2866141Smax.romanov@nginx.com 
28671545Smax.romanov@nginx.com     work = nxt_zalloc(sizeof(nxt_work_t));
28681545Smax.romanov@nginx.com     if (nxt_slow_path(work == NULL)) {
28691545Smax.romanov@nginx.com         return;
28701545Smax.romanov@nginx.com     }
28711545Smax.romanov@nginx.com 
28721545Smax.romanov@nginx.com     work->handler = nxt_router_rt_add_port;
28731545Smax.romanov@nginx.com     work->task = link->work.task;
28741545Smax.romanov@nginx.com     work->obj = work;
28751545Smax.romanov@nginx.com     work->data = port;
28761545Smax.romanov@nginx.com 
28771545Smax.romanov@nginx.com     nxt_event_engine_post(link->work.task->thread->engine, work);
28781545Smax.romanov@nginx.com 
287953Sigor@sysoev.ru     nxt_event_engine_start(engine);
288053Sigor@sysoev.ru }
288153Sigor@sysoev.ru 
288253Sigor@sysoev.ru 
288353Sigor@sysoev.ru static void
28841545Smax.romanov@nginx.com nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data)
28851545Smax.romanov@nginx.com {
28861545Smax.romanov@nginx.com     nxt_int_t      res;
28871545Smax.romanov@nginx.com     nxt_port_t     *port;
28881545Smax.romanov@nginx.com     nxt_runtime_t  *rt;
28891545Smax.romanov@nginx.com 
28901545Smax.romanov@nginx.com     rt = task->thread->runtime;
28911545Smax.romanov@nginx.com     port = data;
28921545Smax.romanov@nginx.com 
28931545Smax.romanov@nginx.com     nxt_free(obj);
28941545Smax.romanov@nginx.com 
28951545Smax.romanov@nginx.com     res = nxt_port_hash_add(&rt->ports, port);
28961545Smax.romanov@nginx.com 
28971545Smax.romanov@nginx.com     if (nxt_fast_path(res == NXT_OK)) {
28981545Smax.romanov@nginx.com         nxt_port_use(task, port, 1);
28991545Smax.romanov@nginx.com     }
29001545Smax.romanov@nginx.com }
29011545Smax.romanov@nginx.com 
29021545Smax.romanov@nginx.com 
29031545Smax.romanov@nginx.com static void
290453Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
290553Sigor@sysoev.ru {
2906153Sigor@sysoev.ru     nxt_joint_job_t          *job;
2907359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
2908359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
290953Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
2910359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
291153Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
291253Sigor@sysoev.ru 
2913153Sigor@sysoev.ru     job = obj;
291453Sigor@sysoev.ru     joint = data;
291553Sigor@sysoev.ru 
2916159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
2917159Sigor@sysoev.ru 
2918359Sigor@sysoev.ru     skcf = joint->socket_conf;
2919359Sigor@sysoev.ru     ls = skcf->listen;
2920359Sigor@sysoev.ru 
2921359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
2922359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
2923359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
292453Sigor@sysoev.ru         return;
292553Sigor@sysoev.ru     }
292653Sigor@sysoev.ru 
2927359Sigor@sysoev.ru     lev->socket.data = joint;
2928359Sigor@sysoev.ru 
2929359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
2930359Sigor@sysoev.ru 
2931359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
2932359Sigor@sysoev.ru     ls->count++;
2933359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
2934139Sigor@sysoev.ru 
2935153Sigor@sysoev.ru     job->work.next = NULL;
2936153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2937153Sigor@sysoev.ru 
2938153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
293953Sigor@sysoev.ru }
294053Sigor@sysoev.ru 
294153Sigor@sysoev.ru 
294253Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
294353Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
294453Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
294553Sigor@sysoev.ru {
2946115Sigor@sysoev.ru     nxt_socket_t        fd;
2947115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
2948359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
2949359Sigor@sysoev.ru 
2950359Sigor@sysoev.ru     fd = skcf->listen->socket;
295153Sigor@sysoev.ru 
2952115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
2953115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
2954115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
295553Sigor@sysoev.ru     {
2956359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
2957359Sigor@sysoev.ru 
2958359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
2959359Sigor@sysoev.ru             return lev;
296053Sigor@sysoev.ru         }
296153Sigor@sysoev.ru     }
296253Sigor@sysoev.ru 
296353Sigor@sysoev.ru     return NULL;
296453Sigor@sysoev.ru }
296553Sigor@sysoev.ru 
296653Sigor@sysoev.ru 
296753Sigor@sysoev.ru static void
296853Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
296953Sigor@sysoev.ru {
2970153Sigor@sysoev.ru     nxt_joint_job_t          *job;
297153Sigor@sysoev.ru     nxt_event_engine_t       *engine;
2972359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
297353Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
297453Sigor@sysoev.ru 
2975153Sigor@sysoev.ru     job = obj;
297653Sigor@sysoev.ru     joint = data;
297753Sigor@sysoev.ru 
2978139Sigor@sysoev.ru     engine = task->thread->engine;
2979139Sigor@sysoev.ru 
2980159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
2981159Sigor@sysoev.ru 
2982359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
2983359Sigor@sysoev.ru                                   joint->socket_conf);
2984359Sigor@sysoev.ru 
2985359Sigor@sysoev.ru     old = lev->socket.data;
2986359Sigor@sysoev.ru     lev->socket.data = joint;
2987359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
298853Sigor@sysoev.ru 
2989153Sigor@sysoev.ru     job->work.next = NULL;
2990153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
2991153Sigor@sysoev.ru 
2992153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
2993139Sigor@sysoev.ru 
2994181Smax.romanov@nginx.com     /*
2995181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
2996181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
2997181Smax.romanov@nginx.com      */
2998181Smax.romanov@nginx.com 
2999181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
300053Sigor@sysoev.ru }
300153Sigor@sysoev.ru 
300253Sigor@sysoev.ru 
300353Sigor@sysoev.ru static void
300453Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
300553Sigor@sysoev.ru {
3006153Sigor@sysoev.ru     nxt_joint_job_t     *job;
3007153Sigor@sysoev.ru     nxt_socket_conf_t   *skcf;
3008359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
3009153Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3010153Sigor@sysoev.ru 
3011153Sigor@sysoev.ru     job = obj;
301253Sigor@sysoev.ru     skcf = data;
301353Sigor@sysoev.ru 
3014139Sigor@sysoev.ru     engine = task->thread->engine;
3015139Sigor@sysoev.ru 
3016359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
3017359Sigor@sysoev.ru 
3018359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
301953Sigor@sysoev.ru 
3020163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
3021359Sigor@sysoev.ru               lev->socket.fd);
3022359Sigor@sysoev.ru 
3023359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
3024359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
3025359Sigor@sysoev.ru 
3026359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
3027139Sigor@sysoev.ru 
3028153Sigor@sysoev.ru     job->work.next = NULL;
3029153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
3030153Sigor@sysoev.ru 
3031153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
303253Sigor@sysoev.ru }
303353Sigor@sysoev.ru 
303453Sigor@sysoev.ru 
303553Sigor@sysoev.ru static void
3036313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
3037313Sigor@sysoev.ru {
3038313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3039313Sigor@sysoev.ru 
3040313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
3041313Sigor@sysoev.ru 
3042313Sigor@sysoev.ru     engine = task->thread->engine;
3043313Sigor@sysoev.ru 
3044313Sigor@sysoev.ru     engine->shutdown = 1;
3045313Sigor@sysoev.ru 
3046313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
3047313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3048313Sigor@sysoev.ru     }
3049313Sigor@sysoev.ru }
3050313Sigor@sysoev.ru 
3051313Sigor@sysoev.ru 
3052313Sigor@sysoev.ru static void
305353Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
305453Sigor@sysoev.ru {
305553Sigor@sysoev.ru     nxt_timer_t              *timer;
3056359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
305753Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
305853Sigor@sysoev.ru 
305953Sigor@sysoev.ru     timer = obj;
3060359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
306153Sigor@sysoev.ru 
3062163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
3063359Sigor@sysoev.ru               lev->socket.fd);
3064359Sigor@sysoev.ru 
3065359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
3066359Sigor@sysoev.ru 
3067683Sigor@sysoev.ru     joint = lev->socket.data;
3068683Sigor@sysoev.ru     lev->socket.data = NULL;
3069683Sigor@sysoev.ru 
3070359Sigor@sysoev.ru     /* 'task' refers to lev->task and we cannot use after nxt_free() */
3071123Smax.romanov@nginx.com     task = &task->thread->engine->task;
3072123Smax.romanov@nginx.com 
3073359Sigor@sysoev.ru     nxt_router_listen_socket_release(task, joint->socket_conf);
3074359Sigor@sysoev.ru 
3075683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
307653Sigor@sysoev.ru }
307753Sigor@sysoev.ru 
307853Sigor@sysoev.ru 
307953Sigor@sysoev.ru static void
3080359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
308153Sigor@sysoev.ru {
3082359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
308353Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
308453Sigor@sysoev.ru 
3085359Sigor@sysoev.ru     ls = skcf->listen;
3086118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
308753Sigor@sysoev.ru 
308853Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
308953Sigor@sysoev.ru 
3090359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
3091359Sigor@sysoev.ru               task->thread->engine, ls->count);
3092359Sigor@sysoev.ru 
3093359Sigor@sysoev.ru     if (--ls->count != 0) {
3094359Sigor@sysoev.ru         ls = NULL;
309553Sigor@sysoev.ru     }
309653Sigor@sysoev.ru 
309753Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
309853Sigor@sysoev.ru 
3099359Sigor@sysoev.ru     if (ls != NULL) {
3100359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
3101359Sigor@sysoev.ru         nxt_free(ls);
310253Sigor@sysoev.ru     }
310353Sigor@sysoev.ru }
310453Sigor@sysoev.ru 
310553Sigor@sysoev.ru 
3106683Sigor@sysoev.ru void
3107683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3108683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
3109683Sigor@sysoev.ru {
3110683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3111683Sigor@sysoev.ru 
3112683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
3113683Sigor@sysoev.ru 
31141541Smax.romanov@nginx.com     engine = task->thread->engine;
31151541Smax.romanov@nginx.com 
3116683Sigor@sysoev.ru     if (--lev->count == 0) {
31171535Smax.romanov@nginx.com         if (lev->next != NULL) {
31181541Smax.romanov@nginx.com             nxt_sockaddr_cache_free(engine, lev->next);
31191541Smax.romanov@nginx.com 
31201535Smax.romanov@nginx.com             nxt_conn_free(task, lev->next);
31211535Smax.romanov@nginx.com         }
31221535Smax.romanov@nginx.com 
3123683Sigor@sysoev.ru         nxt_free(lev);
3124683Sigor@sysoev.ru     }
3125683Sigor@sysoev.ru 
3126683Sigor@sysoev.ru     if (joint != NULL) {
3127683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
3128683Sigor@sysoev.ru     }
3129683Sigor@sysoev.ru 
3130683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3131683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3132683Sigor@sysoev.ru     }
3133683Sigor@sysoev.ru }
3134683Sigor@sysoev.ru 
3135683Sigor@sysoev.ru 
3136683Sigor@sysoev.ru void
313753Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
313853Sigor@sysoev.ru {
313953Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
314053Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
314153Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
314253Sigor@sysoev.ru 
3143163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
314453Sigor@sysoev.ru 
314553Sigor@sysoev.ru     if (--joint->count != 0) {
314653Sigor@sysoev.ru         return;
314753Sigor@sysoev.ru     }
314853Sigor@sysoev.ru 
314953Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
315053Sigor@sysoev.ru 
3151530Sigor@sysoev.ru     /*
3152530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
3153530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
3154530Sigor@sysoev.ru      * be already destroyed by another thread.
3155530Sigor@sysoev.ru      */
315653Sigor@sysoev.ru     skcf = joint->socket_conf;
315753Sigor@sysoev.ru     rtcf = skcf->router_conf;
315853Sigor@sysoev.ru     lock = &rtcf->router->lock;
315953Sigor@sysoev.ru 
316053Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
316153Sigor@sysoev.ru 
3162163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3163163Smax.romanov@nginx.com               rtcf, rtcf->count);
3164163Smax.romanov@nginx.com 
316553Sigor@sysoev.ru     if (--skcf->count != 0) {
3166952Sigor@sysoev.ru         skcf = NULL;
316753Sigor@sysoev.ru         rtcf = NULL;
316853Sigor@sysoev.ru 
316953Sigor@sysoev.ru     } else {
317053Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
317153Sigor@sysoev.ru 
317253Sigor@sysoev.ru         if (--rtcf->count != 0) {
317353Sigor@sysoev.ru             rtcf = NULL;
317453Sigor@sysoev.ru         }
317553Sigor@sysoev.ru     }
317653Sigor@sysoev.ru 
317753Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
317853Sigor@sysoev.ru 
3179952Sigor@sysoev.ru     if (skcf != NULL) {
31801264Sigor@sysoev.ru         if (skcf->action != NULL) {
31811264Sigor@sysoev.ru             nxt_http_action_cleanup(task, skcf->action);
3182964Sigor@sysoev.ru         }
3183964Sigor@sysoev.ru 
3184952Sigor@sysoev.ru #if (NXT_TLS)
3185952Sigor@sysoev.ru         if (skcf->tls != NULL) {
3186952Sigor@sysoev.ru             task->thread->runtime->tls->server_free(task, skcf->tls);
3187952Sigor@sysoev.ru         }
3188952Sigor@sysoev.ru #endif
3189952Sigor@sysoev.ru     }
3190952Sigor@sysoev.ru 
3191141Smax.romanov@nginx.com     /* TODO remove engine->port */
3192141Smax.romanov@nginx.com 
319353Sigor@sysoev.ru     if (rtcf != NULL) {
3194115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
3195131Smax.romanov@nginx.com 
3196964Sigor@sysoev.ru         nxt_http_routes_cleanup(task, rtcf->routes);
3197964Sigor@sysoev.ru 
3198630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
3199630Svbart@nginx.com 
3200131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
3201131Smax.romanov@nginx.com 
320265Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
320353Sigor@sysoev.ru     }
320453Sigor@sysoev.ru }
320553Sigor@sysoev.ru 
320653Sigor@sysoev.ru 
320753Sigor@sysoev.ru static void
3208630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3209630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3210630Svbart@nginx.com {
3211630Svbart@nginx.com     size_t     size;
3212630Svbart@nginx.com     u_char     *buf, *p;
3213630Svbart@nginx.com     nxt_off_t  bytes;
3214630Svbart@nginx.com 
3215630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
3216630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
3217630Svbart@nginx.com         nxt_router_access_log_date,
3218630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3219703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
3220630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
3221630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
3222630Svbart@nginx.com     };
3223630Svbart@nginx.com 
3224630Svbart@nginx.com     size = r->remote->address_length
3225630Svbart@nginx.com            + 6                  /* ' - - [' */
3226630Svbart@nginx.com            + date_cache.size
3227630Svbart@nginx.com            + 3                  /* '] "' */
3228630Svbart@nginx.com            + r->method->length
3229630Svbart@nginx.com            + 1                  /* space */
3230630Svbart@nginx.com            + r->target.length
3231630Svbart@nginx.com            + 1                  /* space */
3232630Svbart@nginx.com            + r->version.length
3233630Svbart@nginx.com            + 2                  /* '" ' */
3234630Svbart@nginx.com            + 3                  /* status */
3235630Svbart@nginx.com            + 1                  /* space */
3236630Svbart@nginx.com            + NXT_OFF_T_LEN
3237630Svbart@nginx.com            + 2                  /* ' "' */
3238630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3239630Svbart@nginx.com            + 3                  /* '" "' */
3240630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3241630Svbart@nginx.com            + 2                  /* '"\n' */
3242630Svbart@nginx.com     ;
3243630Svbart@nginx.com 
3244630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3245630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3246630Svbart@nginx.com         return;
3247630Svbart@nginx.com     }
3248630Svbart@nginx.com 
3249630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3250630Svbart@nginx.com                    r->remote->address_length);
3251630Svbart@nginx.com 
3252630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3253630Svbart@nginx.com 
3254630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3255630Svbart@nginx.com 
3256630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3257630Svbart@nginx.com 
3258630Svbart@nginx.com     if (r->method->length != 0) {
3259630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3260630Svbart@nginx.com 
3261630Svbart@nginx.com         if (r->target.length != 0) {
3262630Svbart@nginx.com             *p++ = ' ';
3263630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3264630Svbart@nginx.com 
3265630Svbart@nginx.com             if (r->version.length != 0) {
3266630Svbart@nginx.com                 *p++ = ' ';
3267630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3268630Svbart@nginx.com             }
3269630Svbart@nginx.com         }
3270630Svbart@nginx.com 
3271630Svbart@nginx.com     } else {
3272630Svbart@nginx.com         *p++ = '-';
3273630Svbart@nginx.com     }
3274630Svbart@nginx.com 
3275630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3276630Svbart@nginx.com 
3277630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3278630Svbart@nginx.com 
3279630Svbart@nginx.com     *p++ = ' ';
3280630Svbart@nginx.com 
32811112Sigor@sysoev.ru     bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3282630Svbart@nginx.com 
3283630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3284630Svbart@nginx.com 
3285630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3286630Svbart@nginx.com 
3287630Svbart@nginx.com     if (r->referer != NULL) {
3288630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3289630Svbart@nginx.com 
3290630Svbart@nginx.com     } else {
3291630Svbart@nginx.com         *p++ = '-';
3292630Svbart@nginx.com     }
3293630Svbart@nginx.com 
3294630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3295630Svbart@nginx.com 
3296630Svbart@nginx.com     if (r->user_agent != NULL) {
3297630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3298630Svbart@nginx.com 
3299630Svbart@nginx.com     } else {
3300630Svbart@nginx.com         *p++ = '-';
3301630Svbart@nginx.com     }
3302630Svbart@nginx.com 
3303630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3304630Svbart@nginx.com 
3305630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3306630Svbart@nginx.com }
3307630Svbart@nginx.com 
3308630Svbart@nginx.com 
3309630Svbart@nginx.com static u_char *
3310630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3311630Svbart@nginx.com     size_t size, const char *format)
3312630Svbart@nginx.com {
3313630Svbart@nginx.com     u_char  sign;
3314630Svbart@nginx.com     time_t  gmtoff;
3315630Svbart@nginx.com 
3316630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3317630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3318630Svbart@nginx.com 
3319630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3320630Svbart@nginx.com 
3321630Svbart@nginx.com     if (gmtoff < 0) {
3322630Svbart@nginx.com         gmtoff = -gmtoff;
3323630Svbart@nginx.com         sign = '-';
3324630Svbart@nginx.com 
3325630Svbart@nginx.com     } else {
3326630Svbart@nginx.com         sign = '+';
3327630Svbart@nginx.com     }
3328630Svbart@nginx.com 
3329630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3330630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3331630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3332630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3333630Svbart@nginx.com }
3334630Svbart@nginx.com 
3335630Svbart@nginx.com 
3336630Svbart@nginx.com static void
3337630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3338630Svbart@nginx.com {
3339630Svbart@nginx.com     uint32_t                 stream;
3340648Svbart@nginx.com     nxt_int_t                ret;
3341630Svbart@nginx.com     nxt_buf_t                *b;
3342630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3343630Svbart@nginx.com     nxt_runtime_t            *rt;
3344630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3345630Svbart@nginx.com 
3346630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3347630Svbart@nginx.com 
3348630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3349630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3350630Svbart@nginx.com         goto fail;
3351630Svbart@nginx.com     }
3352630Svbart@nginx.com 
3353630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3354630Svbart@nginx.com     *b->mem.free++ = '\0';
3355630Svbart@nginx.com 
3356630Svbart@nginx.com     rt = task->thread->runtime;
3357630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3358630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3359630Svbart@nginx.com 
3360630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3361630Svbart@nginx.com                                            nxt_router_access_log_ready,
3362630Svbart@nginx.com                                            nxt_router_access_log_error,
3363630Svbart@nginx.com                                            -1, tmcf);
3364630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3365630Svbart@nginx.com         goto fail;
3366630Svbart@nginx.com     }
3367630Svbart@nginx.com 
3368648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3369648Svbart@nginx.com                                 stream, router_port->id, b);
3370648Svbart@nginx.com 
3371648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3372648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3373648Svbart@nginx.com         goto fail;
3374648Svbart@nginx.com     }
3375630Svbart@nginx.com 
3376630Svbart@nginx.com     return;
3377630Svbart@nginx.com 
3378630Svbart@nginx.com fail:
3379630Svbart@nginx.com 
3380630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3381630Svbart@nginx.com }
3382630Svbart@nginx.com 
3383630Svbart@nginx.com 
3384630Svbart@nginx.com static void
3385630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3386630Svbart@nginx.com     void *data)
3387630Svbart@nginx.com {
3388630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3389630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3390630Svbart@nginx.com 
3391630Svbart@nginx.com     tmcf = data;
3392630Svbart@nginx.com 
3393630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3394630Svbart@nginx.com 
3395*1558Smax.romanov@nginx.com     access_log->fd = msg->fd[0];
3396630Svbart@nginx.com 
3397630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3398630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3399630Svbart@nginx.com }
3400630Svbart@nginx.com 
3401630Svbart@nginx.com 
3402630Svbart@nginx.com static void
3403630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3404630Svbart@nginx.com     void *data)
3405630Svbart@nginx.com {
3406630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3407630Svbart@nginx.com 
3408630Svbart@nginx.com     tmcf = data;
3409630Svbart@nginx.com 
3410630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3411630Svbart@nginx.com }
3412630Svbart@nginx.com 
3413630Svbart@nginx.com 
3414630Svbart@nginx.com static void
3415630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3416630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3417630Svbart@nginx.com {
3418630Svbart@nginx.com     if (access_log == NULL) {
3419630Svbart@nginx.com         return;
3420630Svbart@nginx.com     }
3421630Svbart@nginx.com 
3422630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3423630Svbart@nginx.com 
3424630Svbart@nginx.com     if (--access_log->count != 0) {
3425630Svbart@nginx.com         access_log = NULL;
3426630Svbart@nginx.com     }
3427630Svbart@nginx.com 
3428630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3429630Svbart@nginx.com 
3430630Svbart@nginx.com     if (access_log != NULL) {
3431630Svbart@nginx.com 
3432630Svbart@nginx.com         if (access_log->fd != -1) {
3433630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3434630Svbart@nginx.com         }
3435630Svbart@nginx.com 
3436630Svbart@nginx.com         nxt_free(access_log);
3437630Svbart@nginx.com     }
3438630Svbart@nginx.com }
3439630Svbart@nginx.com 
3440630Svbart@nginx.com 
3441631Svbart@nginx.com typedef struct {
3442631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3443631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3444631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3445631Svbart@nginx.com 
3446631Svbart@nginx.com 
34471552Smax.romanov@nginx.com static void
3448631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3449631Svbart@nginx.com {
3450631Svbart@nginx.com     nxt_mp_t                        *mp;
3451631Svbart@nginx.com     uint32_t                        stream;
3452631Svbart@nginx.com     nxt_int_t                       ret;
3453631Svbart@nginx.com     nxt_buf_t                       *b;
3454631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3455631Svbart@nginx.com     nxt_runtime_t                   *rt;
3456631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3457631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3458631Svbart@nginx.com 
3459631Svbart@nginx.com     access_log = nxt_router->access_log;
3460631Svbart@nginx.com 
3461631Svbart@nginx.com     if (access_log == NULL) {
3462631Svbart@nginx.com         return;
3463631Svbart@nginx.com     }
3464631Svbart@nginx.com 
3465631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3466631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3467631Svbart@nginx.com         return;
3468631Svbart@nginx.com     }
3469631Svbart@nginx.com 
3470631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3471631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3472631Svbart@nginx.com         goto fail;
3473631Svbart@nginx.com     }
3474631Svbart@nginx.com 
3475631Svbart@nginx.com     reopen->mem_pool = mp;
3476631Svbart@nginx.com     reopen->access_log = access_log;
3477631Svbart@nginx.com 
3478631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3479631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3480631Svbart@nginx.com         goto fail;
3481631Svbart@nginx.com     }
3482631Svbart@nginx.com 
3483651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3484651Svbart@nginx.com 
3485631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3486631Svbart@nginx.com     *b->mem.free++ = '\0';
3487631Svbart@nginx.com 
3488631Svbart@nginx.com     rt = task->thread->runtime;
3489631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3490631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3491631Svbart@nginx.com 
3492631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3493631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
3494631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
3495631Svbart@nginx.com                                            -1, reopen);
3496631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3497631Svbart@nginx.com         goto fail;
3498631Svbart@nginx.com     }
3499631Svbart@nginx.com 
3500631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3501631Svbart@nginx.com                                 stream, router_port->id, b);
3502631Svbart@nginx.com 
3503631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3504631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3505631Svbart@nginx.com         goto fail;
3506631Svbart@nginx.com     }
3507631Svbart@nginx.com 
3508651Svbart@nginx.com     nxt_mp_retain(mp);
3509651Svbart@nginx.com 
3510631Svbart@nginx.com     return;
3511631Svbart@nginx.com 
3512631Svbart@nginx.com fail:
3513631Svbart@nginx.com 
3514631Svbart@nginx.com     nxt_mp_destroy(mp);
3515631Svbart@nginx.com }
3516631Svbart@nginx.com 
3517631Svbart@nginx.com 
3518631Svbart@nginx.com static void
3519651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3520651Svbart@nginx.com {
3521651Svbart@nginx.com     nxt_mp_t   *mp;
3522651Svbart@nginx.com     nxt_buf_t  *b;
3523651Svbart@nginx.com 
3524651Svbart@nginx.com     b = obj;
3525651Svbart@nginx.com     mp = b->data;
3526651Svbart@nginx.com 
3527651Svbart@nginx.com     nxt_mp_release(mp);
3528651Svbart@nginx.com }
3529651Svbart@nginx.com 
3530651Svbart@nginx.com 
3531651Svbart@nginx.com static void
3532631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3533631Svbart@nginx.com     void *data)
3534631Svbart@nginx.com {
3535631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3536631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3537631Svbart@nginx.com 
3538631Svbart@nginx.com     reopen = data;
3539631Svbart@nginx.com 
3540631Svbart@nginx.com     access_log = reopen->access_log;
3541631Svbart@nginx.com 
3542631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
3543631Svbart@nginx.com 
3544*1558Smax.romanov@nginx.com         if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
3545631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
3546*1558Smax.romanov@nginx.com                       msg->fd[0], access_log->fd, nxt_errno);
3547631Svbart@nginx.com         }
3548631Svbart@nginx.com     }
3549631Svbart@nginx.com 
3550*1558Smax.romanov@nginx.com     nxt_fd_close(msg->fd[0]);
3551651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3552631Svbart@nginx.com }
3553631Svbart@nginx.com 
3554631Svbart@nginx.com 
3555631Svbart@nginx.com static void
3556631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3557631Svbart@nginx.com     void *data)
3558631Svbart@nginx.com {
3559631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3560631Svbart@nginx.com 
3561631Svbart@nginx.com     reopen = data;
3562631Svbart@nginx.com 
3563651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
3564631Svbart@nginx.com }
3565631Svbart@nginx.com 
3566631Svbart@nginx.com 
3567630Svbart@nginx.com static void
356853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
356953Sigor@sysoev.ru {
3570141Smax.romanov@nginx.com     nxt_port_t           *port;
357153Sigor@sysoev.ru     nxt_thread_link_t    *link;
357253Sigor@sysoev.ru     nxt_event_engine_t   *engine;
357353Sigor@sysoev.ru     nxt_thread_handle_t  handle;
357453Sigor@sysoev.ru 
357558Svbart@nginx.com     handle = (nxt_thread_handle_t) obj;
357653Sigor@sysoev.ru     link = data;
357753Sigor@sysoev.ru 
357853Sigor@sysoev.ru     nxt_thread_wait(handle);
357953Sigor@sysoev.ru 
358053Sigor@sysoev.ru     engine = link->engine;
358153Sigor@sysoev.ru 
358253Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
358353Sigor@sysoev.ru 
3584141Smax.romanov@nginx.com     port = engine->port;
3585141Smax.romanov@nginx.com 
3586141Smax.romanov@nginx.com     // TODO notify all apps
3587141Smax.romanov@nginx.com 
3588343Smax.romanov@nginx.com     port->engine = task->thread->engine;
3589163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
3590343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
3591163Smax.romanov@nginx.com 
3592163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
359363Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
359453Sigor@sysoev.ru 
359553Sigor@sysoev.ru     nxt_event_engine_free(engine);
359653Sigor@sysoev.ru 
359753Sigor@sysoev.ru     nxt_free(link);
359853Sigor@sysoev.ru }
359953Sigor@sysoev.ru 
360053Sigor@sysoev.ru 
360153Sigor@sysoev.ru static void
3602318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3603318Smax.romanov@nginx.com     void *data)
360488Smax.romanov@nginx.com {
36051123Smax.romanov@nginx.com     nxt_int_t               ret;
36061547Smax.romanov@nginx.com     nxt_app_t               *app;
36071269Sigor@sysoev.ru     nxt_buf_t               *b, *next;
36081131Smax.romanov@nginx.com     nxt_port_t              *app_port;
36091123Smax.romanov@nginx.com     nxt_unit_field_t        *f;
36101123Smax.romanov@nginx.com     nxt_http_field_t        *field;
36111123Smax.romanov@nginx.com     nxt_http_request_t      *r;
36121123Smax.romanov@nginx.com     nxt_unit_response_t     *resp;
36131123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
361488Smax.romanov@nginx.com 
36151123Smax.romanov@nginx.com     req_rpc_data = data;
361688Smax.romanov@nginx.com 
36171123Smax.romanov@nginx.com     r = req_rpc_data->request;
36181007Salexander.borisov@nginx.com     if (nxt_slow_path(r == NULL)) {
3619570Smax.romanov@nginx.com         return;
3620570Smax.romanov@nginx.com     }
3621425Smax.romanov@nginx.com 
36221007Salexander.borisov@nginx.com     if (r->error) {
36231123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3624608Sigor@sysoev.ru         return;
3625608Sigor@sysoev.ru     }
3626608Sigor@sysoev.ru 
36271547Smax.romanov@nginx.com     app = req_rpc_data->app;
36281547Smax.romanov@nginx.com     nxt_assert(app != NULL);
36291547Smax.romanov@nginx.com 
36301547Smax.romanov@nginx.com     if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) {
36311547Smax.romanov@nginx.com         nxt_router_req_headers_ack_handler(task, msg, req_rpc_data);
36321547Smax.romanov@nginx.com 
36331547Smax.romanov@nginx.com         return;
36341547Smax.romanov@nginx.com     }
36351547Smax.romanov@nginx.com 
36361547Smax.romanov@nginx.com     b = (msg->size == 0) ? NULL : msg->buf;
36371547Smax.romanov@nginx.com 
363888Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
363988Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
364088Smax.romanov@nginx.com 
36411007Salexander.borisov@nginx.com         nxt_buf_chain_add(&b, nxt_http_buf_last(r));
3642167Smax.romanov@nginx.com 
36431547Smax.romanov@nginx.com         req_rpc_data->rpc_cancel = 0;
36441547Smax.romanov@nginx.com         req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE;
36451547Smax.romanov@nginx.com 
36461123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
3647425Smax.romanov@nginx.com 
3648425Smax.romanov@nginx.com     } else {
36491547Smax.romanov@nginx.com         if (app->timeout != 0) {
36501007Salexander.borisov@nginx.com             r->timer.handler = nxt_router_app_timeout;
36511123Smax.romanov@nginx.com             r->timer_data = req_rpc_data;
36521547Smax.romanov@nginx.com             nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
3653425Smax.romanov@nginx.com         }
365488Smax.romanov@nginx.com     }
365588Smax.romanov@nginx.com 
365688Smax.romanov@nginx.com     if (b == NULL) {
365788Smax.romanov@nginx.com         return;
365888Smax.romanov@nginx.com     }
365988Smax.romanov@nginx.com 
3660206Smax.romanov@nginx.com     if (msg->buf == b) {
3661206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
3662206Smax.romanov@nginx.com         msg->buf = NULL;
3663206Smax.romanov@nginx.com     }
3664194Smax.romanov@nginx.com 
3665431Sigor@sysoev.ru     if (r->header_sent) {
3666431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
3667431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
3668277Sigor@sysoev.ru 
366988Smax.romanov@nginx.com     } else {
3670743Smax.romanov@nginx.com         size_t b_size = nxt_buf_mem_used_size(&b->mem);
3671743Smax.romanov@nginx.com 
3672743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp))) {
3673743Smax.romanov@nginx.com             goto fail;
3674743Smax.romanov@nginx.com         }
3675743Smax.romanov@nginx.com 
3676743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
3677743Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(*resp)
3678743Smax.romanov@nginx.com               + resp->fields_count * sizeof(nxt_unit_field_t))) {
3679743Smax.romanov@nginx.com             goto fail;
3680743Smax.romanov@nginx.com         }
3681743Smax.romanov@nginx.com 
36821126Smax.romanov@nginx.com         field = NULL;
36831126Smax.romanov@nginx.com 
3684743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
36851126Smax.romanov@nginx.com             if (f->skip) {
36861126Smax.romanov@nginx.com                 continue;
36871126Smax.romanov@nginx.com             }
36881126Smax.romanov@nginx.com 
36891007Salexander.borisov@nginx.com             field = nxt_list_add(r->resp.fields);
3690743Smax.romanov@nginx.com 
3691743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
3692743Smax.romanov@nginx.com                 goto fail;
3693743Smax.romanov@nginx.com             }
3694743Smax.romanov@nginx.com 
3695743Smax.romanov@nginx.com             field->hash = f->hash;
36961126Smax.romanov@nginx.com             field->skip = 0;
36971270Sigor@sysoev.ru             field->hopbyhop = 0;
3698743Smax.romanov@nginx.com 
3699743Smax.romanov@nginx.com             field->name_length = f->name_length;
3700743Smax.romanov@nginx.com             field->value_length = f->value_length;
3701743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
3702743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
3703743Smax.romanov@nginx.com 
37041126Smax.romanov@nginx.com             ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
37051126Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
37061126Smax.romanov@nginx.com                 goto fail;
37071126Smax.romanov@nginx.com             }
37081126Smax.romanov@nginx.com 
37091126Smax.romanov@nginx.com             nxt_debug(task, "header%s: %*s: %*s",
37101126Smax.romanov@nginx.com                       (field->skip ? " skipped" : ""),
3711743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
3712743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
37131126Smax.romanov@nginx.com 
37141126Smax.romanov@nginx.com             if (field->skip) {
37151126Smax.romanov@nginx.com                 r->resp.fields->last->nelts--;
37161126Smax.romanov@nginx.com             }
3717743Smax.romanov@nginx.com         }
37181007Salexander.borisov@nginx.com 
3719743Smax.romanov@nginx.com         r->status = resp->status;
3720743Smax.romanov@nginx.com 
3721743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
3722743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3723743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
3724743Smax.romanov@nginx.com 
3725743Smax.romanov@nginx.com         } else {
3726743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
3727743Smax.romanov@nginx.com         }
3728743Smax.romanov@nginx.com 
3729435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
37301269Sigor@sysoev.ru             next = b->next;
37311269Sigor@sysoev.ru             b->next = NULL;
37321269Sigor@sysoev.ru 
3733435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3734435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
3735507Smax.romanov@nginx.com 
37361269Sigor@sysoev.ru             b = next;
3737520Smax.romanov@nginx.com         }
3738520Smax.romanov@nginx.com 
3739520Smax.romanov@nginx.com         if (b != NULL) {
3740431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
3741431Sigor@sysoev.ru         }
3742431Sigor@sysoev.ru 
37431270Sigor@sysoev.ru         nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL);
37441127Smax.romanov@nginx.com 
37451131Smax.romanov@nginx.com         if (r->websocket_handshake
37461131Smax.romanov@nginx.com             && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
37471131Smax.romanov@nginx.com         {
37481547Smax.romanov@nginx.com             app_port = req_rpc_data->app_port;
37491131Smax.romanov@nginx.com             if (nxt_slow_path(app_port == NULL)) {
37501131Smax.romanov@nginx.com                 goto fail;
37511131Smax.romanov@nginx.com             }
37521131Smax.romanov@nginx.com 
37531547Smax.romanov@nginx.com             nxt_thread_mutex_lock(&app->mutex);
37541547Smax.romanov@nginx.com 
37551547Smax.romanov@nginx.com             app_port->main_app_port->active_websockets++;
37561547Smax.romanov@nginx.com 
37571547Smax.romanov@nginx.com             nxt_thread_mutex_unlock(&app->mutex);
37581131Smax.romanov@nginx.com 
37591131Smax.romanov@nginx.com             nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE);
37601547Smax.romanov@nginx.com             req_rpc_data->apr_action = NXT_APR_CLOSE;
37611547Smax.romanov@nginx.com 
37621547Smax.romanov@nginx.com             nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream);
37631131Smax.romanov@nginx.com 
37641131Smax.romanov@nginx.com             r->state = &nxt_http_websocket;
37651131Smax.romanov@nginx.com 
37661131Smax.romanov@nginx.com         } else {
37671131Smax.romanov@nginx.com             r->state = &nxt_http_request_send_state;
37681131Smax.romanov@nginx.com         }
3769431Sigor@sysoev.ru     }
3770431Sigor@sysoev.ru 
3771431Sigor@sysoev.ru     return;
3772431Sigor@sysoev.ru 
3773431Sigor@sysoev.ru fail:
3774431Sigor@sysoev.ru 
3775615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
3776615Smax.romanov@nginx.com 
37771123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3778431Sigor@sysoev.ru }
3779431Sigor@sysoev.ru 
3780431Sigor@sysoev.ru 
37811547Smax.romanov@nginx.com static void
37821547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(nxt_task_t *task,
37831547Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data)
37841547Smax.romanov@nginx.com {
37851555Smax.romanov@nginx.com     int                 res;
37861547Smax.romanov@nginx.com     nxt_app_t           *app;
37871547Smax.romanov@nginx.com     nxt_bool_t          start_process;
37881547Smax.romanov@nginx.com     nxt_port_t          *app_port, *main_app_port, *idle_port;
37891547Smax.romanov@nginx.com     nxt_queue_link_t    *idle_lnk;
37901547Smax.romanov@nginx.com     nxt_http_request_t  *r;
37911547Smax.romanov@nginx.com 
37921547Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD: got ack from %PI:%d",
37931547Smax.romanov@nginx.com               req_rpc_data->stream,
37941547Smax.romanov@nginx.com               msg->port_msg.pid, msg->port_msg.reply_port);
37951547Smax.romanov@nginx.com 
37961547Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data,
37971547Smax.romanov@nginx.com                              msg->port_msg.pid);
37981547Smax.romanov@nginx.com 
37991547Smax.romanov@nginx.com     app = req_rpc_data->app;
38001547Smax.romanov@nginx.com 
38011547Smax.romanov@nginx.com     start_process = 0;
38021547Smax.romanov@nginx.com 
38031547Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
38041547Smax.romanov@nginx.com 
38051547Smax.romanov@nginx.com     app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid,
38061547Smax.romanov@nginx.com                                   msg->port_msg.reply_port);
38071547Smax.romanov@nginx.com     if (nxt_slow_path(app_port == NULL)) {
38081547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
38091547Smax.romanov@nginx.com 
38101547Smax.romanov@nginx.com         r = req_rpc_data->request;
38111547Smax.romanov@nginx.com         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
38121547Smax.romanov@nginx.com 
38131547Smax.romanov@nginx.com         return;
38141547Smax.romanov@nginx.com     }
38151547Smax.romanov@nginx.com 
38161547Smax.romanov@nginx.com     main_app_port = app_port->main_app_port;
38171547Smax.romanov@nginx.com 
38181547Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&main_app_port->idle_link)) {
38191547Smax.romanov@nginx.com         app->idle_processes--;
38201547Smax.romanov@nginx.com 
38211549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)",
38221549Smax.romanov@nginx.com                   &app->name, main_app_port->pid, main_app_port->id,
38231549Smax.romanov@nginx.com                   (main_app_port->idle_start ? "idle_ports" : "spare_ports"));
38241549Smax.romanov@nginx.com 
38251547Smax.romanov@nginx.com         /* Check port was in 'spare_ports' using idle_start field. */
38261547Smax.romanov@nginx.com         if (main_app_port->idle_start == 0
38271547Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
38281547Smax.romanov@nginx.com         {
38291547Smax.romanov@nginx.com             /*
38301547Smax.romanov@nginx.com              * If there is a vacant space in spare ports,
38311547Smax.romanov@nginx.com              * move the last idle to spare_ports.
38321547Smax.romanov@nginx.com              */
38331547Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
38341547Smax.romanov@nginx.com 
38351547Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
38361547Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
38371547Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
38381547Smax.romanov@nginx.com 
38391547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
38401547Smax.romanov@nginx.com 
38411547Smax.romanov@nginx.com             idle_port->idle_start = 0;
38421549Smax.romanov@nginx.com 
38431549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
38441549Smax.romanov@nginx.com                       "to spare_ports",
38451549Smax.romanov@nginx.com                       &app->name, idle_port->pid, idle_port->id);
38461547Smax.romanov@nginx.com         }
38471547Smax.romanov@nginx.com 
38481547Smax.romanov@nginx.com         if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
38491547Smax.romanov@nginx.com             app->pending_processes++;
38501547Smax.romanov@nginx.com             start_process = 1;
38511547Smax.romanov@nginx.com         }
38521547Smax.romanov@nginx.com     }
38531547Smax.romanov@nginx.com 
38541547Smax.romanov@nginx.com     main_app_port->active_requests++;
38551547Smax.romanov@nginx.com 
38561547Smax.romanov@nginx.com     nxt_port_inc_use(app_port);
38571547Smax.romanov@nginx.com 
38581547Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
38591547Smax.romanov@nginx.com 
38601547Smax.romanov@nginx.com     if (start_process) {
38611547Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
38621547Smax.romanov@nginx.com     }
38631547Smax.romanov@nginx.com 
38641547Smax.romanov@nginx.com     nxt_port_use(task, req_rpc_data->app_port, -1);
38651547Smax.romanov@nginx.com 
38661547Smax.romanov@nginx.com     req_rpc_data->app_port = app_port;
38671547Smax.romanov@nginx.com 
38681555Smax.romanov@nginx.com     if (req_rpc_data->msg_info.body_fd != -1) {
38691555Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream,
38701555Smax.romanov@nginx.com                   req_rpc_data->msg_info.body_fd);
38711555Smax.romanov@nginx.com 
38721555Smax.romanov@nginx.com         lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET);
38731555Smax.romanov@nginx.com 
38741555Smax.romanov@nginx.com         res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY,
38751555Smax.romanov@nginx.com                                     req_rpc_data->msg_info.body_fd,
38761555Smax.romanov@nginx.com                                     req_rpc_data->stream,
38771555Smax.romanov@nginx.com                                     task->thread->engine->port->id, NULL);
38781555Smax.romanov@nginx.com 
38791555Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
38801555Smax.romanov@nginx.com             r = req_rpc_data->request;
38811555Smax.romanov@nginx.com 
38821555Smax.romanov@nginx.com             nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
38831555Smax.romanov@nginx.com         }
38841555Smax.romanov@nginx.com     }
38851555Smax.romanov@nginx.com 
38861547Smax.romanov@nginx.com     if (app->timeout != 0) {
38871547Smax.romanov@nginx.com         r = req_rpc_data->request;
38881547Smax.romanov@nginx.com 
38891547Smax.romanov@nginx.com         r->timer.handler = nxt_router_app_timeout;
38901547Smax.romanov@nginx.com         r->timer_data = req_rpc_data;
38911547Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
38921547Smax.romanov@nginx.com     }
38931547Smax.romanov@nginx.com }
38941547Smax.romanov@nginx.com 
38951547Smax.romanov@nginx.com 
3896431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
3897431Sigor@sysoev.ru     nxt_aligned(64) =
3898431Sigor@sysoev.ru {
3899943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
3900431Sigor@sysoev.ru };
3901431Sigor@sysoev.ru 
3902431Sigor@sysoev.ru 
3903431Sigor@sysoev.ru static void
3904431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
3905431Sigor@sysoev.ru {
3906431Sigor@sysoev.ru     nxt_buf_t           *out;
3907431Sigor@sysoev.ru     nxt_http_request_t  *r;
3908431Sigor@sysoev.ru 
3909431Sigor@sysoev.ru     r = obj;
3910431Sigor@sysoev.ru 
3911431Sigor@sysoev.ru     out = r->out;
3912431Sigor@sysoev.ru 
3913431Sigor@sysoev.ru     if (out != NULL) {
3914431Sigor@sysoev.ru         r->out = NULL;
3915431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
391688Smax.romanov@nginx.com     }
391788Smax.romanov@nginx.com }
391888Smax.romanov@nginx.com 
3919277Sigor@sysoev.ru 
3920318Smax.romanov@nginx.com static void
3921318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3922318Smax.romanov@nginx.com     void *data)
3923318Smax.romanov@nginx.com {
39241123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
39251123Smax.romanov@nginx.com 
39261123Smax.romanov@nginx.com     req_rpc_data = data;
39271123Smax.romanov@nginx.com 
39281547Smax.romanov@nginx.com     req_rpc_data->rpc_cancel = 0;
39291547Smax.romanov@nginx.com 
39301547Smax.romanov@nginx.com     /* TODO cancel message and return if cancelled. */
39311547Smax.romanov@nginx.com     // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
3932425Smax.romanov@nginx.com 
39331123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
39341123Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
3935616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
3936616Smax.romanov@nginx.com     }
3937318Smax.romanov@nginx.com 
39381123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
3939318Smax.romanov@nginx.com }
3940318Smax.romanov@nginx.com 
3941318Smax.romanov@nginx.com 
3942141Smax.romanov@nginx.com static void
3943343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3944343Smax.romanov@nginx.com     void *data)
3945192Smax.romanov@nginx.com {
3946753Smax.romanov@nginx.com     nxt_app_t        *app;
3947753Smax.romanov@nginx.com     nxt_port_t       *port;
3948753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
3949753Smax.romanov@nginx.com 
3950753Smax.romanov@nginx.com     app_joint = data;
3951347Smax.romanov@nginx.com     port = msg->u.new_port;
3952343Smax.romanov@nginx.com 
3953753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
3954343Smax.romanov@nginx.com     nxt_assert(port != NULL);
39551547Smax.romanov@nginx.com     nxt_assert(port->type == NXT_PROCESS_APP);
39561547Smax.romanov@nginx.com     nxt_assert(port->id == 0);
3957343Smax.romanov@nginx.com 
3958753Smax.romanov@nginx.com     app = app_joint->app;
3959753Smax.romanov@nginx.com 
3960753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
3961753Smax.romanov@nginx.com 
3962753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
3963753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
3964753Smax.romanov@nginx.com 
3965753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
3966753Smax.romanov@nginx.com 
3967753Smax.romanov@nginx.com         return;
3968753Smax.romanov@nginx.com     }
3969753Smax.romanov@nginx.com 
3970343Smax.romanov@nginx.com     port->app = app;
39711547Smax.romanov@nginx.com     port->main_app_port = port;
3972343Smax.romanov@nginx.com 
3973343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
3974343Smax.romanov@nginx.com 
3975507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
3976507Smax.romanov@nginx.com 
3977507Smax.romanov@nginx.com     app->pending_processes--;
3978507Smax.romanov@nginx.com     app->processes++;
39791547Smax.romanov@nginx.com     nxt_port_hash_add(&app->port_hash, port);
39801547Smax.romanov@nginx.com     app->port_hash_count++;
3981343Smax.romanov@nginx.com 
3982343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
3983343Smax.romanov@nginx.com 
3984507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
3985507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
3986343Smax.romanov@nginx.com 
39871547Smax.romanov@nginx.com     nxt_router_app_shared_port_send(task, port);
39881547Smax.romanov@nginx.com 
39891123Smax.romanov@nginx.com     nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT);
3990192Smax.romanov@nginx.com }
3991192Smax.romanov@nginx.com 
3992192Smax.romanov@nginx.com 
39931547Smax.romanov@nginx.com static nxt_int_t
39941547Smax.romanov@nginx.com nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port)
39951547Smax.romanov@nginx.com {
39961547Smax.romanov@nginx.com     nxt_buf_t                *b;
39971547Smax.romanov@nginx.com     nxt_port_t               *port;
39981547Smax.romanov@nginx.com     nxt_port_msg_new_port_t  *msg;
39991547Smax.romanov@nginx.com 
40001547Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
40011547Smax.romanov@nginx.com                              sizeof(nxt_port_data_t));
40021547Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
40031547Smax.romanov@nginx.com         return NXT_ERROR;
40041547Smax.romanov@nginx.com     }
40051547Smax.romanov@nginx.com 
40061547Smax.romanov@nginx.com     port = app_port->app->shared_port;
40071547Smax.romanov@nginx.com 
40081547Smax.romanov@nginx.com     nxt_debug(task, "send port %FD to process %PI",
40091547Smax.romanov@nginx.com               port->pair[0], app_port->pid);
40101547Smax.romanov@nginx.com 
40111547Smax.romanov@nginx.com     b->mem.free += sizeof(nxt_port_msg_new_port_t);
40121547Smax.romanov@nginx.com     msg = (nxt_port_msg_new_port_t *) b->mem.pos;
40131547Smax.romanov@nginx.com 
40141547Smax.romanov@nginx.com     msg->id = port->id;
40151547Smax.romanov@nginx.com     msg->pid = port->pid;
40161547Smax.romanov@nginx.com     msg->max_size = port->max_size;
40171547Smax.romanov@nginx.com     msg->max_share = port->max_share;
40181547Smax.romanov@nginx.com     msg->type = port->type;
40191547Smax.romanov@nginx.com 
40201555Smax.romanov@nginx.com     return nxt_port_socket_write2(task, app_port,
40211547Smax.romanov@nginx.com                                   NXT_PORT_MSG_NEW_PORT,
40221555Smax.romanov@nginx.com                                   port->pair[0], port->queue_fd,
40231555Smax.romanov@nginx.com                                   0, 0, b);
40241547Smax.romanov@nginx.com }
40251547Smax.romanov@nginx.com 
40261547Smax.romanov@nginx.com 
4027192Smax.romanov@nginx.com static void
4028343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4029343Smax.romanov@nginx.com     void *data)
4030192Smax.romanov@nginx.com {
40311547Smax.romanov@nginx.com     nxt_app_t        *app;
40321547Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4033343Smax.romanov@nginx.com 
4034753Smax.romanov@nginx.com     app_joint = data;
4035753Smax.romanov@nginx.com 
4036753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
4037753Smax.romanov@nginx.com 
4038753Smax.romanov@nginx.com     app = app_joint->app;
4039753Smax.romanov@nginx.com 
4040753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4041753Smax.romanov@nginx.com 
4042753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
4043753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
4044753Smax.romanov@nginx.com 
4045753Smax.romanov@nginx.com         return;
4046753Smax.romanov@nginx.com     }
4047343Smax.romanov@nginx.com 
4048343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
4049343Smax.romanov@nginx.com 
4050343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4051343Smax.romanov@nginx.com 
4052507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
4053507Smax.romanov@nginx.com 
4054507Smax.romanov@nginx.com     app->pending_processes--;
4055318Smax.romanov@nginx.com 
4056343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4057343Smax.romanov@nginx.com 
40581547Smax.romanov@nginx.com     /* TODO req_app_link to cancel first pending message */
4059192Smax.romanov@nginx.com }
4060192Smax.romanov@nginx.com 
4061192Smax.romanov@nginx.com 
4062343Smax.romanov@nginx.com void
4063343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
4064141Smax.romanov@nginx.com {
4065343Smax.romanov@nginx.com     int  c;
4066343Smax.romanov@nginx.com 
4067343Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
4068343Smax.romanov@nginx.com 
4069343Smax.romanov@nginx.com     if (i < 0 && c == -i) {
4070343Smax.romanov@nginx.com 
4071753Smax.romanov@nginx.com         if (task->thread->engine != app->engine) {
4072753Smax.romanov@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
4073753Smax.romanov@nginx.com 
4074753Smax.romanov@nginx.com         } else {
4075753Smax.romanov@nginx.com             nxt_router_free_app(task, app->joint, NULL);
4076753Smax.romanov@nginx.com         }
4077163Smax.romanov@nginx.com     }
4078343Smax.romanov@nginx.com }
4079343Smax.romanov@nginx.com 
4080343Smax.romanov@nginx.com 
4081507Smax.romanov@nginx.com nxt_inline nxt_port_t *
40821549Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
4083141Smax.romanov@nginx.com {
4084343Smax.romanov@nginx.com     nxt_port_t  *port;
4085141Smax.romanov@nginx.com 
4086141Smax.romanov@nginx.com     port = NULL;
4087141Smax.romanov@nginx.com 
4088141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4089141Smax.romanov@nginx.com 
4090343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
4091343Smax.romanov@nginx.com 
4092507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
4093507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4094507Smax.romanov@nginx.com 
4095507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
4096507Smax.romanov@nginx.com             app->idle_processes--;
40971549Smax.romanov@nginx.com 
40981549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit",
40991549Smax.romanov@nginx.com                       &app->name, port->pid, port->id,
41001549Smax.romanov@nginx.com                       (port->idle_start ? "idle_ports" : "spare_ports"));
4101507Smax.romanov@nginx.com         }
4102507Smax.romanov@nginx.com 
41031547Smax.romanov@nginx.com         nxt_port_hash_remove(&app->port_hash, port);
41041547Smax.romanov@nginx.com         app->port_hash_count--;
41051547Smax.romanov@nginx.com 
4106507Smax.romanov@nginx.com         port->app = NULL;
4107507Smax.romanov@nginx.com         app->processes--;
4108343Smax.romanov@nginx.com 
4109343Smax.romanov@nginx.com         break;
4110343Smax.romanov@nginx.com 
4111343Smax.romanov@nginx.com     } nxt_queue_loop;
4112141Smax.romanov@nginx.com 
4113141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4114141Smax.romanov@nginx.com 
4115141Smax.romanov@nginx.com     return port;
4116141Smax.romanov@nginx.com }
4117141Smax.romanov@nginx.com 
4118141Smax.romanov@nginx.com 
4119141Smax.romanov@nginx.com static void
4120753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
4121507Smax.romanov@nginx.com {
4122753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
4123507Smax.romanov@nginx.com 
4124507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
4125507Smax.romanov@nginx.com 
4126753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
4127507Smax.romanov@nginx.com }
4128507Smax.romanov@nginx.com 
4129507Smax.romanov@nginx.com 
4130507Smax.romanov@nginx.com static void
4131343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
41321123Smax.romanov@nginx.com     nxt_apr_action_t action)
4133343Smax.romanov@nginx.com {
41341547Smax.romanov@nginx.com     int         inc_use;
41351547Smax.romanov@nginx.com     uint32_t    got_response, dec_requests;
41361547Smax.romanov@nginx.com     nxt_app_t   *app;
41371547Smax.romanov@nginx.com     nxt_bool_t  port_unchained, send_quit, adjust_idle_timer;
41381547Smax.romanov@nginx.com     nxt_port_t  *main_app_port;
4139343Smax.romanov@nginx.com 
4140343Smax.romanov@nginx.com     nxt_assert(port != NULL);
4141343Smax.romanov@nginx.com     nxt_assert(port->app != NULL);
4142343Smax.romanov@nginx.com 
4143343Smax.romanov@nginx.com     app = port->app;
4144343Smax.romanov@nginx.com 
41451123Smax.romanov@nginx.com     inc_use = 0;
41461123Smax.romanov@nginx.com     got_response = 0;
41471547Smax.romanov@nginx.com     dec_requests = 0;
41481123Smax.romanov@nginx.com 
41491123Smax.romanov@nginx.com     switch (action) {
41501123Smax.romanov@nginx.com     case NXT_APR_NEW_PORT:
41511123Smax.romanov@nginx.com         break;
41521123Smax.romanov@nginx.com     case NXT_APR_REQUEST_FAILED:
41531547Smax.romanov@nginx.com         dec_requests = 1;
41541123Smax.romanov@nginx.com         inc_use = -1;
41551123Smax.romanov@nginx.com         break;
41561123Smax.romanov@nginx.com     case NXT_APR_GOT_RESPONSE:
41571123Smax.romanov@nginx.com         got_response = 1;
41581123Smax.romanov@nginx.com         inc_use = -1;
41591123Smax.romanov@nginx.com         break;
41601131Smax.romanov@nginx.com     case NXT_APR_UPGRADE:
41611131Smax.romanov@nginx.com         got_response = 1;
41621131Smax.romanov@nginx.com         break;
41631123Smax.romanov@nginx.com     case NXT_APR_CLOSE:
41641123Smax.romanov@nginx.com         inc_use = -1;
41651123Smax.romanov@nginx.com         break;
41661123Smax.romanov@nginx.com     }
41671123Smax.romanov@nginx.com 
41681547Smax.romanov@nginx.com     nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name,
41691547Smax.romanov@nginx.com               port->pid, port->id,
41701547Smax.romanov@nginx.com               (int) inc_use, (int) got_response);
41711547Smax.romanov@nginx.com 
41721547Smax.romanov@nginx.com     if (port == app->shared_port) {
41731547Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
41741547Smax.romanov@nginx.com 
41751547Smax.romanov@nginx.com         app->active_requests -= got_response + dec_requests;
41761547Smax.romanov@nginx.com 
41771547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
41781547Smax.romanov@nginx.com 
41791547Smax.romanov@nginx.com         goto adjust_use;
41801547Smax.romanov@nginx.com     }
41811547Smax.romanov@nginx.com 
41821547Smax.romanov@nginx.com     main_app_port = port->main_app_port;
41831547Smax.romanov@nginx.com 
4184343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4185343Smax.romanov@nginx.com 
41861547Smax.romanov@nginx.com     main_app_port->app_responses += got_response;
41871547Smax.romanov@nginx.com     main_app_port->active_requests -= got_response + dec_requests;
41881547Smax.romanov@nginx.com     app->active_requests -= got_response + dec_requests;
41891547Smax.romanov@nginx.com 
41901547Smax.romanov@nginx.com     if (main_app_port->pair[1] != -1
4191428Smax.romanov@nginx.com         && (app->max_requests == 0
41921547Smax.romanov@nginx.com             || main_app_port->app_responses < app->max_requests))
4193425Smax.romanov@nginx.com     {
41941547Smax.romanov@nginx.com         if (main_app_port->app_link.next == NULL) {
41951547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->ports, &main_app_port->app_link);
41961547Smax.romanov@nginx.com 
41971547Smax.romanov@nginx.com             nxt_port_inc_use(main_app_port);
4198427Smax.romanov@nginx.com         }
4199427Smax.romanov@nginx.com     }
4200427Smax.romanov@nginx.com 
4201753Smax.romanov@nginx.com     send_quit = (app->max_requests > 0
42021547Smax.romanov@nginx.com                  && main_app_port->app_responses >= app->max_requests);
4203367Smax.romanov@nginx.com 
4204507Smax.romanov@nginx.com     if (send_quit) {
42051547Smax.romanov@nginx.com         port_unchained = nxt_queue_chk_remove(&main_app_port->app_link);
42061547Smax.romanov@nginx.com 
42071547Smax.romanov@nginx.com         nxt_port_hash_remove(&app->port_hash, main_app_port);
42081547Smax.romanov@nginx.com         app->port_hash_count--;
42091547Smax.romanov@nginx.com 
42101547Smax.romanov@nginx.com         main_app_port->app = NULL;
4211507Smax.romanov@nginx.com         app->processes--;
4212507Smax.romanov@nginx.com 
4213507Smax.romanov@nginx.com     } else {
4214507Smax.romanov@nginx.com         port_unchained = 0;
4215507Smax.romanov@nginx.com     }
4216507Smax.romanov@nginx.com 
4217507Smax.romanov@nginx.com     adjust_idle_timer = 0;
4218507Smax.romanov@nginx.com 
42191547Smax.romanov@nginx.com     if (main_app_port->pair[1] != -1 && !send_quit
42201547Smax.romanov@nginx.com         && main_app_port->active_requests == 0
42211547Smax.romanov@nginx.com         && main_app_port->active_websockets == 0
42221547Smax.romanov@nginx.com         && main_app_port->idle_link.next == NULL)
42231131Smax.romanov@nginx.com     {
4224507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
4225507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
4226507Smax.romanov@nginx.com         {
4227507Smax.romanov@nginx.com             adjust_idle_timer = 1;
4228507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
4229507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
4230507Smax.romanov@nginx.com         }
4231507Smax.romanov@nginx.com 
4232507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
42331547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link);
4234507Smax.romanov@nginx.com 
42351549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d to spare_ports",
42361549Smax.romanov@nginx.com                       &app->name, main_app_port->pid, main_app_port->id);
4237507Smax.romanov@nginx.com         } else {
42381547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link);
42391547Smax.romanov@nginx.com 
42401547Smax.romanov@nginx.com             main_app_port->idle_start = task->thread->engine->timers.now;
42411549Smax.romanov@nginx.com 
42421549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d to idle_ports",
42431549Smax.romanov@nginx.com                       &app->name, main_app_port->pid, main_app_port->id);
4244507Smax.romanov@nginx.com         }
4245507Smax.romanov@nginx.com 
4246507Smax.romanov@nginx.com         app->idle_processes++;
4247507Smax.romanov@nginx.com     }
4248507Smax.romanov@nginx.com 
4249343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4250343Smax.romanov@nginx.com 
4251507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4252507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4253507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4254507Smax.romanov@nginx.com     }
4255507Smax.romanov@nginx.com 
4256343Smax.romanov@nginx.com     /* ? */
42571547Smax.romanov@nginx.com     if (main_app_port->pair[1] == -1) {
4258343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
42591547Smax.romanov@nginx.com                   &app->name, app, main_app_port, main_app_port->pid);
4260343Smax.romanov@nginx.com 
4261343Smax.romanov@nginx.com         goto adjust_use;
4262163Smax.romanov@nginx.com     }
4263163Smax.romanov@nginx.com 
4264367Smax.romanov@nginx.com     if (send_quit) {
42651547Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p send QUIT to port", &app->name, app);
42661547Smax.romanov@nginx.com 
42671547Smax.romanov@nginx.com         nxt_port_socket_write(task, main_app_port, NXT_PORT_MSG_QUIT, -1, 0, 0,
42681547Smax.romanov@nginx.com                               NULL);
4269163Smax.romanov@nginx.com 
4270507Smax.romanov@nginx.com         if (port_unchained) {
42711547Smax.romanov@nginx.com             nxt_port_use(task, main_app_port, -1);
4272507Smax.romanov@nginx.com         }
4273507Smax.romanov@nginx.com 
4274343Smax.romanov@nginx.com         goto adjust_use;
4275163Smax.romanov@nginx.com     }
4276163Smax.romanov@nginx.com 
4277167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4278167Smax.romanov@nginx.com               &app->name, app);
4279141Smax.romanov@nginx.com 
4280343Smax.romanov@nginx.com adjust_use:
4281343Smax.romanov@nginx.com 
42821123Smax.romanov@nginx.com     nxt_port_use(task, port, inc_use);
4283141Smax.romanov@nginx.com }
4284141Smax.romanov@nginx.com 
4285141Smax.romanov@nginx.com 
4286343Smax.romanov@nginx.com void
4287343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4288141Smax.romanov@nginx.com {
4289507Smax.romanov@nginx.com     nxt_app_t         *app;
4290507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4291507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4292507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4293141Smax.romanov@nginx.com 
4294141Smax.romanov@nginx.com     app = port->app;
4295343Smax.romanov@nginx.com 
4296343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4297141Smax.romanov@nginx.com 
4298141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4299141Smax.romanov@nginx.com 
43001547Smax.romanov@nginx.com     nxt_port_hash_remove(&app->port_hash, port);
43011547Smax.romanov@nginx.com     app->port_hash_count--;
43021547Smax.romanov@nginx.com 
43031547Smax.romanov@nginx.com     if (port->id != 0) {
43041547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
43051547Smax.romanov@nginx.com 
43061547Smax.romanov@nginx.com         nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name,
43071547Smax.romanov@nginx.com                   port->pid, port->id);
43081547Smax.romanov@nginx.com 
43091547Smax.romanov@nginx.com         return;
43101547Smax.romanov@nginx.com     }
43111547Smax.romanov@nginx.com 
4312507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4313507Smax.romanov@nginx.com 
4314507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4315507Smax.romanov@nginx.com         app->idle_processes--;
4316507Smax.romanov@nginx.com 
43171549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of %s before close",
43181549Smax.romanov@nginx.com                   &app->name, port->pid, port->id,
43191549Smax.romanov@nginx.com                   (port->idle_start ? "idle_ports" : "spare_ports"));
43201549Smax.romanov@nginx.com 
4321507Smax.romanov@nginx.com         if (port->idle_start == 0
4322507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4323507Smax.romanov@nginx.com         {
4324507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4325507Smax.romanov@nginx.com 
4326507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4327507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4328507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4329507Smax.romanov@nginx.com 
4330507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4331507Smax.romanov@nginx.com 
4332507Smax.romanov@nginx.com             idle_port->idle_start = 0;
43331549Smax.romanov@nginx.com 
43341549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
43351549Smax.romanov@nginx.com                       "to spare_ports",
43361549Smax.romanov@nginx.com                       &app->name, idle_port->pid, idle_port->id);
4337507Smax.romanov@nginx.com         }
4338343Smax.romanov@nginx.com     }
4339343Smax.romanov@nginx.com 
4340507Smax.romanov@nginx.com     app->processes--;
4341507Smax.romanov@nginx.com 
4342753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4343507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
43441547Smax.romanov@nginx.com                     && nxt_router_app_need_start(app);
4345507Smax.romanov@nginx.com 
4346507Smax.romanov@nginx.com     if (start_process) {
4347507Smax.romanov@nginx.com         app->pending_processes++;
4348163Smax.romanov@nginx.com     }
4349141Smax.romanov@nginx.com 
4350141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4351163Smax.romanov@nginx.com 
4352507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4353343Smax.romanov@nginx.com 
4354343Smax.romanov@nginx.com     if (unchain) {
4355343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4356163Smax.romanov@nginx.com     }
4357163Smax.romanov@nginx.com 
4358507Smax.romanov@nginx.com     if (start_process) {
4359507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4360507Smax.romanov@nginx.com     }
4361507Smax.romanov@nginx.com }
4362507Smax.romanov@nginx.com 
4363507Smax.romanov@nginx.com 
4364507Smax.romanov@nginx.com static void
4365507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4366507Smax.romanov@nginx.com {
4367507Smax.romanov@nginx.com     nxt_app_t           *app;
4368507Smax.romanov@nginx.com     nxt_bool_t          queued;
4369507Smax.romanov@nginx.com     nxt_port_t          *port;
4370507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4371507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4372507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4373507Smax.romanov@nginx.com 
4374507Smax.romanov@nginx.com     app = obj;
4375507Smax.romanov@nginx.com     queued = (data == app);
4376507Smax.romanov@nginx.com 
4377507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4378507Smax.romanov@nginx.com               &app->name, queued);
4379507Smax.romanov@nginx.com 
4380507Smax.romanov@nginx.com     engine = task->thread->engine;
4381507Smax.romanov@nginx.com 
4382507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
4383507Smax.romanov@nginx.com 
4384811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
4385507Smax.romanov@nginx.com     timeout = 0;
4386507Smax.romanov@nginx.com 
4387507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4388507Smax.romanov@nginx.com 
4389507Smax.romanov@nginx.com     if (queued) {
4390507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
4391343Smax.romanov@nginx.com     }
4392507Smax.romanov@nginx.com 
43931547Smax.romanov@nginx.com     nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d",
43941547Smax.romanov@nginx.com               &app->name,
43951547Smax.romanov@nginx.com               (int) app->idle_processes, (int) app->spare_processes);
43961547Smax.romanov@nginx.com 
4397507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
4398507Smax.romanov@nginx.com 
4399551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4400507Smax.romanov@nginx.com 
4401507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
4402507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4403507Smax.romanov@nginx.com 
4404507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
4405507Smax.romanov@nginx.com 
44061547Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M",
44071547Smax.romanov@nginx.com                   &app->name, port->pid,
44081547Smax.romanov@nginx.com                   port->idle_start, timeout, threshold);
44091547Smax.romanov@nginx.com 
4410507Smax.romanov@nginx.com         if (timeout > threshold) {
4411507Smax.romanov@nginx.com             break;
4412507Smax.romanov@nginx.com         }
4413507Smax.romanov@nginx.com 
4414507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
4415507Smax.romanov@nginx.com         lnk->next = NULL;
4416507Smax.romanov@nginx.com 
44171549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)",
44181549Smax.romanov@nginx.com                   &app->name, port->pid, port->id);
44191549Smax.romanov@nginx.com 
4420507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4421507Smax.romanov@nginx.com 
44221547Smax.romanov@nginx.com         nxt_port_hash_remove(&app->port_hash, port);
44231547Smax.romanov@nginx.com         app->port_hash_count--;
44241547Smax.romanov@nginx.com 
4425507Smax.romanov@nginx.com         app->idle_processes--;
4426507Smax.romanov@nginx.com         app->processes--;
4427507Smax.romanov@nginx.com         port->app = NULL;
4428507Smax.romanov@nginx.com 
4429507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
4430507Smax.romanov@nginx.com 
4431507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4432507Smax.romanov@nginx.com                   &app->name, port->pid);
4433507Smax.romanov@nginx.com 
4434507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4435507Smax.romanov@nginx.com 
4436507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4437507Smax.romanov@nginx.com 
4438507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
4439507Smax.romanov@nginx.com     }
4440507Smax.romanov@nginx.com 
4441507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4442507Smax.romanov@nginx.com 
4443507Smax.romanov@nginx.com     if (timeout > threshold) {
4444753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4445507Smax.romanov@nginx.com 
4446507Smax.romanov@nginx.com     } else {
4447753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
4448507Smax.romanov@nginx.com     }
4449507Smax.romanov@nginx.com 
4450507Smax.romanov@nginx.com     if (queued) {
4451507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
4452507Smax.romanov@nginx.com     }
4453507Smax.romanov@nginx.com }
4454507Smax.romanov@nginx.com 
4455507Smax.romanov@nginx.com 
4456507Smax.romanov@nginx.com static void
4457507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4458507Smax.romanov@nginx.com {
4459753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4460753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4461507Smax.romanov@nginx.com 
4462507Smax.romanov@nginx.com     timer = obj;
4463753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4464753Smax.romanov@nginx.com 
4465753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
4466753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4467753Smax.romanov@nginx.com     }
4468753Smax.romanov@nginx.com }
4469753Smax.romanov@nginx.com 
4470753Smax.romanov@nginx.com 
4471753Smax.romanov@nginx.com static void
4472753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4473753Smax.romanov@nginx.com {
4474753Smax.romanov@nginx.com     nxt_timer_t      *timer;
4475753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4476753Smax.romanov@nginx.com 
4477753Smax.romanov@nginx.com     timer = obj;
4478753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4479753Smax.romanov@nginx.com 
4480753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4481507Smax.romanov@nginx.com }
4482507Smax.romanov@nginx.com 
4483507Smax.romanov@nginx.com 
4484507Smax.romanov@nginx.com static void
4485753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4486507Smax.romanov@nginx.com {
4487753Smax.romanov@nginx.com     nxt_app_t        *app;
4488753Smax.romanov@nginx.com     nxt_port_t       *port;
4489753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
4490753Smax.romanov@nginx.com 
4491753Smax.romanov@nginx.com     app_joint = obj;
4492753Smax.romanov@nginx.com     app = app_joint->app;
4493753Smax.romanov@nginx.com 
4494753Smax.romanov@nginx.com     for ( ;; ) {
44951549Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(task, app);
4496753Smax.romanov@nginx.com         if (port == NULL) {
4497753Smax.romanov@nginx.com             break;
4498753Smax.romanov@nginx.com         }
4499753Smax.romanov@nginx.com 
4500753Smax.romanov@nginx.com         nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4501753Smax.romanov@nginx.com 
4502753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4503753Smax.romanov@nginx.com 
4504753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4505753Smax.romanov@nginx.com     }
4506753Smax.romanov@nginx.com 
4507753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
45081547Smax.romanov@nginx.com     nxt_assert(app->active_requests == 0);
45091547Smax.romanov@nginx.com     nxt_assert(app->port_hash_count == 0);
4510753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
4511753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
4512753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4513753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4514753Smax.romanov@nginx.com 
45151547Smax.romanov@nginx.com     nxt_port_mmaps_destroy(&app->outgoing, 1);
45161547Smax.romanov@nginx.com 
45171547Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->outgoing.mutex);
45181547Smax.romanov@nginx.com 
45191547Smax.romanov@nginx.com     if (app->shared_port != NULL) {
45201547Smax.romanov@nginx.com         app->shared_port->app = NULL;
45211547Smax.romanov@nginx.com         nxt_port_close(task, app->shared_port);
45221547Smax.romanov@nginx.com         nxt_port_use(task, app->shared_port, -1);
45231547Smax.romanov@nginx.com     }
45241547Smax.romanov@nginx.com 
4525753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
45261473Svbart@nginx.com     nxt_mp_destroy(app->mem_pool);
4527753Smax.romanov@nginx.com 
4528753Smax.romanov@nginx.com     app_joint->app = NULL;
4529753Smax.romanov@nginx.com 
4530753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4531753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4532753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4533753Smax.romanov@nginx.com 
4534753Smax.romanov@nginx.com     } else {
4535753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
4536753Smax.romanov@nginx.com     }
4537141Smax.romanov@nginx.com }
4538141Smax.romanov@nginx.com 
4539141Smax.romanov@nginx.com 
4540427Smax.romanov@nginx.com static void
45411547Smax.romanov@nginx.com nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
45421547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
4543141Smax.romanov@nginx.com {
45441547Smax.romanov@nginx.com     nxt_bool_t  start_process;
45451547Smax.romanov@nginx.com     nxt_port_t  *port;
45461547Smax.romanov@nginx.com 
45471547Smax.romanov@nginx.com     start_process = 0;
4548427Smax.romanov@nginx.com 
4549427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4550427Smax.romanov@nginx.com 
45511547Smax.romanov@nginx.com     port = app->shared_port;
45521547Smax.romanov@nginx.com     nxt_port_inc_use(port);
45531547Smax.romanov@nginx.com 
45541547Smax.romanov@nginx.com     app->active_requests++;
45551547Smax.romanov@nginx.com 
45561547Smax.romanov@nginx.com     if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
45571547Smax.romanov@nginx.com         app->pending_processes++;
45581547Smax.romanov@nginx.com         start_process = 1;
45591547Smax.romanov@nginx.com     }
4560427Smax.romanov@nginx.com 
4561427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4562427Smax.romanov@nginx.com 
45631547Smax.romanov@nginx.com     req_rpc_data->app_port = port;
45641547Smax.romanov@nginx.com     req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED;
45651547Smax.romanov@nginx.com 
45661547Smax.romanov@nginx.com     if (start_process) {
45671547Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
45681547Smax.romanov@nginx.com     }
4569427Smax.romanov@nginx.com }
4570427Smax.romanov@nginx.com 
4571427Smax.romanov@nginx.com 
4572431Sigor@sysoev.ru void
45731007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
4574964Sigor@sysoev.ru     nxt_app_t *app)
457553Sigor@sysoev.ru {
45761123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
45771123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
4578431Sigor@sysoev.ru 
457988Smax.romanov@nginx.com     engine = task->thread->engine;
458088Smax.romanov@nginx.com 
45811123Smax.romanov@nginx.com     req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
4582318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
4583318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
45841123Smax.romanov@nginx.com                                           sizeof(nxt_request_rpc_data_t));
45851123Smax.romanov@nginx.com     if (nxt_slow_path(req_rpc_data == NULL)) {
4586431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4587141Smax.romanov@nginx.com         return;
458888Smax.romanov@nginx.com     }
458988Smax.romanov@nginx.com 
45901402Smax.romanov@nginx.com     /*
45911402Smax.romanov@nginx.com      * At this point we have request req_rpc_data allocated and registered
45921402Smax.romanov@nginx.com      * in port handlers.  Need to fixup request memory pool.  Counterpart
45931402Smax.romanov@nginx.com      * release will be called via following call chain:
45941402Smax.romanov@nginx.com      *    nxt_request_rpc_data_unlink() ->
45951547Smax.romanov@nginx.com      *        nxt_router_http_request_release_post() ->
45961402Smax.romanov@nginx.com      *            nxt_router_http_request_release()
45971402Smax.romanov@nginx.com      */
45981402Smax.romanov@nginx.com     nxt_mp_retain(r->mem_pool);
45991402Smax.romanov@nginx.com 
46001402Smax.romanov@nginx.com     r->timer.task = &engine->task;
46011402Smax.romanov@nginx.com     r->timer.work_queue = &engine->fast_work_queue;
46021402Smax.romanov@nginx.com     r->timer.log = engine->task.log;
46031402Smax.romanov@nginx.com     r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
46041402Smax.romanov@nginx.com 
46051123Smax.romanov@nginx.com     req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
46061123Smax.romanov@nginx.com     req_rpc_data->app = app;
46071547Smax.romanov@nginx.com     req_rpc_data->msg_info.body_fd = -1;
46081547Smax.romanov@nginx.com     req_rpc_data->rpc_cancel = 1;
4609425Smax.romanov@nginx.com 
4610425Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
4611425Smax.romanov@nginx.com 
46121123Smax.romanov@nginx.com     req_rpc_data->request = r;
46131131Smax.romanov@nginx.com     r->req_rpc_data = req_rpc_data;
46141123Smax.romanov@nginx.com 
46151547Smax.romanov@nginx.com     if (r->last != NULL) {
46161547Smax.romanov@nginx.com         r->last->completion_handler = nxt_router_http_request_done;
46171547Smax.romanov@nginx.com     }
46181547Smax.romanov@nginx.com 
46191547Smax.romanov@nginx.com     nxt_router_app_port_get(task, app, req_rpc_data);
46201547Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, req_rpc_data);
46211547Smax.romanov@nginx.com }
46221547Smax.romanov@nginx.com 
46231547Smax.romanov@nginx.com 
46241547Smax.romanov@nginx.com static void
46251547Smax.romanov@nginx.com nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data)
46261547Smax.romanov@nginx.com {
46271547Smax.romanov@nginx.com     nxt_http_request_t  *r;
46281547Smax.romanov@nginx.com 
46291547Smax.romanov@nginx.com     r = data;
46301547Smax.romanov@nginx.com 
46311547Smax.romanov@nginx.com     nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data);
46321547Smax.romanov@nginx.com 
46331547Smax.romanov@nginx.com     if (r->req_rpc_data) {
46341547Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, r->req_rpc_data);
46351547Smax.romanov@nginx.com     }
46361547Smax.romanov@nginx.com 
46371547Smax.romanov@nginx.com     nxt_http_request_close_handler(task, r, r->proto.any);
4638167Smax.romanov@nginx.com }
4639167Smax.romanov@nginx.com 
4640167Smax.romanov@nginx.com 
4641167Smax.romanov@nginx.com static void
4642423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
4643423Smax.romanov@nginx.com {
4644423Smax.romanov@nginx.com }
4645423Smax.romanov@nginx.com 
4646423Smax.romanov@nginx.com 
4647423Smax.romanov@nginx.com static void
46481123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task,
46491547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
4650167Smax.romanov@nginx.com {
46511547Smax.romanov@nginx.com     nxt_app_t         *app;
46521547Smax.romanov@nginx.com     nxt_buf_t         *buf, *body;
46531123Smax.romanov@nginx.com     nxt_int_t         res;
46541545Smax.romanov@nginx.com     nxt_port_t        *port, *reply_port;
46551547Smax.romanov@nginx.com 
46561555Smax.romanov@nginx.com     int                   notify;
46571555Smax.romanov@nginx.com     struct {
46581555Smax.romanov@nginx.com         nxt_port_msg_t       pm;
46591555Smax.romanov@nginx.com         nxt_port_mmap_msg_t  mm;
46601555Smax.romanov@nginx.com     } msg;
46611555Smax.romanov@nginx.com 
46621555Smax.romanov@nginx.com 
46631547Smax.romanov@nginx.com     app = req_rpc_data->app;
46641547Smax.romanov@nginx.com 
46651547Smax.romanov@nginx.com     nxt_assert(app != NULL);
46661547Smax.romanov@nginx.com 
46671547Smax.romanov@nginx.com     port = req_rpc_data->app_port;
46681547Smax.romanov@nginx.com 
46691547Smax.romanov@nginx.com     nxt_assert(port != NULL);
46701555Smax.romanov@nginx.com     nxt_assert(port->queue != NULL);
46711547Smax.romanov@nginx.com 
46721547Smax.romanov@nginx.com     reply_port = task->thread->engine->port;
46731547Smax.romanov@nginx.com 
46741547Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, req_rpc_data->request, app,
46751547Smax.romanov@nginx.com                                  nxt_app_msg_prefix[app->type]);
4676743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
46771547Smax.romanov@nginx.com         nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message",
46781547Smax.romanov@nginx.com                   req_rpc_data->stream, &app->name);
46791547Smax.romanov@nginx.com 
46801547Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
46811547Smax.romanov@nginx.com                                NXT_HTTP_INTERNAL_SERVER_ERROR);
46821547Smax.romanov@nginx.com 
46831547Smax.romanov@nginx.com         return;
4684122Smax.romanov@nginx.com     }
468588Smax.romanov@nginx.com 
4686507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
4687743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
4688743Smax.romanov@nginx.com                     port->socket.fd);
468988Smax.romanov@nginx.com 
46901547Smax.romanov@nginx.com     req_rpc_data->msg_info.buf = buf;
46911547Smax.romanov@nginx.com     req_rpc_data->msg_info.completion_handler = buf->completion_handler;
46921547Smax.romanov@nginx.com 
46931547Smax.romanov@nginx.com     do {
4694743Smax.romanov@nginx.com         buf->completion_handler = nxt_router_dummy_buf_completion;
46951547Smax.romanov@nginx.com         buf = buf->next;
46961547Smax.romanov@nginx.com     } while (buf != NULL);
46971547Smax.romanov@nginx.com 
46981547Smax.romanov@nginx.com     buf = req_rpc_data->msg_info.buf;
46991547Smax.romanov@nginx.com 
47001547Smax.romanov@nginx.com     body = req_rpc_data->request->body;
47011547Smax.romanov@nginx.com 
47021547Smax.romanov@nginx.com     if (body != NULL && nxt_buf_is_file(body)) {
47031547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = body->file->fd;
47041547Smax.romanov@nginx.com 
47051547Smax.romanov@nginx.com         body->file->fd = -1;
47061547Smax.romanov@nginx.com 
47071547Smax.romanov@nginx.com     } else {
47081547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = -1;
47091547Smax.romanov@nginx.com     }
47101547Smax.romanov@nginx.com 
47111555Smax.romanov@nginx.com     msg.pm.stream = req_rpc_data->stream;
47121555Smax.romanov@nginx.com     msg.pm.pid = reply_port->pid;
47131555Smax.romanov@nginx.com     msg.pm.reply_port = reply_port->id;
47141555Smax.romanov@nginx.com     msg.pm.type = NXT_PORT_MSG_REQ_HEADERS;
47151555Smax.romanov@nginx.com     msg.pm.last = 0;
47161555Smax.romanov@nginx.com     msg.pm.mmap = 1;
47171555Smax.romanov@nginx.com     msg.pm.nf = 0;
47181555Smax.romanov@nginx.com     msg.pm.mf = 0;
47191555Smax.romanov@nginx.com     msg.pm.tracking = 0;
47201555Smax.romanov@nginx.com 
47211555Smax.romanov@nginx.com     nxt_port_mmap_handler_t *mmap_handler = buf->parent;
47221555Smax.romanov@nginx.com     nxt_port_mmap_header_t *hdr = mmap_handler->hdr;
47231555Smax.romanov@nginx.com 
47241555Smax.romanov@nginx.com     msg.mm.mmap_id = hdr->id;
47251555Smax.romanov@nginx.com     msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos);
47261555Smax.romanov@nginx.com     msg.mm.size = nxt_buf_used_size(buf);
47271555Smax.romanov@nginx.com 
47281555Smax.romanov@nginx.com     res = nxt_app_queue_send(port->queue, &msg, sizeof(msg),
47291555Smax.romanov@nginx.com                              req_rpc_data->stream, &notify,
47301555Smax.romanov@nginx.com                              &req_rpc_data->msg_info.tracking_cookie);
47311555Smax.romanov@nginx.com     if (nxt_fast_path(res == NXT_OK)) {
47321555Smax.romanov@nginx.com         if (notify != 0) {
47331555Smax.romanov@nginx.com             (void) nxt_port_socket_write(task, port,
47341555Smax.romanov@nginx.com                                          NXT_PORT_MSG_READ_QUEUE,
47351555Smax.romanov@nginx.com                                          -1, req_rpc_data->stream,
47361555Smax.romanov@nginx.com                                          reply_port->id, NULL);
47371555Smax.romanov@nginx.com 
47381555Smax.romanov@nginx.com         } else {
47391555Smax.romanov@nginx.com             nxt_debug(task, "queue is not empty");
47401555Smax.romanov@nginx.com         }
47411555Smax.romanov@nginx.com 
47421555Smax.romanov@nginx.com     } else {
47431547Smax.romanov@nginx.com         nxt_alert(task, "stream #%uD, app '%V': failed to send app message",
47441547Smax.romanov@nginx.com                   req_rpc_data->stream, &app->name);
47451547Smax.romanov@nginx.com 
47461547Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
47471547Smax.romanov@nginx.com                                NXT_HTTP_INTERNAL_SERVER_ERROR);
47481547Smax.romanov@nginx.com     }
474953Sigor@sysoev.ru }
475053Sigor@sysoev.ru 
475153Sigor@sysoev.ru 
4752743Smax.romanov@nginx.com struct nxt_fields_iter_s {
4753743Smax.romanov@nginx.com     nxt_list_part_t   *part;
4754743Smax.romanov@nginx.com     nxt_http_field_t  *field;
4755743Smax.romanov@nginx.com };
4756743Smax.romanov@nginx.com 
4757743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
4758743Smax.romanov@nginx.com 
4759743Smax.romanov@nginx.com 
4760743Smax.romanov@nginx.com static nxt_http_field_t *
4761743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
4762216Sigor@sysoev.ru {
4763743Smax.romanov@nginx.com     if (part == NULL) {
4764743Smax.romanov@nginx.com         return NULL;
4765216Sigor@sysoev.ru     }
4766216Sigor@sysoev.ru 
4767743Smax.romanov@nginx.com     while (part->nelts == 0) {
4768743Smax.romanov@nginx.com         part = part->next;
4769743Smax.romanov@nginx.com         if (part == NULL) {
4770743Smax.romanov@nginx.com             return NULL;
4771743Smax.romanov@nginx.com         }
4772216Sigor@sysoev.ru     }
4773216Sigor@sysoev.ru 
4774743Smax.romanov@nginx.com     i->part = part;
4775743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
4776743Smax.romanov@nginx.com 
4777743Smax.romanov@nginx.com     return i->field;
4778743Smax.romanov@nginx.com }
4779743Smax.romanov@nginx.com 
4780743Smax.romanov@nginx.com 
4781743Smax.romanov@nginx.com static nxt_http_field_t *
4782743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
4783743Smax.romanov@nginx.com {
4784743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
4785743Smax.romanov@nginx.com }
4786743Smax.romanov@nginx.com 
4787743Smax.romanov@nginx.com 
4788743Smax.romanov@nginx.com static nxt_http_field_t *
4789743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
4790743Smax.romanov@nginx.com {
4791743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
4792743Smax.romanov@nginx.com 
4793743Smax.romanov@nginx.com     end += i->part->nelts;
4794743Smax.romanov@nginx.com     i->field++;
4795743Smax.romanov@nginx.com 
4796743Smax.romanov@nginx.com     if (i->field < end) {
4797743Smax.romanov@nginx.com         return i->field;
4798216Sigor@sysoev.ru     }
4799216Sigor@sysoev.ru 
4800743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
4801216Sigor@sysoev.ru }
4802216Sigor@sysoev.ru 
4803216Sigor@sysoev.ru 
4804743Smax.romanov@nginx.com static nxt_buf_t *
48051007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
48061547Smax.romanov@nginx.com     nxt_app_t *app, const nxt_str_t *prefix)
4807216Sigor@sysoev.ru {
48081007Salexander.borisov@nginx.com     void                *target_pos, *query_pos;
48091007Salexander.borisov@nginx.com     u_char              *pos, *end, *p, c;
48101007Salexander.borisov@nginx.com     size_t              fields_count, req_size, size, free_size;
48111007Salexander.borisov@nginx.com     size_t              copy_size;
48121007Salexander.borisov@nginx.com     nxt_off_t           content_length;
48131007Salexander.borisov@nginx.com     nxt_buf_t           *b, *buf, *out, **tail;
48141007Salexander.borisov@nginx.com     nxt_http_field_t    *field, *dup;
48151007Salexander.borisov@nginx.com     nxt_unit_field_t    *dst_field;
48161007Salexander.borisov@nginx.com     nxt_fields_iter_t   iter, dup_iter;
48171007Salexander.borisov@nginx.com     nxt_unit_request_t  *req;
4818216Sigor@sysoev.ru 
4819743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
48201007Salexander.borisov@nginx.com                + r->method->length + 1
48211007Salexander.borisov@nginx.com                + r->version.length + 1
48221007Salexander.borisov@nginx.com                + r->remote->length + 1
48231007Salexander.borisov@nginx.com                + r->local->length + 1
48241007Salexander.borisov@nginx.com                + r->server_name.length + 1
48251007Salexander.borisov@nginx.com                + r->target.length + 1
48261007Salexander.borisov@nginx.com                + (r->path->start != r->target.start ? r->path->length + 1 : 0);
48271007Salexander.borisov@nginx.com 
48281007Salexander.borisov@nginx.com     content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
4829743Smax.romanov@nginx.com     fields_count = 0;
4830743Smax.romanov@nginx.com 
48311007Salexander.borisov@nginx.com     nxt_list_each(field, r->fields) {
4832743Smax.romanov@nginx.com         fields_count++;
4833743Smax.romanov@nginx.com 
4834743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
4835743Smax.romanov@nginx.com                     + field->value_length + 1;
4836743Smax.romanov@nginx.com     } nxt_list_loop;
4837743Smax.romanov@nginx.com 
4838743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
4839743Smax.romanov@nginx.com 
4840743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
4841743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
4842743Smax.romanov@nginx.com                   (int) req_size);
4843743Smax.romanov@nginx.com 
4844743Smax.romanov@nginx.com         return NULL;
4845743Smax.romanov@nginx.com     }
4846743Smax.romanov@nginx.com 
48471547Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, &app->outgoing,
48481007Salexander.borisov@nginx.com               nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
4849743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
4850743Smax.romanov@nginx.com         return NULL;
4851743Smax.romanov@nginx.com     }
4852743Smax.romanov@nginx.com 
4853743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
4854743Smax.romanov@nginx.com     out->mem.free += req_size;
4855743Smax.romanov@nginx.com 
48561473Svbart@nginx.com     req->app_target = r->app_target;
48571473Svbart@nginx.com 
48581007Salexander.borisov@nginx.com     req->content_length = content_length;
4859743Smax.romanov@nginx.com 
4860743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
4861743Smax.romanov@nginx.com 
4862743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
4863743Smax.romanov@nginx.com 
48641007Salexander.borisov@nginx.com     req->method_length = r->method->length;
4865743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
48661007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->method->start, r->method->length);
4867743Smax.romanov@nginx.com     *p++ = '\0';
4868743Smax.romanov@nginx.com 
48691007Salexander.borisov@nginx.com     req->version_length = r->version.length;
4870743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
48711007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->version.start, r->version.length);
4872743Smax.romanov@nginx.com     *p++ = '\0';
4873743Smax.romanov@nginx.com 
48741007Salexander.borisov@nginx.com     req->remote_length = r->remote->address_length;
4875743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
48761007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
48771007Salexander.borisov@nginx.com                    r->remote->address_length);
4878743Smax.romanov@nginx.com     *p++ = '\0';
4879743Smax.romanov@nginx.com 
48801007Salexander.borisov@nginx.com     req->local_length = r->local->address_length;
4881743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
48821007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
4883743Smax.romanov@nginx.com     *p++ = '\0';
4884743Smax.romanov@nginx.com 
48851011Smax.romanov@nginx.com     req->tls = (r->tls != NULL);
48861131Smax.romanov@nginx.com     req->websocket_handshake = r->websocket_handshake;
48871011Smax.romanov@nginx.com 
48881007Salexander.borisov@nginx.com     req->server_name_length = r->server_name.length;
4889967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
48901007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
4891967Svbart@nginx.com     *p++ = '\0';
4892967Svbart@nginx.com 
4893743Smax.romanov@nginx.com     target_pos = p;
48941007Salexander.borisov@nginx.com     req->target_length = (uint32_t) r->target.length;
4895743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
48961007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->target.start, r->target.length);
4897743Smax.romanov@nginx.com     *p++ = '\0';
4898743Smax.romanov@nginx.com 
48991007Salexander.borisov@nginx.com     req->path_length = (uint32_t) r->path->length;
49001007Salexander.borisov@nginx.com     if (r->path->start == r->target.start) {
4901743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
4902277Sigor@sysoev.ru 
4903216Sigor@sysoev.ru     } else {
4904743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
49051007Salexander.borisov@nginx.com         p = nxt_cpymem(p, r->path->start, r->path->length);
4906743Smax.romanov@nginx.com         *p++ = '\0';
4907305Smax.romanov@nginx.com     }
4908216Sigor@sysoev.ru 
49091007Salexander.borisov@nginx.com     req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
49101007Salexander.borisov@nginx.com     if (r->args != NULL && r->args->start != NULL) {
4911743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
49121007Salexander.borisov@nginx.com                                    r->args->start - r->target.start);
4913743Smax.romanov@nginx.com 
4914743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
4915277Sigor@sysoev.ru 
4916216Sigor@sysoev.ru     } else {
4917743Smax.romanov@nginx.com         req->query.offset = 0;
4918216Sigor@sysoev.ru     }
4919216Sigor@sysoev.ru 
4920743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
4921743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
4922743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
4923743Smax.romanov@nginx.com 
4924743Smax.romanov@nginx.com     dst_field = req->fields;
4925743Smax.romanov@nginx.com 
49261007Salexander.borisov@nginx.com     for (field = nxt_fields_first(r->fields, &iter);
4927743Smax.romanov@nginx.com          field != NULL;
4928743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
4929743Smax.romanov@nginx.com     {
4930743Smax.romanov@nginx.com         if (field->skip) {
4931743Smax.romanov@nginx.com             continue;
4932743Smax.romanov@nginx.com         }
4933743Smax.romanov@nginx.com 
4934743Smax.romanov@nginx.com         dst_field->hash = field->hash;
4935743Smax.romanov@nginx.com         dst_field->skip = 0;
4936743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
4937743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
4938743Smax.romanov@nginx.com 
49391007Salexander.borisov@nginx.com         if (field == r->content_length) {
4940743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
4941743Smax.romanov@nginx.com 
49421007Salexander.borisov@nginx.com         } else if (field == r->content_type) {
4943743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
4944743Smax.romanov@nginx.com 
49451007Salexander.borisov@nginx.com         } else if (field == r->cookie) {
4946743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
4947743Smax.romanov@nginx.com         }
4948743Smax.romanov@nginx.com 
4949743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
4950743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
4951743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
4952743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
4953743Smax.romanov@nginx.com 
4954743Smax.romanov@nginx.com         if (prefix->length != 0) {
4955743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4956743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
4957743Smax.romanov@nginx.com 
4958743Smax.romanov@nginx.com             end = field->name + field->name_length;
4959743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
4960743Smax.romanov@nginx.com                 c = *pos;
4961743Smax.romanov@nginx.com 
4962743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
4963743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
4964743Smax.romanov@nginx.com                     continue;
4965743Smax.romanov@nginx.com                 }
4966743Smax.romanov@nginx.com 
4967743Smax.romanov@nginx.com                 if (c == '-') {
4968743Smax.romanov@nginx.com                     *p++ = '_';
4969743Smax.romanov@nginx.com                     continue;
4970743Smax.romanov@nginx.com                 }
4971743Smax.romanov@nginx.com 
4972743Smax.romanov@nginx.com                 *p++ = c;
4973743Smax.romanov@nginx.com             }
4974743Smax.romanov@nginx.com 
4975743Smax.romanov@nginx.com         } else {
4976743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
4977743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
4978743Smax.romanov@nginx.com         }
4979743Smax.romanov@nginx.com 
4980743Smax.romanov@nginx.com         *p++ = '\0';
4981743Smax.romanov@nginx.com 
4982743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
4983743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
4984743Smax.romanov@nginx.com 
4985743Smax.romanov@nginx.com         if (prefix->length != 0) {
4986743Smax.romanov@nginx.com             dup_iter = iter;
4987743Smax.romanov@nginx.com 
4988743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
4989743Smax.romanov@nginx.com                  dup != NULL;
4990743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
4991743Smax.romanov@nginx.com             {
4992743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
4993743Smax.romanov@nginx.com                     || dup->skip
4994743Smax.romanov@nginx.com                     || dup->hash != field->hash
4995743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
4996743Smax.romanov@nginx.com                 {
4997743Smax.romanov@nginx.com                     continue;
4998743Smax.romanov@nginx.com                 }
4999743Smax.romanov@nginx.com 
5000743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
5001743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
5002743Smax.romanov@nginx.com 
5003743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
5004743Smax.romanov@nginx.com 
5005743Smax.romanov@nginx.com                 dup->skip = 1;
5006743Smax.romanov@nginx.com             }
5007743Smax.romanov@nginx.com         }
5008743Smax.romanov@nginx.com 
5009743Smax.romanov@nginx.com         *p++ = '\0';
5010743Smax.romanov@nginx.com 
5011743Smax.romanov@nginx.com         dst_field++;
5012743Smax.romanov@nginx.com     }
5013743Smax.romanov@nginx.com 
50141007Salexander.borisov@nginx.com     req->fields_count = (uint32_t) (dst_field - req->fields);
5015743Smax.romanov@nginx.com 
5016743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5017743Smax.romanov@nginx.com 
5018743Smax.romanov@nginx.com     buf = out;
5019743Smax.romanov@nginx.com     tail = &buf->next;
5020216Sigor@sysoev.ru 
50211007Salexander.borisov@nginx.com     for (b = r->body; b != NULL; b = b->next) {
5022743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
5023743Smax.romanov@nginx.com         pos = b->mem.pos;
5024743Smax.romanov@nginx.com 
5025743Smax.romanov@nginx.com         while (size > 0) {
5026743Smax.romanov@nginx.com             if (buf == NULL) {
5027743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5028743Smax.romanov@nginx.com 
50291547Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size);
5030743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
5031743Smax.romanov@nginx.com                     while (out != NULL) {
5032743Smax.romanov@nginx.com                         buf = out->next;
50331269Sigor@sysoev.ru                         out->next = NULL;
5034743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
5035743Smax.romanov@nginx.com                         out = buf;
5036743Smax.romanov@nginx.com                     }
5037743Smax.romanov@nginx.com                     return NULL;
5038743Smax.romanov@nginx.com                 }
5039743Smax.romanov@nginx.com 
5040743Smax.romanov@nginx.com                 *tail = buf;
5041743Smax.romanov@nginx.com                 tail = &buf->next;
5042743Smax.romanov@nginx.com 
5043743Smax.romanov@nginx.com             } else {
5044743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
5045743Smax.romanov@nginx.com                 if (free_size < size
5046743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
5047743Smax.romanov@nginx.com                        == NXT_OK)
5048743Smax.romanov@nginx.com                 {
5049743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
5050743Smax.romanov@nginx.com                 }
5051743Smax.romanov@nginx.com             }
5052743Smax.romanov@nginx.com 
5053743Smax.romanov@nginx.com             if (free_size > 0) {
5054743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
5055743Smax.romanov@nginx.com 
5056743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5057743Smax.romanov@nginx.com 
5058743Smax.romanov@nginx.com                 size -= copy_size;
5059743Smax.romanov@nginx.com                 pos += copy_size;
5060743Smax.romanov@nginx.com 
5061743Smax.romanov@nginx.com                 if (size == 0) {
5062743Smax.romanov@nginx.com                     break;
5063743Smax.romanov@nginx.com                 }
5064743Smax.romanov@nginx.com             }
5065743Smax.romanov@nginx.com 
5066743Smax.romanov@nginx.com             buf = NULL;
5067743Smax.romanov@nginx.com         }
5068216Sigor@sysoev.ru     }
5069216Sigor@sysoev.ru 
5070743Smax.romanov@nginx.com     return out;
5071584Salexander.borisov@nginx.com }
5072584Salexander.borisov@nginx.com 
5073584Salexander.borisov@nginx.com 
507453Sigor@sysoev.ru static void
5075318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5076318Smax.romanov@nginx.com {
5077615Smax.romanov@nginx.com     nxt_timer_t              *timer;
50781007Salexander.borisov@nginx.com     nxt_http_request_t       *r;
50791123Smax.romanov@nginx.com     nxt_request_rpc_data_t   *req_rpc_data;
5080318Smax.romanov@nginx.com 
5081318Smax.romanov@nginx.com     timer = obj;
5082318Smax.romanov@nginx.com 
5083318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
5084318Smax.romanov@nginx.com 
50851007Salexander.borisov@nginx.com     r = nxt_timer_data(timer, nxt_http_request_t, timer);
50861123Smax.romanov@nginx.com     req_rpc_data = r->timer_data;
5087615Smax.romanov@nginx.com 
50881007Salexander.borisov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5089615Smax.romanov@nginx.com 
50901123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
5091318Smax.romanov@nginx.com }
50921007Salexander.borisov@nginx.com 
50931007Salexander.borisov@nginx.com 
50941547Smax.romanov@nginx.com static void
50951547Smax.romanov@nginx.com nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r)
50961007Salexander.borisov@nginx.com {
50971007Salexander.borisov@nginx.com     r->timer.handler = nxt_router_http_request_release;
50981007Salexander.borisov@nginx.com     nxt_timer_add(task->thread->engine, &r->timer, 0);
50991007Salexander.borisov@nginx.com }
51001007Salexander.borisov@nginx.com 
51011007Salexander.borisov@nginx.com 
51021007Salexander.borisov@nginx.com static void
51031007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
51041007Salexander.borisov@nginx.com {
51051007Salexander.borisov@nginx.com     nxt_http_request_t  *r;
51061007Salexander.borisov@nginx.com 
51071547Smax.romanov@nginx.com     nxt_debug(task, "http request pool release");
51081007Salexander.borisov@nginx.com 
51091007Salexander.borisov@nginx.com     r = nxt_timer_data(obj, nxt_http_request_t, timer);
51101007Salexander.borisov@nginx.com 
51111007Salexander.borisov@nginx.com     nxt_mp_release(r->mem_pool);
51121007Salexander.borisov@nginx.com }
51131321Smax.romanov@nginx.com 
51141321Smax.romanov@nginx.com 
51151321Smax.romanov@nginx.com static void
51161321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
51171321Smax.romanov@nginx.com {
51181321Smax.romanov@nginx.com     size_t                   mi;
51191321Smax.romanov@nginx.com     uint32_t                 i;
51201321Smax.romanov@nginx.com     nxt_bool_t               ack;
51211321Smax.romanov@nginx.com     nxt_process_t            *process;
51221321Smax.romanov@nginx.com     nxt_free_map_t           *m;
51231321Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
51241321Smax.romanov@nginx.com 
51251321Smax.romanov@nginx.com     nxt_debug(task, "oosm in %PI", msg->port_msg.pid);
51261321Smax.romanov@nginx.com 
51271321Smax.romanov@nginx.com     process = nxt_runtime_process_find(task->thread->runtime,
51281321Smax.romanov@nginx.com                                        msg->port_msg.pid);
51291321Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
51301321Smax.romanov@nginx.com         return;
51311321Smax.romanov@nginx.com     }
51321321Smax.romanov@nginx.com 
51331321Smax.romanov@nginx.com     ack = 0;
51341321Smax.romanov@nginx.com 
51351321Smax.romanov@nginx.com     /*
51361321Smax.romanov@nginx.com      * To mitigate possible racing condition (when OOSM message received
51371321Smax.romanov@nginx.com      * after some of the memory was already freed), need to try to find
51381321Smax.romanov@nginx.com      * first free segment in shared memory and send ACK if found.
51391321Smax.romanov@nginx.com      */
51401321Smax.romanov@nginx.com 
51411321Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
51421321Smax.romanov@nginx.com 
51431321Smax.romanov@nginx.com     for (i = 0; i < process->incoming.size; i++) {
51441321Smax.romanov@nginx.com         hdr = process->incoming.elts[i].mmap_handler->hdr;
51451321Smax.romanov@nginx.com         m = hdr->free_map;
51461321Smax.romanov@nginx.com 
51471321Smax.romanov@nginx.com         for (mi = 0; mi < MAX_FREE_IDX; mi++) {
51481321Smax.romanov@nginx.com             if (m[mi] != 0) {
51491321Smax.romanov@nginx.com                 ack = 1;
51501321Smax.romanov@nginx.com 
51511321Smax.romanov@nginx.com                 nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA",
51521321Smax.romanov@nginx.com                           i, mi, m[mi]);
51531321Smax.romanov@nginx.com 
51541321Smax.romanov@nginx.com                 break;
51551321Smax.romanov@nginx.com             }
51561321Smax.romanov@nginx.com         }
51571321Smax.romanov@nginx.com     }
51581321Smax.romanov@nginx.com 
51591321Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
51601321Smax.romanov@nginx.com 
51611321Smax.romanov@nginx.com     if (ack) {
51621321Smax.romanov@nginx.com         (void) nxt_port_socket_write(task, msg->port, NXT_PORT_MSG_SHM_ACK,
51631321Smax.romanov@nginx.com                                      -1, 0, 0, NULL);
51641321Smax.romanov@nginx.com     }
51651321Smax.romanov@nginx.com }
51661545Smax.romanov@nginx.com 
51671545Smax.romanov@nginx.com 
51681545Smax.romanov@nginx.com static void
51691546Smax.romanov@nginx.com nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
51701546Smax.romanov@nginx.com {
51711546Smax.romanov@nginx.com     nxt_fd_t                 fd;
51721546Smax.romanov@nginx.com     nxt_port_t               *port;
51731546Smax.romanov@nginx.com     nxt_runtime_t            *rt;
51741546Smax.romanov@nginx.com     nxt_port_mmaps_t         *mmaps;
51751546Smax.romanov@nginx.com     nxt_port_msg_get_mmap_t  *get_mmap_msg;
51761546Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
51771546Smax.romanov@nginx.com 
51781546Smax.romanov@nginx.com     rt = task->thread->runtime;
51791546Smax.romanov@nginx.com 
51801546Smax.romanov@nginx.com     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
51811546Smax.romanov@nginx.com                                  msg->port_msg.reply_port);
51821546Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
51831546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found",
51841546Smax.romanov@nginx.com                   msg->port_msg.pid, msg->port_msg.reply_port);
51851546Smax.romanov@nginx.com 
51861546Smax.romanov@nginx.com         return;
51871546Smax.romanov@nginx.com     }
51881546Smax.romanov@nginx.com 
51891546Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_used_size(msg->buf)
51901546Smax.romanov@nginx.com                       < (int) sizeof(nxt_port_msg_get_mmap_t)))
51911546Smax.romanov@nginx.com     {
51921546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: message buffer too small (%d)",
51931546Smax.romanov@nginx.com                   (int) nxt_buf_used_size(msg->buf));
51941546Smax.romanov@nginx.com 
51951546Smax.romanov@nginx.com         return;
51961546Smax.romanov@nginx.com     }
51971546Smax.romanov@nginx.com 
51981546Smax.romanov@nginx.com     get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos;
51991546Smax.romanov@nginx.com 
52001546Smax.romanov@nginx.com     nxt_assert(port->type == NXT_PROCESS_APP);
52011546Smax.romanov@nginx.com 
52021547Smax.romanov@nginx.com     if (nxt_slow_path(port->app == NULL)) {
52031547Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d",
52041547Smax.romanov@nginx.com                   port->pid, port->id);
52051547Smax.romanov@nginx.com 
52061547Smax.romanov@nginx.com         // FIXME
52071547Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
52081547Smax.romanov@nginx.com                               -1, msg->port_msg.stream, 0, NULL);
52091547Smax.romanov@nginx.com 
52101547Smax.romanov@nginx.com         return;
52111547Smax.romanov@nginx.com     }
52121547Smax.romanov@nginx.com 
52131547Smax.romanov@nginx.com     mmaps = &port->app->outgoing;
52141546Smax.romanov@nginx.com     nxt_thread_mutex_lock(&mmaps->mutex);
52151546Smax.romanov@nginx.com 
52161546Smax.romanov@nginx.com     if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) {
52171546Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&mmaps->mutex);
52181546Smax.romanov@nginx.com 
52191546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)",
52201546Smax.romanov@nginx.com                   (int) get_mmap_msg->id);
52211546Smax.romanov@nginx.com 
52221547Smax.romanov@nginx.com         // FIXME
52231547Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
52241547Smax.romanov@nginx.com                               -1, msg->port_msg.stream, 0, NULL);
52251546Smax.romanov@nginx.com         return;
52261546Smax.romanov@nginx.com     }
52271546Smax.romanov@nginx.com 
52281546Smax.romanov@nginx.com     mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler;
52291546Smax.romanov@nginx.com 
52301546Smax.romanov@nginx.com     fd = mmap_handler->fd;
52311546Smax.romanov@nginx.com 
52321546Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&mmaps->mutex);
52331546Smax.romanov@nginx.com 
52341546Smax.romanov@nginx.com     nxt_debug(task, "get mmap %PI:%d found",
52351546Smax.romanov@nginx.com               msg->port_msg.pid, (int) get_mmap_msg->id);
52361546Smax.romanov@nginx.com 
52371546Smax.romanov@nginx.com     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL);
52381546Smax.romanov@nginx.com }
52391546Smax.romanov@nginx.com 
52401546Smax.romanov@nginx.com 
52411546Smax.romanov@nginx.com static void
52421545Smax.romanov@nginx.com nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
52431545Smax.romanov@nginx.com {
52441545Smax.romanov@nginx.com     nxt_port_t               *port, *reply_port;
52451545Smax.romanov@nginx.com     nxt_runtime_t            *rt;
52461545Smax.romanov@nginx.com     nxt_port_msg_get_port_t  *get_port_msg;
52471545Smax.romanov@nginx.com 
52481545Smax.romanov@nginx.com     rt = task->thread->runtime;
52491545Smax.romanov@nginx.com 
52501545Smax.romanov@nginx.com     reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid,
52511545Smax.romanov@nginx.com                                        msg->port_msg.reply_port);
52521545Smax.romanov@nginx.com     if (nxt_slow_path(reply_port == NULL)) {
52531545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: reply_port %PI:%d not found",
52541545Smax.romanov@nginx.com                   msg->port_msg.pid, msg->port_msg.reply_port);
52551545Smax.romanov@nginx.com 
52561545Smax.romanov@nginx.com         return;
52571545Smax.romanov@nginx.com     }
52581545Smax.romanov@nginx.com 
52591545Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_used_size(msg->buf)
52601545Smax.romanov@nginx.com                       < (int) sizeof(nxt_port_msg_get_port_t)))
52611545Smax.romanov@nginx.com     {
52621545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: message buffer too small (%d)",
52631545Smax.romanov@nginx.com                   (int) nxt_buf_used_size(msg->buf));
52641545Smax.romanov@nginx.com 
52651545Smax.romanov@nginx.com         return;
52661545Smax.romanov@nginx.com     }
52671545Smax.romanov@nginx.com 
52681545Smax.romanov@nginx.com     get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos;
52691545Smax.romanov@nginx.com 
52701545Smax.romanov@nginx.com     port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id);
52711545Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
52721545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: port %PI:%d not found",
52731545Smax.romanov@nginx.com                   get_port_msg->pid, get_port_msg->id);
52741545Smax.romanov@nginx.com 
52751545Smax.romanov@nginx.com         return;
52761545Smax.romanov@nginx.com     }
52771545Smax.romanov@nginx.com 
52781545Smax.romanov@nginx.com     nxt_debug(task, "get port %PI:%d found", get_port_msg->pid,
52791545Smax.romanov@nginx.com               get_port_msg->id);
52801545Smax.romanov@nginx.com 
52811545Smax.romanov@nginx.com     (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream);
52821545Smax.romanov@nginx.com }
5283