xref: /unit/src/nxt_router.c (revision 1998)
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 
211926Smax.romanov@nginx.com #define NXT_SHARED_PORT_ID  0xFFFFu
221926Smax.romanov@nginx.com 
23115Sigor@sysoev.ru typedef struct {
24318Smax.romanov@nginx.com     nxt_str_t         type;
25507Smax.romanov@nginx.com     uint32_t          processes;
26507Smax.romanov@nginx.com     uint32_t          max_processes;
27507Smax.romanov@nginx.com     uint32_t          spare_processes;
28318Smax.romanov@nginx.com     nxt_msec_t        timeout;
29507Smax.romanov@nginx.com     nxt_msec_t        idle_timeout;
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 {
451885Sa.suvorov@f5.com     nxt_str_t               name;
461885Sa.suvorov@f5.com     nxt_socket_conf_t       *socket_conf;
471885Sa.suvorov@f5.com     nxt_router_temp_conf_t  *temp_conf;
481920Sa.suvorov@f5.com     nxt_tls_init_t          *tls_init;
491885Sa.suvorov@f5.com     nxt_bool_t              last;
50774Svbart@nginx.com 
511920Sa.suvorov@f5.com     nxt_queue_link_t        link;  /* for nxt_socket_conf_t.tls */
52774Svbart@nginx.com } nxt_router_tlssock_t;
53774Svbart@nginx.com 
54774Svbart@nginx.com #endif
55774Svbart@nginx.com 
56774Svbart@nginx.com 
57198Sigor@sysoev.ru typedef struct {
581828Sa.suvorov@f5.com     nxt_str_t               *name;
59198Sigor@sysoev.ru     nxt_socket_conf_t       *socket_conf;
60198Sigor@sysoev.ru     nxt_router_temp_conf_t  *temp_conf;
611828Sa.suvorov@f5.com     nxt_bool_t              last;
62198Sigor@sysoev.ru } nxt_socket_rpc_t;
63198Sigor@sysoev.ru 
64198Sigor@sysoev.ru 
65507Smax.romanov@nginx.com typedef struct {
66507Smax.romanov@nginx.com     nxt_app_t               *app;
67507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *temp_conf;
68*1998St.nateldemoura@f5.com     uint8_t                 proto;  /* 1 bit */
69507Smax.romanov@nginx.com } nxt_app_rpc_t;
70507Smax.romanov@nginx.com 
71507Smax.romanov@nginx.com 
721926Smax.romanov@nginx.com typedef struct {
731926Smax.romanov@nginx.com     nxt_app_joint_t         *app_joint;
741926Smax.romanov@nginx.com     uint32_t                generation;
75*1998St.nateldemoura@f5.com     uint8_t                 proto;  /* 1 bit */
761926Smax.romanov@nginx.com } nxt_app_joint_rpc_t;
771926Smax.romanov@nginx.com 
781926Smax.romanov@nginx.com 
791488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process,
801488St.nateldemoura@f5.com     nxt_mp_t *mp);
811488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data);
82662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task,
83662Smax.romanov@nginx.com     nxt_port_t *controller_port);
84662Smax.romanov@nginx.com 
85507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
86425Smax.romanov@nginx.com 
871552Smax.romanov@nginx.com static void nxt_router_new_port_handler(nxt_task_t *task,
881552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
891552Smax.romanov@nginx.com static void nxt_router_conf_data_handler(nxt_task_t *task,
901552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
911926Smax.romanov@nginx.com static void nxt_router_app_restart_handler(nxt_task_t *task,
921926Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
931552Smax.romanov@nginx.com static void nxt_router_remove_pid_handler(nxt_task_t *task,
941552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
951552Smax.romanov@nginx.com static void nxt_router_access_log_reopen_handler(nxt_task_t *task,
961552Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
971552Smax.romanov@nginx.com 
98139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
99198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
100198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task,
101139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
102139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task,
103139Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
104139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task,
105193Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
10653Sigor@sysoev.ru 
107115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
108115Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
1091183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
1101183Svbart@nginx.com     nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
1111936So.canty@f5.com static nxt_int_t nxt_router_conf_process_client_ip(nxt_task_t *task,
1121936So.canty@f5.com     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf,
1131936So.canty@f5.com     nxt_conf_value_t *conf);
1141563Svbart@nginx.com 
115133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
1161563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
1171563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf,
1181563Svbart@nginx.com     nxt_app_t *app);
1191563Svbart@nginx.com static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf,
1201563Svbart@nginx.com     nxt_str_t *name);
1211563Svbart@nginx.com static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf,
1221563Svbart@nginx.com     int i);
1231563Svbart@nginx.com 
1241555Smax.romanov@nginx.com static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task,
1251555Smax.romanov@nginx.com     nxt_port_t *port);
1261555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task,
1271555Smax.romanov@nginx.com     nxt_port_t *port);
1281555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task,
1291555Smax.romanov@nginx.com     nxt_port_t *port, nxt_fd_t fd);
130198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
131198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
132198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task,
133198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
134198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task,
135198Sigor@sysoev.ru     nxt_port_recv_msg_t *msg, void *data);
136774Svbart@nginx.com #if (NXT_TLS)
137774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task,
138774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
1391828Sa.suvorov@f5.com static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
1401920Sa.suvorov@f5.com     nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init,
1411920Sa.suvorov@f5.com     nxt_bool_t last);
142774Svbart@nginx.com #endif
143507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task,
144507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
145507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task,
146507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
147507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task,
148507Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
149359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
150359Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
151359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
152359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
15353Sigor@sysoev.ru 
15453Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
15553Sigor@sysoev.ru     nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
15653Sigor@sysoev.ru     const nxt_event_interface_t *interface);
157115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
158115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
159115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
160115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
161115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
162115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
163154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
164154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
165154Sigor@sysoev.ru     nxt_work_handler_t handler);
166313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
167313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf);
168139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
169139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
17053Sigor@sysoev.ru 
17153Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
17253Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
17353Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
17453Sigor@sysoev.ru     nxt_event_engine_t *engine);
175343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
176133Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
17753Sigor@sysoev.ru 
178315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router,
179315Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf);
180315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine,
181315Sigor@sysoev.ru     nxt_work_t *jobs);
18253Sigor@sysoev.ru 
18353Sigor@sysoev.ru static void nxt_router_thread_start(void *data);
1841545Smax.romanov@nginx.com static void nxt_router_rt_add_port(nxt_task_t *task, void *obj,
1851545Smax.romanov@nginx.com     void *data);
18653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
18753Sigor@sysoev.ru     void *data);
18853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
18953Sigor@sysoev.ru     void *data);
19053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
19153Sigor@sysoev.ru     void *data);
192313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
193313Sigor@sysoev.ru     void *data);
19453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
19553Sigor@sysoev.ru     void *data);
19653Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
19753Sigor@sysoev.ru     void *data);
1981547Smax.romanov@nginx.com static void nxt_router_req_headers_ack_handler(nxt_task_t *task,
1991547Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data);
200359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task,
201359Sigor@sysoev.ru     nxt_socket_conf_t *skcf);
20253Sigor@sysoev.ru 
203630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task,
204630Svbart@nginx.com     nxt_http_request_t *r, nxt_router_access_log_t *access_log);
205630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
206630Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
207630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task,
208630Svbart@nginx.com     nxt_router_temp_conf_t *tmcf);
209630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task,
210630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
211630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task,
212630Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
213630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task,
214630Svbart@nginx.com     nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
215651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
216651Svbart@nginx.com     void *data);
217631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
218631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
219631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task,
220631Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
221630Svbart@nginx.com 
222343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task,
223343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
2241547Smax.romanov@nginx.com static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task,
2251547Smax.romanov@nginx.com     nxt_port_t *app_port);
226343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task,
227343Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
228343Smax.romanov@nginx.com 
2291563Svbart@nginx.com static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i);
230753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
2311123Smax.romanov@nginx.com 
2321978Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app,
2331978Smax.romanov@nginx.com     nxt_port_t *port, nxt_apr_action_t action);
2341547Smax.romanov@nginx.com static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
2351547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data);
2361561Smax.romanov@nginx.com static void nxt_router_http_request_error(nxt_task_t *task, void *obj,
2371561Smax.romanov@nginx.com     void *data);
2381547Smax.romanov@nginx.com static void nxt_router_http_request_done(nxt_task_t *task, void *obj,
2391547Smax.romanov@nginx.com     void *data);
240141Smax.romanov@nginx.com 
241425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task,
2421547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data);
2431007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
2441547Smax.romanov@nginx.com     nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix);
245510Salexander.borisov@nginx.com 
246318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
247507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
248507Smax.romanov@nginx.com     void *data);
249507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
250507Smax.romanov@nginx.com     void *data);
251753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
252507Smax.romanov@nginx.com     void *data);
253753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
254431Sigor@sysoev.ru 
255431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state;
256431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
257141Smax.romanov@nginx.com 
258753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task,
259753Smax.romanov@nginx.com     nxt_app_joint_t *app_joint, int i);
260753Smax.romanov@nginx.com 
2611547Smax.romanov@nginx.com static void nxt_router_http_request_release_post(nxt_task_t *task,
2621007Salexander.borisov@nginx.com     nxt_http_request_t *r);
2631007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
2641007Salexander.borisov@nginx.com     void *data);
2651321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
2661545Smax.romanov@nginx.com static void nxt_router_get_port_handler(nxt_task_t *task,
2671545Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
2681546Smax.romanov@nginx.com static void nxt_router_get_mmap_handler(nxt_task_t *task,
2691546Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
2701007Salexander.borisov@nginx.com 
2711149Smax.romanov@nginx.com extern const nxt_http_request_state_t  nxt_http_websocket;
2721131Smax.romanov@nginx.com 
273119Smax.romanov@nginx.com static nxt_router_t  *nxt_router;
27420Sigor@sysoev.ru 
275743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_");
276743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string("");
277743Smax.romanov@nginx.com 
278743Smax.romanov@nginx.com static const nxt_str_t  *nxt_app_msg_prefix[] = {
279804Svbart@nginx.com     &empty_prefix,
2801594Smax.romanov@nginx.com     &empty_prefix,
281743Smax.romanov@nginx.com     &http_prefix,
282743Smax.romanov@nginx.com     &http_prefix,
283743Smax.romanov@nginx.com     &http_prefix,
284977Smax.romanov@gmail.com     &empty_prefix,
285216Sigor@sysoev.ru };
286216Sigor@sysoev.ru 
287216Sigor@sysoev.ru 
2881488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_router_process_port_handlers = {
2891488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
290662Smax.romanov@nginx.com     .new_port     = nxt_router_new_port_handler,
2911545Smax.romanov@nginx.com     .get_port     = nxt_router_get_port_handler,
292662Smax.romanov@nginx.com     .change_file  = nxt_port_change_log_file_handler,
293662Smax.romanov@nginx.com     .mmap         = nxt_port_mmap_handler,
2941546Smax.romanov@nginx.com     .get_mmap     = nxt_router_get_mmap_handler,
295662Smax.romanov@nginx.com     .data         = nxt_router_conf_data_handler,
2961926Smax.romanov@nginx.com     .app_restart  = nxt_router_app_restart_handler,
297662Smax.romanov@nginx.com     .remove_pid   = nxt_router_remove_pid_handler,
298662Smax.romanov@nginx.com     .access_log   = nxt_router_access_log_reopen_handler,
299662Smax.romanov@nginx.com     .rpc_ready    = nxt_port_rpc_handler,
300662Smax.romanov@nginx.com     .rpc_error    = nxt_port_rpc_handler,
3011321Smax.romanov@nginx.com     .oosm         = nxt_router_oosm_handler,
302662Smax.romanov@nginx.com };
303662Smax.romanov@nginx.com 
304662Smax.romanov@nginx.com 
3051488St.nateldemoura@f5.com const nxt_process_init_t  nxt_router_process = {
3061488St.nateldemoura@f5.com     .name           = "router",
3071488St.nateldemoura@f5.com     .type           = NXT_PROCESS_ROUTER,
3081488St.nateldemoura@f5.com     .prefork        = nxt_router_prefork,
3091488St.nateldemoura@f5.com     .restart        = 1,
3101488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
3111488St.nateldemoura@f5.com     .start          = nxt_router_start,
3121488St.nateldemoura@f5.com     .port_handlers  = &nxt_router_process_port_handlers,
3131488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
3141488St.nateldemoura@f5.com };
3151488St.nateldemoura@f5.com 
3161488St.nateldemoura@f5.com 
3171509Sigor@sysoev.ru /* Queues of nxt_socket_conf_t */
3181509Sigor@sysoev.ru nxt_queue_t  creating_sockets;
3191509Sigor@sysoev.ru nxt_queue_t  pending_sockets;
3201509Sigor@sysoev.ru nxt_queue_t  updating_sockets;
3211509Sigor@sysoev.ru nxt_queue_t  keeping_sockets;
3221509Sigor@sysoev.ru nxt_queue_t  deleting_sockets;
3231509Sigor@sysoev.ru 
3241509Sigor@sysoev.ru 
3251488St.nateldemoura@f5.com static nxt_int_t
3261488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
3271488St.nateldemoura@f5.com {
3281488St.nateldemoura@f5.com     nxt_runtime_stop_app_processes(task, task->thread->runtime);
3291488St.nateldemoura@f5.com 
3301488St.nateldemoura@f5.com     return NXT_OK;
3311488St.nateldemoura@f5.com }
3321488St.nateldemoura@f5.com 
3331488St.nateldemoura@f5.com 
3341488St.nateldemoura@f5.com static nxt_int_t
3351488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data)
33620Sigor@sysoev.ru {
337141Smax.romanov@nginx.com     nxt_int_t      ret;
338662Smax.romanov@nginx.com     nxt_port_t     *controller_port;
339141Smax.romanov@nginx.com     nxt_router_t   *router;
340141Smax.romanov@nginx.com     nxt_runtime_t  *rt;
341141Smax.romanov@nginx.com 
342141Smax.romanov@nginx.com     rt = task->thread->runtime;
34353Sigor@sysoev.ru 
3441488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "router started");
3451488St.nateldemoura@f5.com 
346771Sigor@sysoev.ru #if (NXT_TLS)
347771Sigor@sysoev.ru     rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
348771Sigor@sysoev.ru     if (nxt_slow_path(rt->tls == NULL)) {
349771Sigor@sysoev.ru         return NXT_ERROR;
350771Sigor@sysoev.ru     }
351771Sigor@sysoev.ru 
352771Sigor@sysoev.ru     ret = rt->tls->library_init(task);
353771Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
354771Sigor@sysoev.ru         return ret;
355771Sigor@sysoev.ru     }
356771Sigor@sysoev.ru #endif
357771Sigor@sysoev.ru 
3581459Smax.romanov@nginx.com     ret = nxt_http_init(task);
35988Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
36088Smax.romanov@nginx.com         return ret;
36188Smax.romanov@nginx.com     }
36288Smax.romanov@nginx.com 
36353Sigor@sysoev.ru     router = nxt_zalloc(sizeof(nxt_router_t));
36453Sigor@sysoev.ru     if (nxt_slow_path(router == NULL)) {
36553Sigor@sysoev.ru         return NXT_ERROR;
36653Sigor@sysoev.ru     }
36753Sigor@sysoev.ru 
36853Sigor@sysoev.ru     nxt_queue_init(&router->engines);
36953Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
370133Sigor@sysoev.ru     nxt_queue_init(&router->apps);
37153Sigor@sysoev.ru 
372119Smax.romanov@nginx.com     nxt_router = router;
373119Smax.romanov@nginx.com 
374662Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
375662Smax.romanov@nginx.com     if (controller_port != NULL) {
376662Smax.romanov@nginx.com         nxt_router_greet_controller(task, controller_port);
377662Smax.romanov@nginx.com     }
378662Smax.romanov@nginx.com 
379115Sigor@sysoev.ru     return NXT_OK;
380115Sigor@sysoev.ru }
381115Sigor@sysoev.ru 
382115Sigor@sysoev.ru 
383343Smax.romanov@nginx.com static void
384662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
385662Smax.romanov@nginx.com {
386662Smax.romanov@nginx.com     nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
387662Smax.romanov@nginx.com                           -1, 0, 0, NULL);
388662Smax.romanov@nginx.com }
389662Smax.romanov@nginx.com 
390662Smax.romanov@nginx.com 
391662Smax.romanov@nginx.com static void
392507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
393507Smax.romanov@nginx.com     void *data)
394167Smax.romanov@nginx.com {
3951926Smax.romanov@nginx.com     size_t               size;
3961926Smax.romanov@nginx.com     uint32_t             stream;
3971926Smax.romanov@nginx.com     nxt_int_t            ret;
3981926Smax.romanov@nginx.com     nxt_app_t            *app;
3991926Smax.romanov@nginx.com     nxt_buf_t            *b;
400*1998St.nateldemoura@f5.com     nxt_port_t           *dport;
4011926Smax.romanov@nginx.com     nxt_runtime_t        *rt;
4021926Smax.romanov@nginx.com     nxt_app_joint_rpc_t  *app_joint_rpc;
403343Smax.romanov@nginx.com 
404343Smax.romanov@nginx.com     app = data;
405167Smax.romanov@nginx.com 
406*1998St.nateldemoura@f5.com     nxt_thread_mutex_lock(&app->mutex);
407*1998St.nateldemoura@f5.com 
408*1998St.nateldemoura@f5.com     dport = app->proto_port;
409*1998St.nateldemoura@f5.com 
410*1998St.nateldemoura@f5.com     nxt_thread_mutex_unlock(&app->mutex);
411*1998St.nateldemoura@f5.com 
412*1998St.nateldemoura@f5.com     if (dport != NULL) {
413*1998St.nateldemoura@f5.com         nxt_debug(task, "app '%V' %p start process", &app->name, app);
414*1998St.nateldemoura@f5.com 
415*1998St.nateldemoura@f5.com         b = NULL;
416*1998St.nateldemoura@f5.com 
417*1998St.nateldemoura@f5.com     } else {
418*1998St.nateldemoura@f5.com         if (app->proto_port_requests > 0) {
419*1998St.nateldemoura@f5.com             nxt_debug(task, "app '%V' %p wait for prototype process",
420*1998St.nateldemoura@f5.com                       &app->name, app);
421*1998St.nateldemoura@f5.com 
422*1998St.nateldemoura@f5.com             app->proto_port_requests++;
423*1998St.nateldemoura@f5.com 
424*1998St.nateldemoura@f5.com             goto skip;
425*1998St.nateldemoura@f5.com         }
426*1998St.nateldemoura@f5.com 
427*1998St.nateldemoura@f5.com         nxt_debug(task, "app '%V' %p start prototype process", &app->name, app);
428*1998St.nateldemoura@f5.com 
429*1998St.nateldemoura@f5.com         rt = task->thread->runtime;
430*1998St.nateldemoura@f5.com         dport = rt->port_by_type[NXT_PROCESS_MAIN];
431*1998St.nateldemoura@f5.com 
432*1998St.nateldemoura@f5.com         size = app->name.length + 1 + app->conf.length;
433*1998St.nateldemoura@f5.com 
434*1998St.nateldemoura@f5.com         b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, size, 0);
435*1998St.nateldemoura@f5.com         if (nxt_slow_path(b == NULL)) {
436*1998St.nateldemoura@f5.com             goto failed;
437*1998St.nateldemoura@f5.com         }
438*1998St.nateldemoura@f5.com 
439*1998St.nateldemoura@f5.com         nxt_buf_cpystr(b, &app->name);
440*1998St.nateldemoura@f5.com         *b->mem.free++ = '\0';
441*1998St.nateldemoura@f5.com         nxt_buf_cpystr(b, &app->conf);
442*1998St.nateldemoura@f5.com     }
443343Smax.romanov@nginx.com 
4441926Smax.romanov@nginx.com     app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port,
4451926Smax.romanov@nginx.com                                                      nxt_router_app_port_ready,
4461926Smax.romanov@nginx.com                                                      nxt_router_app_port_error,
4471926Smax.romanov@nginx.com                                                    sizeof(nxt_app_joint_rpc_t));
4481926Smax.romanov@nginx.com     if (nxt_slow_path(app_joint_rpc == NULL)) {
449343Smax.romanov@nginx.com         goto failed;
450343Smax.romanov@nginx.com     }
451343Smax.romanov@nginx.com 
4521926Smax.romanov@nginx.com     stream = nxt_port_rpc_ex_stream(app_joint_rpc);
4531926Smax.romanov@nginx.com 
454*1998St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, dport, NXT_PORT_MSG_START_PROCESS,
4551488St.nateldemoura@f5.com                                 -1, stream, port->id, b);
456648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
457648Svbart@nginx.com         nxt_port_rpc_cancel(task, port, stream);
458753Smax.romanov@nginx.com 
459648Svbart@nginx.com         goto failed;
460648Svbart@nginx.com     }
461343Smax.romanov@nginx.com 
4621926Smax.romanov@nginx.com     app_joint_rpc->app_joint = app->joint;
4631926Smax.romanov@nginx.com     app_joint_rpc->generation = app->generation;
464*1998St.nateldemoura@f5.com     app_joint_rpc->proto = (b != NULL);
465*1998St.nateldemoura@f5.com 
466*1998St.nateldemoura@f5.com     if (b != NULL) {
467*1998St.nateldemoura@f5.com         app->proto_port_requests++;
468*1998St.nateldemoura@f5.com 
469*1998St.nateldemoura@f5.com         b = NULL;
470*1998St.nateldemoura@f5.com     }
4711926Smax.romanov@nginx.com 
4721926Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app->joint, 1);
4731926Smax.romanov@nginx.com 
474343Smax.romanov@nginx.com failed:
475343Smax.romanov@nginx.com 
476648Svbart@nginx.com     if (b != NULL) {
477*1998St.nateldemoura@f5.com         nxt_mp_free(b->data, b);
478*1998St.nateldemoura@f5.com     }
479*1998St.nateldemoura@f5.com 
480*1998St.nateldemoura@f5.com skip:
481343Smax.romanov@nginx.com 
482343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
483167Smax.romanov@nginx.com }
484167Smax.romanov@nginx.com 
485167Smax.romanov@nginx.com 
486753Smax.romanov@nginx.com static void
487753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
488753Smax.romanov@nginx.com {
489753Smax.romanov@nginx.com     app_joint->use_count += i;
490753Smax.romanov@nginx.com 
491753Smax.romanov@nginx.com     if (app_joint->use_count == 0) {
492753Smax.romanov@nginx.com         nxt_assert(app_joint->app == NULL);
493753Smax.romanov@nginx.com 
494753Smax.romanov@nginx.com         nxt_free(app_joint);
495753Smax.romanov@nginx.com     }
496753Smax.romanov@nginx.com }
497753Smax.romanov@nginx.com 
498753Smax.romanov@nginx.com 
499343Smax.romanov@nginx.com static nxt_int_t
500507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
501141Smax.romanov@nginx.com {
502343Smax.romanov@nginx.com     nxt_int_t      res;
503343Smax.romanov@nginx.com     nxt_port_t     *router_port;
504343Smax.romanov@nginx.com     nxt_runtime_t  *rt;
505343Smax.romanov@nginx.com 
5061549Smax.romanov@nginx.com     nxt_debug(task, "app '%V' start process", &app->name);
5071549Smax.romanov@nginx.com 
508343Smax.romanov@nginx.com     rt = task->thread->runtime;
509343Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
510343Smax.romanov@nginx.com 
511343Smax.romanov@nginx.com     nxt_router_app_use(task, app, 1);
512343Smax.romanov@nginx.com 
513507Smax.romanov@nginx.com     res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
514343Smax.romanov@nginx.com                         app);
515343Smax.romanov@nginx.com 
516343Smax.romanov@nginx.com     if (res == NXT_OK) {
517343Smax.romanov@nginx.com         return res;
518318Smax.romanov@nginx.com     }
519318Smax.romanov@nginx.com 
520343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
521343Smax.romanov@nginx.com 
522507Smax.romanov@nginx.com     app->pending_processes--;
523343Smax.romanov@nginx.com 
524343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
525343Smax.romanov@nginx.com 
526343Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
527343Smax.romanov@nginx.com 
528343Smax.romanov@nginx.com     return NXT_ERROR;
529318Smax.romanov@nginx.com }
530318Smax.romanov@nginx.com 
531318Smax.romanov@nginx.com 
532423Smax.romanov@nginx.com nxt_inline nxt_bool_t
5331555Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
534423Smax.romanov@nginx.com {
5351555Smax.romanov@nginx.com     nxt_buf_t       *b, *next;
5361555Smax.romanov@nginx.com     nxt_bool_t      cancelled;
5371926Smax.romanov@nginx.com     nxt_port_t      *app_port;
5381555Smax.romanov@nginx.com     nxt_msg_info_t  *msg_info;
5391555Smax.romanov@nginx.com 
5401555Smax.romanov@nginx.com     msg_info = &req_rpc_data->msg_info;
541423Smax.romanov@nginx.com 
542423Smax.romanov@nginx.com     if (msg_info->buf == NULL) {
543423Smax.romanov@nginx.com         return 0;
544423Smax.romanov@nginx.com     }
545423Smax.romanov@nginx.com 
5461926Smax.romanov@nginx.com     app_port = req_rpc_data->app_port;
5471926Smax.romanov@nginx.com 
5481926Smax.romanov@nginx.com     if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) {
5491926Smax.romanov@nginx.com         cancelled = nxt_app_queue_cancel(app_port->queue,
5501926Smax.romanov@nginx.com                                          msg_info->tracking_cookie,
5511926Smax.romanov@nginx.com                                          req_rpc_data->stream);
5521926Smax.romanov@nginx.com 
5531926Smax.romanov@nginx.com         if (cancelled) {
5541926Smax.romanov@nginx.com             nxt_debug(task, "stream #%uD: cancelled by router",
5551926Smax.romanov@nginx.com                       req_rpc_data->stream);
5561926Smax.romanov@nginx.com         }
5571926Smax.romanov@nginx.com 
5581926Smax.romanov@nginx.com     } else {
5591926Smax.romanov@nginx.com         cancelled = 0;
560423Smax.romanov@nginx.com     }
561423Smax.romanov@nginx.com 
562423Smax.romanov@nginx.com     for (b = msg_info->buf; b != NULL; b = next) {
563423Smax.romanov@nginx.com         next = b->next;
5641269Sigor@sysoev.ru         b->next = NULL;
565423Smax.romanov@nginx.com 
566423Smax.romanov@nginx.com         if (b->is_port_mmap_sent) {
567423Smax.romanov@nginx.com             b->is_port_mmap_sent = cancelled == 0;
568423Smax.romanov@nginx.com         }
5691829Smax.romanov@nginx.com 
5701829Smax.romanov@nginx.com         b->completion_handler(task, b, b->parent);
571423Smax.romanov@nginx.com     }
572423Smax.romanov@nginx.com 
573423Smax.romanov@nginx.com     msg_info->buf = NULL;
574423Smax.romanov@nginx.com 
575423Smax.romanov@nginx.com     return cancelled;
576423Smax.romanov@nginx.com }
577423Smax.romanov@nginx.com 
578423Smax.romanov@nginx.com 
579425Smax.romanov@nginx.com nxt_inline nxt_bool_t
580425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk)
581425Smax.romanov@nginx.com {
582425Smax.romanov@nginx.com     if (lnk->next != NULL) {
583425Smax.romanov@nginx.com         nxt_queue_remove(lnk);
584425Smax.romanov@nginx.com 
585425Smax.romanov@nginx.com         lnk->next = NULL;
586425Smax.romanov@nginx.com 
587425Smax.romanov@nginx.com         return 1;
588425Smax.romanov@nginx.com     }
589425Smax.romanov@nginx.com 
590425Smax.romanov@nginx.com     return 0;
591425Smax.romanov@nginx.com }
592425Smax.romanov@nginx.com 
593425Smax.romanov@nginx.com 
594343Smax.romanov@nginx.com nxt_inline void
5951123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task,
5961123Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
597343Smax.romanov@nginx.com {
5981561Smax.romanov@nginx.com     nxt_app_t           *app;
5991561Smax.romanov@nginx.com     nxt_bool_t          unlinked;
6001547Smax.romanov@nginx.com     nxt_http_request_t  *r;
6011547Smax.romanov@nginx.com 
6021555Smax.romanov@nginx.com     nxt_router_msg_cancel(task, req_rpc_data);
6031123Smax.romanov@nginx.com 
6041978Smax.romanov@nginx.com     app = req_rpc_data->app;
6051978Smax.romanov@nginx.com 
6061123Smax.romanov@nginx.com     if (req_rpc_data->app_port != NULL) {
6071978Smax.romanov@nginx.com         nxt_router_app_port_release(task, app, req_rpc_data->app_port,
6081123Smax.romanov@nginx.com                                     req_rpc_data->apr_action);
6091123Smax.romanov@nginx.com 
6101123Smax.romanov@nginx.com         req_rpc_data->app_port = NULL;
6111123Smax.romanov@nginx.com     }
6121123Smax.romanov@nginx.com 
6131547Smax.romanov@nginx.com     r = req_rpc_data->request;
6141547Smax.romanov@nginx.com 
6151547Smax.romanov@nginx.com     if (r != NULL) {
6161547Smax.romanov@nginx.com         r->timer_data = NULL;
6171547Smax.romanov@nginx.com 
6181547Smax.romanov@nginx.com         nxt_router_http_request_release_post(task, r);
6191547Smax.romanov@nginx.com 
6201547Smax.romanov@nginx.com         r->req_rpc_data = NULL;
6211123Smax.romanov@nginx.com         req_rpc_data->request = NULL;
6221561Smax.romanov@nginx.com 
6231561Smax.romanov@nginx.com         if (app != NULL) {
6241561Smax.romanov@nginx.com             unlinked = 0;
6251561Smax.romanov@nginx.com 
6261561Smax.romanov@nginx.com             nxt_thread_mutex_lock(&app->mutex);
6271561Smax.romanov@nginx.com 
6281561Smax.romanov@nginx.com             if (r->app_link.next != NULL) {
6291561Smax.romanov@nginx.com                 nxt_queue_remove(&r->app_link);
6301561Smax.romanov@nginx.com                 r->app_link.next = NULL;
6311561Smax.romanov@nginx.com 
6321561Smax.romanov@nginx.com                 unlinked = 1;
6331561Smax.romanov@nginx.com             }
6341561Smax.romanov@nginx.com 
6351561Smax.romanov@nginx.com             nxt_thread_mutex_unlock(&app->mutex);
6361561Smax.romanov@nginx.com 
6371561Smax.romanov@nginx.com             if (unlinked) {
6381561Smax.romanov@nginx.com                 nxt_mp_release(r->mem_pool);
6391561Smax.romanov@nginx.com             }
6401561Smax.romanov@nginx.com         }
6411561Smax.romanov@nginx.com     }
6421561Smax.romanov@nginx.com 
6431561Smax.romanov@nginx.com     if (app != NULL) {
6441561Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
6451561Smax.romanov@nginx.com 
6461561Smax.romanov@nginx.com         req_rpc_data->app = NULL;
647346Smax.romanov@nginx.com     }
6481547Smax.romanov@nginx.com 
6491547Smax.romanov@nginx.com     if (req_rpc_data->msg_info.body_fd != -1) {
6501547Smax.romanov@nginx.com         nxt_fd_close(req_rpc_data->msg_info.body_fd);
6511547Smax.romanov@nginx.com 
6521547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = -1;
6531547Smax.romanov@nginx.com     }
6541547Smax.romanov@nginx.com 
6551547Smax.romanov@nginx.com     if (req_rpc_data->rpc_cancel) {
6561547Smax.romanov@nginx.com         req_rpc_data->rpc_cancel = 0;
6571547Smax.romanov@nginx.com 
6581547Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, task->thread->engine->port,
6591547Smax.romanov@nginx.com                             req_rpc_data->stream);
6601547Smax.romanov@nginx.com     }
661343Smax.romanov@nginx.com }
662343Smax.romanov@nginx.com 
663343Smax.romanov@nginx.com 
6641552Smax.romanov@nginx.com static void
665141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
666141Smax.romanov@nginx.com {
6671555Smax.romanov@nginx.com     nxt_int_t      res;
6681547Smax.romanov@nginx.com     nxt_app_t      *app;
6691547Smax.romanov@nginx.com     nxt_port_t     *port, *main_app_port;
6701547Smax.romanov@nginx.com     nxt_runtime_t  *rt;
6711547Smax.romanov@nginx.com 
672141Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
673141Smax.romanov@nginx.com 
6741547Smax.romanov@nginx.com     port = msg->u.new_port;
6751547Smax.romanov@nginx.com 
6761547Smax.romanov@nginx.com     if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) {
677662Smax.romanov@nginx.com         nxt_router_greet_controller(task, msg->u.new_port);
678662Smax.romanov@nginx.com     }
679662Smax.romanov@nginx.com 
680*1998St.nateldemoura@f5.com     if (port != NULL && port->type == NXT_PROCESS_PROTOTYPE)  {
681*1998St.nateldemoura@f5.com         nxt_port_rpc_handler(task, msg);
682*1998St.nateldemoura@f5.com 
683*1998St.nateldemoura@f5.com         return;
684*1998St.nateldemoura@f5.com     }
685*1998St.nateldemoura@f5.com 
6861547Smax.romanov@nginx.com     if (port == NULL || port->type != NXT_PROCESS_APP) {
6871547Smax.romanov@nginx.com 
6881547Smax.romanov@nginx.com         if (msg->port_msg.stream == 0) {
6891547Smax.romanov@nginx.com             return;
6901547Smax.romanov@nginx.com         }
6911547Smax.romanov@nginx.com 
6921547Smax.romanov@nginx.com         msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
6931555Smax.romanov@nginx.com 
6941555Smax.romanov@nginx.com     } else {
6951558Smax.romanov@nginx.com         if (msg->fd[1] != -1) {
6961558Smax.romanov@nginx.com             res = nxt_router_port_queue_map(task, port, msg->fd[1]);
6971555Smax.romanov@nginx.com             if (nxt_slow_path(res != NXT_OK)) {
6981555Smax.romanov@nginx.com                 return;
6991555Smax.romanov@nginx.com             }
7001555Smax.romanov@nginx.com 
7011558Smax.romanov@nginx.com             nxt_fd_close(msg->fd[1]);
7021558Smax.romanov@nginx.com             msg->fd[1] = -1;
7031555Smax.romanov@nginx.com         }
7041547Smax.romanov@nginx.com     }
7051547Smax.romanov@nginx.com 
7061547Smax.romanov@nginx.com     if (msg->port_msg.stream != 0) {
7071547Smax.romanov@nginx.com         nxt_port_rpc_handler(task, msg);
708141Smax.romanov@nginx.com         return;
709141Smax.romanov@nginx.com     }
710141Smax.romanov@nginx.com 
711*1998St.nateldemoura@f5.com     nxt_debug(task, "new port id %d (%d)", port->id, port->type);
712*1998St.nateldemoura@f5.com 
7131547Smax.romanov@nginx.com     /*
7141547Smax.romanov@nginx.com      * Port with "id == 0" is application 'main' port and it always
7151547Smax.romanov@nginx.com      * should come with non-zero stream.
7161547Smax.romanov@nginx.com      */
7171547Smax.romanov@nginx.com     nxt_assert(port->id != 0);
7181547Smax.romanov@nginx.com 
7191547Smax.romanov@nginx.com     /* Find 'main' app port and get app reference. */
7201547Smax.romanov@nginx.com     rt = task->thread->runtime;
7211547Smax.romanov@nginx.com 
7221547Smax.romanov@nginx.com     /*
7231547Smax.romanov@nginx.com      * It is safe to access 'runtime->ports' hash because 'NEW_PORT'
7241547Smax.romanov@nginx.com      * sent to main port (with id == 0) and processed in main thread.
7251547Smax.romanov@nginx.com      */
7261547Smax.romanov@nginx.com     main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0);
7271547Smax.romanov@nginx.com     nxt_assert(main_app_port != NULL);
7281547Smax.romanov@nginx.com 
7291547Smax.romanov@nginx.com     app = main_app_port->app;
7301915Smax.romanov@nginx.com 
7311915Smax.romanov@nginx.com     if (nxt_fast_path(app != NULL)) {
7321915Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
7331915Smax.romanov@nginx.com 
7341915Smax.romanov@nginx.com         /* TODO here should be find-and-add code because there can be
7351915Smax.romanov@nginx.com            port waiters in port_hash */
7361915Smax.romanov@nginx.com         nxt_port_hash_add(&app->port_hash, port);
7371915Smax.romanov@nginx.com         app->port_hash_count++;
7381915Smax.romanov@nginx.com 
7391915Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
7401915Smax.romanov@nginx.com 
7411915Smax.romanov@nginx.com         port->app = app;
7421915Smax.romanov@nginx.com     }
7431915Smax.romanov@nginx.com 
7441547Smax.romanov@nginx.com     port->main_app_port = main_app_port;
7451666Smax.romanov@nginx.com 
7461666Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL);
747141Smax.romanov@nginx.com }
748141Smax.romanov@nginx.com 
749141Smax.romanov@nginx.com 
7501552Smax.romanov@nginx.com static void
751139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
752115Sigor@sysoev.ru {
7531526Smax.romanov@nginx.com     void                    *p;
7541526Smax.romanov@nginx.com     size_t                  size;
755198Sigor@sysoev.ru     nxt_int_t               ret;
7561779Smax.romanov@nginx.com     nxt_port_t              *port;
757139Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
758139Sigor@sysoev.ru 
7591779Smax.romanov@nginx.com     port = nxt_runtime_port_find(task->thread->runtime,
7601779Smax.romanov@nginx.com                                  msg->port_msg.pid,
7611779Smax.romanov@nginx.com                                  msg->port_msg.reply_port);
7621779Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
7631779Smax.romanov@nginx.com         nxt_alert(task, "conf_data_handler: reply port not found");
7641779Smax.romanov@nginx.com         return;
7651779Smax.romanov@nginx.com     }
7661779Smax.romanov@nginx.com 
7671779Smax.romanov@nginx.com     p = MAP_FAILED;
7681779Smax.romanov@nginx.com 
7691779Smax.romanov@nginx.com     /*
7701779Smax.romanov@nginx.com      * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be
7711779Smax.romanov@nginx.com      * initialized in 'cleanup' section.
7721779Smax.romanov@nginx.com      */
7731779Smax.romanov@nginx.com     size = 0;
7741779Smax.romanov@nginx.com 
775139Sigor@sysoev.ru     tmcf = nxt_router_temp_conf(task);
776139Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
7771779Smax.romanov@nginx.com         goto fail;
77853Sigor@sysoev.ru     }
77953Sigor@sysoev.ru 
7801558Smax.romanov@nginx.com     if (nxt_slow_path(msg->fd[0] == -1)) {
7811779Smax.romanov@nginx.com         nxt_alert(task, "conf_data_handler: invalid shm fd");
7821779Smax.romanov@nginx.com         goto fail;
7831526Smax.romanov@nginx.com     }
7841526Smax.romanov@nginx.com 
7851526Smax.romanov@nginx.com     if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
7861526Smax.romanov@nginx.com         nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)",
7871526Smax.romanov@nginx.com                   (int) nxt_buf_mem_used_size(&msg->buf->mem));
7881779Smax.romanov@nginx.com         goto fail;
7891526Smax.romanov@nginx.com     }
7901526Smax.romanov@nginx.com 
7911526Smax.romanov@nginx.com     nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
7921526Smax.romanov@nginx.com 
7931558Smax.romanov@nginx.com     p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
7941558Smax.romanov@nginx.com 
7951558Smax.romanov@nginx.com     nxt_fd_close(msg->fd[0]);
7961558Smax.romanov@nginx.com     msg->fd[0] = -1;
7971526Smax.romanov@nginx.com 
7981526Smax.romanov@nginx.com     if (nxt_slow_path(p == MAP_FAILED)) {
7991779Smax.romanov@nginx.com         goto fail;
8001526Smax.romanov@nginx.com     }
8011526Smax.romanov@nginx.com 
8021526Smax.romanov@nginx.com     nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p);
803423Smax.romanov@nginx.com 
804591Sigor@sysoev.ru     tmcf->router_conf->router = nxt_router;
805139Sigor@sysoev.ru     tmcf->stream = msg->port_msg.stream;
8061779Smax.romanov@nginx.com     tmcf->port = port;
807779Smax.romanov@nginx.com 
808779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, 1);
809779Smax.romanov@nginx.com 
8101526Smax.romanov@nginx.com     ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size));
811198Sigor@sysoev.ru 
812198Sigor@sysoev.ru     if (nxt_fast_path(ret == NXT_OK)) {
813198Sigor@sysoev.ru         nxt_router_conf_apply(task, tmcf, NULL);
814198Sigor@sysoev.ru 
815198Sigor@sysoev.ru     } else {
816198Sigor@sysoev.ru         nxt_router_conf_error(task, tmcf);
817139Sigor@sysoev.ru     }
8181526Smax.romanov@nginx.com 
8191779Smax.romanov@nginx.com     goto cleanup;
8201779Smax.romanov@nginx.com 
8211526Smax.romanov@nginx.com fail:
8221526Smax.romanov@nginx.com 
8231779Smax.romanov@nginx.com     nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
8241779Smax.romanov@nginx.com                           msg->port_msg.stream, 0, NULL);
8251779Smax.romanov@nginx.com 
8261779Smax.romanov@nginx.com     if (tmcf != NULL) {
8271869Sa.suvorov@f5.com         nxt_mp_release(tmcf->mem_pool);
8281779Smax.romanov@nginx.com     }
8291779Smax.romanov@nginx.com 
8301779Smax.romanov@nginx.com cleanup:
8311779Smax.romanov@nginx.com 
8321779Smax.romanov@nginx.com     if (p != MAP_FAILED) {
8331779Smax.romanov@nginx.com         nxt_mem_munmap(p, size);
8341779Smax.romanov@nginx.com     }
8351779Smax.romanov@nginx.com 
8361779Smax.romanov@nginx.com     if (msg->fd[0] != -1) {
8371779Smax.romanov@nginx.com         nxt_fd_close(msg->fd[0]);
8381779Smax.romanov@nginx.com         msg->fd[0] = -1;
8391779Smax.romanov@nginx.com     }
84053Sigor@sysoev.ru }
84153Sigor@sysoev.ru 
84253Sigor@sysoev.ru 
843347Smax.romanov@nginx.com static void
8441926Smax.romanov@nginx.com nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
8451926Smax.romanov@nginx.com {
8461926Smax.romanov@nginx.com     nxt_app_t            *app;
8471926Smax.romanov@nginx.com     nxt_int_t            ret;
8481926Smax.romanov@nginx.com     nxt_str_t            app_name;
849*1998St.nateldemoura@f5.com     nxt_port_t           *reply_port, *shared_port, *old_shared_port;
850*1998St.nateldemoura@f5.com     nxt_port_t           *proto_port;
8511926Smax.romanov@nginx.com     nxt_port_msg_type_t  reply;
8521926Smax.romanov@nginx.com 
8531926Smax.romanov@nginx.com     reply_port = nxt_runtime_port_find(task->thread->runtime,
8541926Smax.romanov@nginx.com                                        msg->port_msg.pid,
8551926Smax.romanov@nginx.com                                        msg->port_msg.reply_port);
8561926Smax.romanov@nginx.com     if (nxt_slow_path(reply_port == NULL)) {
8571926Smax.romanov@nginx.com         nxt_alert(task, "app_restart_handler: reply port not found");
8581926Smax.romanov@nginx.com         return;
8591926Smax.romanov@nginx.com     }
8601926Smax.romanov@nginx.com 
8611926Smax.romanov@nginx.com     app_name.length = nxt_buf_mem_used_size(&msg->buf->mem);
8621926Smax.romanov@nginx.com     app_name.start = msg->buf->mem.pos;
8631926Smax.romanov@nginx.com 
8641926Smax.romanov@nginx.com     nxt_debug(task, "app_restart_handler: %V", &app_name);
8651926Smax.romanov@nginx.com 
8661926Smax.romanov@nginx.com     app = nxt_router_app_find(&nxt_router->apps, &app_name);
8671926Smax.romanov@nginx.com 
8681926Smax.romanov@nginx.com     if (nxt_fast_path(app != NULL)) {
8691926Smax.romanov@nginx.com         shared_port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
8701926Smax.romanov@nginx.com                                    NXT_PROCESS_APP);
8711926Smax.romanov@nginx.com         if (nxt_slow_path(shared_port == NULL)) {
8721926Smax.romanov@nginx.com             goto fail;
8731926Smax.romanov@nginx.com         }
8741926Smax.romanov@nginx.com 
8751926Smax.romanov@nginx.com         ret = nxt_port_socket_init(task, shared_port, 0);
8761926Smax.romanov@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
8771926Smax.romanov@nginx.com             nxt_port_use(task, shared_port, -1);
8781926Smax.romanov@nginx.com             goto fail;
8791926Smax.romanov@nginx.com         }
8801926Smax.romanov@nginx.com 
8811926Smax.romanov@nginx.com         ret = nxt_router_app_queue_init(task, shared_port);
8821926Smax.romanov@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
8831926Smax.romanov@nginx.com             nxt_port_write_close(shared_port);
8841926Smax.romanov@nginx.com             nxt_port_read_close(shared_port);
8851926Smax.romanov@nginx.com             nxt_port_use(task, shared_port, -1);
8861926Smax.romanov@nginx.com             goto fail;
8871926Smax.romanov@nginx.com         }
8881926Smax.romanov@nginx.com 
8891926Smax.romanov@nginx.com         nxt_port_write_enable(task, shared_port);
8901926Smax.romanov@nginx.com 
8911926Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
8921926Smax.romanov@nginx.com 
893*1998St.nateldemoura@f5.com         proto_port = app->proto_port;
894*1998St.nateldemoura@f5.com 
895*1998St.nateldemoura@f5.com         if (proto_port != NULL) {
896*1998St.nateldemoura@f5.com             nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name,
897*1998St.nateldemoura@f5.com                       proto_port->pid);
898*1998St.nateldemoura@f5.com 
899*1998St.nateldemoura@f5.com             app->proto_port = NULL;
900*1998St.nateldemoura@f5.com             proto_port->app = NULL;
901*1998St.nateldemoura@f5.com         }
9021926Smax.romanov@nginx.com 
9031926Smax.romanov@nginx.com         app->generation++;
9041926Smax.romanov@nginx.com 
9051926Smax.romanov@nginx.com         shared_port->app = app;
9061926Smax.romanov@nginx.com 
9071926Smax.romanov@nginx.com         old_shared_port = app->shared_port;
9081926Smax.romanov@nginx.com         old_shared_port->app = NULL;
9091926Smax.romanov@nginx.com 
9101926Smax.romanov@nginx.com         app->shared_port = shared_port;
9111926Smax.romanov@nginx.com 
9121926Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
9131926Smax.romanov@nginx.com 
9141926Smax.romanov@nginx.com         nxt_port_close(task, old_shared_port);
9151926Smax.romanov@nginx.com         nxt_port_use(task, old_shared_port, -1);
9161926Smax.romanov@nginx.com 
917*1998St.nateldemoura@f5.com         if (proto_port != NULL) {
918*1998St.nateldemoura@f5.com             (void) nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT,
919*1998St.nateldemoura@f5.com                                          -1, 0, 0, NULL);
920*1998St.nateldemoura@f5.com 
921*1998St.nateldemoura@f5.com             nxt_port_close(task, proto_port);
922*1998St.nateldemoura@f5.com 
923*1998St.nateldemoura@f5.com             nxt_port_use(task, proto_port, -1);
924*1998St.nateldemoura@f5.com         }
925*1998St.nateldemoura@f5.com 
9261926Smax.romanov@nginx.com         reply = NXT_PORT_MSG_RPC_READY_LAST;
9271926Smax.romanov@nginx.com 
9281926Smax.romanov@nginx.com     } else {
9291926Smax.romanov@nginx.com 
9301926Smax.romanov@nginx.com fail:
9311926Smax.romanov@nginx.com 
9321926Smax.romanov@nginx.com         reply = NXT_PORT_MSG_RPC_ERROR;
9331926Smax.romanov@nginx.com     }
9341926Smax.romanov@nginx.com 
9351926Smax.romanov@nginx.com     nxt_port_socket_write(task, reply_port, reply, -1, msg->port_msg.stream,
9361926Smax.romanov@nginx.com                           0, NULL);
9371926Smax.romanov@nginx.com }
9381926Smax.romanov@nginx.com 
9391926Smax.romanov@nginx.com 
9401926Smax.romanov@nginx.com static void
941507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
942507Smax.romanov@nginx.com     void *data)
943347Smax.romanov@nginx.com {
944347Smax.romanov@nginx.com     union {
945347Smax.romanov@nginx.com         nxt_pid_t  removed_pid;
946347Smax.romanov@nginx.com         void       *data;
947347Smax.romanov@nginx.com     } u;
948347Smax.romanov@nginx.com 
949347Smax.romanov@nginx.com     u.data = data;
950347Smax.romanov@nginx.com 
951347Smax.romanov@nginx.com     nxt_port_rpc_remove_peer(task, port, u.removed_pid);
952347Smax.romanov@nginx.com }
953347Smax.romanov@nginx.com 
954347Smax.romanov@nginx.com 
9551552Smax.romanov@nginx.com static void
956192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
957192Smax.romanov@nginx.com {
958347Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
959318Smax.romanov@nginx.com 
960192Smax.romanov@nginx.com     nxt_port_remove_pid_handler(task, msg);
961192Smax.romanov@nginx.com 
962318Smax.romanov@nginx.com     nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
963318Smax.romanov@nginx.com     {
9641486Smax.romanov@nginx.com         if (nxt_fast_path(engine->port != NULL)) {
9651486Smax.romanov@nginx.com             nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
9661486Smax.romanov@nginx.com                           msg->u.data);
9671486Smax.romanov@nginx.com         }
968318Smax.romanov@nginx.com     }
969318Smax.romanov@nginx.com     nxt_queue_loop;
970318Smax.romanov@nginx.com 
9711085Smax.romanov@nginx.com     if (msg->port_msg.stream == 0) {
9721085Smax.romanov@nginx.com         return;
9731085Smax.romanov@nginx.com     }
9741085Smax.romanov@nginx.com 
975192Smax.romanov@nginx.com     msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
976192Smax.romanov@nginx.com 
977192Smax.romanov@nginx.com     nxt_port_rpc_handler(task, msg);
978192Smax.romanov@nginx.com }
979192Smax.romanov@nginx.com 
980192Smax.romanov@nginx.com 
98153Sigor@sysoev.ru static nxt_router_temp_conf_t *
982139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task)
98353Sigor@sysoev.ru {
98465Sigor@sysoev.ru     nxt_mp_t                *mp, *tmp;
98553Sigor@sysoev.ru     nxt_router_conf_t       *rtcf;
98653Sigor@sysoev.ru     nxt_router_temp_conf_t  *tmcf;
98753Sigor@sysoev.ru 
98865Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
98953Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
99053Sigor@sysoev.ru         return NULL;
99153Sigor@sysoev.ru     }
99253Sigor@sysoev.ru 
99365Sigor@sysoev.ru     rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
99453Sigor@sysoev.ru     if (nxt_slow_path(rtcf == NULL)) {
99553Sigor@sysoev.ru         goto fail;
99653Sigor@sysoev.ru     }
99753Sigor@sysoev.ru 
99853Sigor@sysoev.ru     rtcf->mem_pool = mp;
99953Sigor@sysoev.ru 
100065Sigor@sysoev.ru     tmp = nxt_mp_create(1024, 128, 256, 32);
100153Sigor@sysoev.ru     if (nxt_slow_path(tmp == NULL)) {
100253Sigor@sysoev.ru         goto fail;
100353Sigor@sysoev.ru     }
100453Sigor@sysoev.ru 
100565Sigor@sysoev.ru     tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
100653Sigor@sysoev.ru     if (nxt_slow_path(tmcf == NULL)) {
100753Sigor@sysoev.ru         goto temp_fail;
100853Sigor@sysoev.ru     }
100953Sigor@sysoev.ru 
101053Sigor@sysoev.ru     tmcf->mem_pool = tmp;
1011591Sigor@sysoev.ru     tmcf->router_conf = rtcf;
1012139Sigor@sysoev.ru     tmcf->count = 1;
1013139Sigor@sysoev.ru     tmcf->engine = task->thread->engine;
101453Sigor@sysoev.ru 
101553Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
101653Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
101753Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
101853Sigor@sysoev.ru         goto temp_fail;
101953Sigor@sysoev.ru     }
102053Sigor@sysoev.ru 
10211509Sigor@sysoev.ru     nxt_queue_init(&creating_sockets);
10221509Sigor@sysoev.ru     nxt_queue_init(&pending_sockets);
10231509Sigor@sysoev.ru     nxt_queue_init(&updating_sockets);
10241509Sigor@sysoev.ru     nxt_queue_init(&keeping_sockets);
10251509Sigor@sysoev.ru     nxt_queue_init(&deleting_sockets);
1026416Smax.romanov@nginx.com 
1027774Svbart@nginx.com #if (NXT_TLS)
1028774Svbart@nginx.com     nxt_queue_init(&tmcf->tls);
1029774Svbart@nginx.com #endif
1030774Svbart@nginx.com 
1031133Sigor@sysoev.ru     nxt_queue_init(&tmcf->apps);
1032133Sigor@sysoev.ru     nxt_queue_init(&tmcf->previous);
103353Sigor@sysoev.ru 
103453Sigor@sysoev.ru     return tmcf;
103553Sigor@sysoev.ru 
103653Sigor@sysoev.ru temp_fail:
103753Sigor@sysoev.ru 
103865Sigor@sysoev.ru     nxt_mp_destroy(tmp);
103953Sigor@sysoev.ru 
104053Sigor@sysoev.ru fail:
104153Sigor@sysoev.ru 
104265Sigor@sysoev.ru     nxt_mp_destroy(mp);
104353Sigor@sysoev.ru 
104453Sigor@sysoev.ru     return NULL;
104553Sigor@sysoev.ru }
104653Sigor@sysoev.ru 
104753Sigor@sysoev.ru 
1048507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1049507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app)
1050507Smax.romanov@nginx.com {
1051507Smax.romanov@nginx.com     return app->processes + app->pending_processes < app->max_processes
1052507Smax.romanov@nginx.com             && app->pending_processes < app->max_pending_processes;
1053507Smax.romanov@nginx.com }
1054507Smax.romanov@nginx.com 
1055507Smax.romanov@nginx.com 
1056507Smax.romanov@nginx.com nxt_inline nxt_bool_t
1057507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app)
1058507Smax.romanov@nginx.com {
10591547Smax.romanov@nginx.com     return (app->active_requests
10601547Smax.romanov@nginx.com               > app->port_hash_count + app->pending_processes)
10611547Smax.romanov@nginx.com            || (app->spare_processes
10621547Smax.romanov@nginx.com                 > app->idle_processes + app->pending_processes);
1063507Smax.romanov@nginx.com }
1064507Smax.romanov@nginx.com 
1065507Smax.romanov@nginx.com 
1066198Sigor@sysoev.ru static void
1067198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1068139Sigor@sysoev.ru {
1069139Sigor@sysoev.ru     nxt_int_t                    ret;
1070507Smax.romanov@nginx.com     nxt_app_t                    *app;
1071139Sigor@sysoev.ru     nxt_router_t                 *router;
1072139Sigor@sysoev.ru     nxt_runtime_t                *rt;
1073198Sigor@sysoev.ru     nxt_queue_link_t             *qlk;
1074198Sigor@sysoev.ru     nxt_socket_conf_t            *skcf;
1075630Svbart@nginx.com     nxt_router_conf_t            *rtcf;
1076198Sigor@sysoev.ru     nxt_router_temp_conf_t       *tmcf;
1077139Sigor@sysoev.ru     const nxt_event_interface_t  *interface;
1078774Svbart@nginx.com #if (NXT_TLS)
1079774Svbart@nginx.com     nxt_router_tlssock_t         *tls;
1080774Svbart@nginx.com #endif
1081139Sigor@sysoev.ru 
1082198Sigor@sysoev.ru     tmcf = obj;
1083198Sigor@sysoev.ru 
10841509Sigor@sysoev.ru     qlk = nxt_queue_first(&pending_sockets);
10851509Sigor@sysoev.ru 
10861509Sigor@sysoev.ru     if (qlk != nxt_queue_tail(&pending_sockets)) {
1087198Sigor@sysoev.ru         nxt_queue_remove(qlk);
10881509Sigor@sysoev.ru         nxt_queue_insert_tail(&creating_sockets, qlk);
1089198Sigor@sysoev.ru 
1090198Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1091198Sigor@sysoev.ru 
1092198Sigor@sysoev.ru         nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1093198Sigor@sysoev.ru 
1094198Sigor@sysoev.ru         return;
1095139Sigor@sysoev.ru     }
1096139Sigor@sysoev.ru 
1097774Svbart@nginx.com #if (NXT_TLS)
10981828Sa.suvorov@f5.com     qlk = nxt_queue_last(&tmcf->tls);
10991828Sa.suvorov@f5.com 
11001828Sa.suvorov@f5.com     if (qlk != nxt_queue_head(&tmcf->tls)) {
1101774Svbart@nginx.com         nxt_queue_remove(qlk);
1102774Svbart@nginx.com 
1103774Svbart@nginx.com         tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1104774Svbart@nginx.com 
11051885Sa.suvorov@f5.com         nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
11061885Sa.suvorov@f5.com                            nxt_router_tls_rpc_handler, tls);
1107774Svbart@nginx.com         return;
1108774Svbart@nginx.com     }
1109774Svbart@nginx.com #endif
1110774Svbart@nginx.com 
1111507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1112507Smax.romanov@nginx.com 
1113507Smax.romanov@nginx.com         if (nxt_router_app_need_start(app)) {
1114507Smax.romanov@nginx.com             nxt_router_app_rpc_create(task, tmcf, app);
1115507Smax.romanov@nginx.com             return;
1116507Smax.romanov@nginx.com         }
1117507Smax.romanov@nginx.com 
1118507Smax.romanov@nginx.com     } nxt_queue_loop;
1119507Smax.romanov@nginx.com 
1120630Svbart@nginx.com     rtcf = tmcf->router_conf;
1121630Svbart@nginx.com 
1122630Svbart@nginx.com     if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1123630Svbart@nginx.com         nxt_router_access_log_open(task, tmcf);
1124630Svbart@nginx.com         return;
1125630Svbart@nginx.com     }
1126630Svbart@nginx.com 
1127139Sigor@sysoev.ru     rt = task->thread->runtime;
1128139Sigor@sysoev.ru 
1129139Sigor@sysoev.ru     interface = nxt_service_get(rt->services, "engine", NULL);
1130139Sigor@sysoev.ru 
1131630Svbart@nginx.com     router = rtcf->router;
1132198Sigor@sysoev.ru 
1133139Sigor@sysoev.ru     ret = nxt_router_engines_create(task, router, tmcf, interface);
1134139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1135198Sigor@sysoev.ru         goto fail;
1136139Sigor@sysoev.ru     }
1137139Sigor@sysoev.ru 
1138139Sigor@sysoev.ru     ret = nxt_router_threads_create(task, rt, tmcf);
1139139Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
1140198Sigor@sysoev.ru         goto fail;
1141139Sigor@sysoev.ru     }
1142139Sigor@sysoev.ru 
1143343Smax.romanov@nginx.com     nxt_router_apps_sort(task, router, tmcf);
1144139Sigor@sysoev.ru 
11451828Sa.suvorov@f5.com     nxt_router_apps_hash_use(task, rtcf, 1);
11461563Svbart@nginx.com 
1147315Sigor@sysoev.ru     nxt_router_engines_post(router, tmcf);
1148139Sigor@sysoev.ru 
11491509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &updating_sockets);
11501509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &creating_sockets);
1151139Sigor@sysoev.ru 
1152630Svbart@nginx.com     router->access_log = rtcf->access_log;
1153630Svbart@nginx.com 
1154198Sigor@sysoev.ru     nxt_router_conf_ready(task, tmcf);
1155198Sigor@sysoev.ru 
1156198Sigor@sysoev.ru     return;
1157198Sigor@sysoev.ru 
1158198Sigor@sysoev.ru fail:
1159198Sigor@sysoev.ru 
1160198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
1161198Sigor@sysoev.ru 
1162198Sigor@sysoev.ru     return;
1163139Sigor@sysoev.ru }
1164139Sigor@sysoev.ru 
1165139Sigor@sysoev.ru 
1166139Sigor@sysoev.ru static void
1167139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1168139Sigor@sysoev.ru {
1169153Sigor@sysoev.ru     nxt_joint_job_t  *job;
1170153Sigor@sysoev.ru 
1171153Sigor@sysoev.ru     job = obj;
1172153Sigor@sysoev.ru 
1173198Sigor@sysoev.ru     nxt_router_conf_ready(task, job->tmcf);
1174139Sigor@sysoev.ru }
1175139Sigor@sysoev.ru 
1176139Sigor@sysoev.ru 
1177139Sigor@sysoev.ru static void
1178198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1179139Sigor@sysoev.ru {
11801542Smax.romanov@nginx.com     uint32_t               count;
11811542Smax.romanov@nginx.com     nxt_router_conf_t      *rtcf;
11821542Smax.romanov@nginx.com     nxt_thread_spinlock_t  *lock;
11831542Smax.romanov@nginx.com 
11841542Smax.romanov@nginx.com     nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count);
11851542Smax.romanov@nginx.com 
11861542Smax.romanov@nginx.com     if (--tmcf->count > 0) {
11871542Smax.romanov@nginx.com         return;
11881542Smax.romanov@nginx.com     }
11891542Smax.romanov@nginx.com 
11901542Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
11911542Smax.romanov@nginx.com 
11921542Smax.romanov@nginx.com     rtcf = tmcf->router_conf;
11931542Smax.romanov@nginx.com 
11941542Smax.romanov@nginx.com     lock = &rtcf->router->lock;
11951542Smax.romanov@nginx.com 
11961542Smax.romanov@nginx.com     nxt_thread_spin_lock(lock);
11971542Smax.romanov@nginx.com 
11981542Smax.romanov@nginx.com     count = rtcf->count;
11991542Smax.romanov@nginx.com 
12001542Smax.romanov@nginx.com     nxt_thread_spin_unlock(lock);
12011542Smax.romanov@nginx.com 
12021542Smax.romanov@nginx.com     nxt_debug(task, "rtcf %p: %D", rtcf, count);
12031542Smax.romanov@nginx.com 
12041542Smax.romanov@nginx.com     if (count == 0) {
12051563Svbart@nginx.com         nxt_router_apps_hash_use(task, rtcf, -1);
12061542Smax.romanov@nginx.com 
12071542Smax.romanov@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
12081542Smax.romanov@nginx.com 
12091542Smax.romanov@nginx.com         nxt_mp_destroy(rtcf->mem_pool);
12101542Smax.romanov@nginx.com     }
12111542Smax.romanov@nginx.com 
12121869Sa.suvorov@f5.com     nxt_mp_release(tmcf->mem_pool);
1213139Sigor@sysoev.ru }
1214139Sigor@sysoev.ru 
1215139Sigor@sysoev.ru 
1216139Sigor@sysoev.ru static void
1217139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1218139Sigor@sysoev.ru {
1219507Smax.romanov@nginx.com     nxt_app_t          *app;
1220568Smax.romanov@nginx.com     nxt_queue_t        new_socket_confs;
1221148Sigor@sysoev.ru     nxt_socket_t       s;
1222149Sigor@sysoev.ru     nxt_router_t       *router;
1223148Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
1224148Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
1225630Svbart@nginx.com     nxt_router_conf_t  *rtcf;
1226148Sigor@sysoev.ru 
1227564Svbart@nginx.com     nxt_alert(task, "failed to apply new conf");
1228198Sigor@sysoev.ru 
12291509Sigor@sysoev.ru     for (qlk = nxt_queue_first(&creating_sockets);
12301509Sigor@sysoev.ru          qlk != nxt_queue_tail(&creating_sockets);
1231148Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
1232148Sigor@sysoev.ru     {
1233148Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1234359Sigor@sysoev.ru         s = skcf->listen->socket;
1235148Sigor@sysoev.ru 
1236148Sigor@sysoev.ru         if (s != -1) {
1237148Sigor@sysoev.ru             nxt_socket_close(task, s);
1238148Sigor@sysoev.ru         }
1239148Sigor@sysoev.ru 
1240359Sigor@sysoev.ru         nxt_free(skcf->listen);
1241148Sigor@sysoev.ru     }
1242148Sigor@sysoev.ru 
1243568Smax.romanov@nginx.com     nxt_queue_init(&new_socket_confs);
12441509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &updating_sockets);
12451509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &pending_sockets);
12461509Sigor@sysoev.ru     nxt_queue_add(&new_socket_confs, &creating_sockets);
1247568Smax.romanov@nginx.com 
1248964Sigor@sysoev.ru     rtcf = tmcf->router_conf;
1249964Sigor@sysoev.ru 
1250507Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1251507Smax.romanov@nginx.com 
1252753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
1253507Smax.romanov@nginx.com 
1254507Smax.romanov@nginx.com     } nxt_queue_loop;
1255507Smax.romanov@nginx.com 
1256630Svbart@nginx.com     router = rtcf->router;
1257149Sigor@sysoev.ru 
12581509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &keeping_sockets);
12591509Sigor@sysoev.ru     nxt_queue_add(&router->sockets, &deleting_sockets);
1260149Sigor@sysoev.ru 
1261416Smax.romanov@nginx.com     nxt_queue_add(&router->apps, &tmcf->previous);
1262416Smax.romanov@nginx.com 
1263148Sigor@sysoev.ru     // TODO: new engines and threads
1264148Sigor@sysoev.ru 
1265630Svbart@nginx.com     nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1266630Svbart@nginx.com 
1267630Svbart@nginx.com     nxt_mp_destroy(rtcf->mem_pool);
1268139Sigor@sysoev.ru 
1269193Smax.romanov@nginx.com     nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
12701509Sigor@sysoev.ru 
12711869Sa.suvorov@f5.com     nxt_mp_release(tmcf->mem_pool);
1272139Sigor@sysoev.ru }
1273139Sigor@sysoev.ru 
1274139Sigor@sysoev.ru 
1275139Sigor@sysoev.ru static void
1276139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1277193Smax.romanov@nginx.com     nxt_port_msg_type_t type)
1278139Sigor@sysoev.ru {
1279193Smax.romanov@nginx.com     nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1280779Smax.romanov@nginx.com 
1281779Smax.romanov@nginx.com     nxt_port_use(task, tmcf->port, -1);
1282779Smax.romanov@nginx.com 
1283779Smax.romanov@nginx.com     tmcf->port = NULL;
1284139Sigor@sysoev.ru }
1285139Sigor@sysoev.ru 
1286139Sigor@sysoev.ru 
1287115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_conf[] = {
1288115Sigor@sysoev.ru     {
1289133Sigor@sysoev.ru         nxt_string("listeners_threads"),
1290115Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
1291115Sigor@sysoev.ru         offsetof(nxt_router_conf_t, threads),
1292115Sigor@sysoev.ru     },
1293115Sigor@sysoev.ru };
1294115Sigor@sysoev.ru 
1295115Sigor@sysoev.ru 
1296133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_app_conf[] = {
1297115Sigor@sysoev.ru     {
1298133Sigor@sysoev.ru         nxt_string("type"),
1299115Sigor@sysoev.ru         NXT_CONF_MAP_STR,
1300133Sigor@sysoev.ru         offsetof(nxt_router_app_conf_t, type),
1301115Sigor@sysoev.ru     },
1302115Sigor@sysoev.ru 
1303115Sigor@sysoev.ru     {
1304507Smax.romanov@nginx.com         nxt_string("limits"),
1305507Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1306507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, limits_value),
1307133Sigor@sysoev.ru     },
1308318Smax.romanov@nginx.com 
1309318Smax.romanov@nginx.com     {
1310507Smax.romanov@nginx.com         nxt_string("processes"),
1311507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1312507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes),
1313507Smax.romanov@nginx.com     },
1314507Smax.romanov@nginx.com 
1315507Smax.romanov@nginx.com     {
1316507Smax.romanov@nginx.com         nxt_string("processes"),
1317318Smax.romanov@nginx.com         NXT_CONF_MAP_PTR,
1318507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, processes_value),
1319318Smax.romanov@nginx.com     },
13201473Svbart@nginx.com 
13211473Svbart@nginx.com     {
13221473Svbart@nginx.com         nxt_string("targets"),
13231473Svbart@nginx.com         NXT_CONF_MAP_PTR,
13241473Svbart@nginx.com         offsetof(nxt_router_app_conf_t, targets_value),
13251473Svbart@nginx.com     },
1326318Smax.romanov@nginx.com };
1327318Smax.romanov@nginx.com 
1328318Smax.romanov@nginx.com 
1329318Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_limits_conf[] = {
1330318Smax.romanov@nginx.com     {
1331318Smax.romanov@nginx.com         nxt_string("timeout"),
1332318Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1333318Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, timeout),
1334318Smax.romanov@nginx.com     },
1335133Sigor@sysoev.ru };
1336133Sigor@sysoev.ru 
1337133Sigor@sysoev.ru 
1338507Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_app_processes_conf[] = {
1339507Smax.romanov@nginx.com     {
1340507Smax.romanov@nginx.com         nxt_string("spare"),
1341507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1342507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, spare_processes),
1343507Smax.romanov@nginx.com     },
1344507Smax.romanov@nginx.com 
1345507Smax.romanov@nginx.com     {
1346507Smax.romanov@nginx.com         nxt_string("max"),
1347507Smax.romanov@nginx.com         NXT_CONF_MAP_INT32,
1348507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, max_processes),
1349507Smax.romanov@nginx.com     },
1350507Smax.romanov@nginx.com 
1351507Smax.romanov@nginx.com     {
1352507Smax.romanov@nginx.com         nxt_string("idle_timeout"),
1353507Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1354507Smax.romanov@nginx.com         offsetof(nxt_router_app_conf_t, idle_timeout),
1355507Smax.romanov@nginx.com     },
1356507Smax.romanov@nginx.com };
1357507Smax.romanov@nginx.com 
1358507Smax.romanov@nginx.com 
1359133Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_listener_conf[] = {
1360133Sigor@sysoev.ru     {
1361964Sigor@sysoev.ru         nxt_string("pass"),
1362964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1363964Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, pass),
1364964Sigor@sysoev.ru     },
1365964Sigor@sysoev.ru 
1366964Sigor@sysoev.ru     {
1367133Sigor@sysoev.ru         nxt_string("application"),
1368964Sigor@sysoev.ru         NXT_CONF_MAP_STR_COPY,
1369133Sigor@sysoev.ru         offsetof(nxt_router_listener_conf_t, application),
1370115Sigor@sysoev.ru     },
1371115Sigor@sysoev.ru };
1372115Sigor@sysoev.ru 
1373115Sigor@sysoev.ru 
1374115Sigor@sysoev.ru static nxt_conf_map_t  nxt_router_http_conf[] = {
1375115Sigor@sysoev.ru     {
1376115Sigor@sysoev.ru         nxt_string("header_buffer_size"),
1377115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1378115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_buffer_size),
1379115Sigor@sysoev.ru     },
1380115Sigor@sysoev.ru 
1381115Sigor@sysoev.ru     {
1382115Sigor@sysoev.ru         nxt_string("large_header_buffer_size"),
1383115Sigor@sysoev.ru         NXT_CONF_MAP_SIZE,
1384115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, large_header_buffer_size),
1385115Sigor@sysoev.ru     },
1386115Sigor@sysoev.ru 
1387115Sigor@sysoev.ru     {
1388206Smax.romanov@nginx.com         nxt_string("large_header_buffers"),
1389206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1390206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, large_header_buffers),
1391206Smax.romanov@nginx.com     },
1392206Smax.romanov@nginx.com 
1393206Smax.romanov@nginx.com     {
1394206Smax.romanov@nginx.com         nxt_string("body_buffer_size"),
1395206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1396206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_buffer_size),
1397206Smax.romanov@nginx.com     },
1398206Smax.romanov@nginx.com 
1399206Smax.romanov@nginx.com     {
1400206Smax.romanov@nginx.com         nxt_string("max_body_size"),
1401206Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
1402206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, max_body_size),
1403206Smax.romanov@nginx.com     },
1404206Smax.romanov@nginx.com 
1405206Smax.romanov@nginx.com     {
1406431Sigor@sysoev.ru         nxt_string("idle_timeout"),
1407431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1408431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, idle_timeout),
1409431Sigor@sysoev.ru     },
1410431Sigor@sysoev.ru 
1411431Sigor@sysoev.ru     {
1412115Sigor@sysoev.ru         nxt_string("header_read_timeout"),
1413115Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1414115Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, header_read_timeout),
1415115Sigor@sysoev.ru     },
1416206Smax.romanov@nginx.com 
1417206Smax.romanov@nginx.com     {
1418206Smax.romanov@nginx.com         nxt_string("body_read_timeout"),
1419206Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
1420206Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_read_timeout),
1421206Smax.romanov@nginx.com     },
1422431Sigor@sysoev.ru 
1423431Sigor@sysoev.ru     {
1424431Sigor@sysoev.ru         nxt_string("send_timeout"),
1425431Sigor@sysoev.ru         NXT_CONF_MAP_MSEC,
1426431Sigor@sysoev.ru         offsetof(nxt_socket_conf_t, send_timeout),
1427431Sigor@sysoev.ru     },
14281403Smax.romanov@nginx.com 
14291403Smax.romanov@nginx.com     {
14301403Smax.romanov@nginx.com         nxt_string("body_temp_path"),
14311403Smax.romanov@nginx.com         NXT_CONF_MAP_STR,
14321403Smax.romanov@nginx.com         offsetof(nxt_socket_conf_t, body_temp_path),
14331403Smax.romanov@nginx.com     },
14341709Svbart@nginx.com 
14351709Svbart@nginx.com     {
14361709Svbart@nginx.com         nxt_string("discard_unsafe_fields"),
14371709Svbart@nginx.com         NXT_CONF_MAP_INT8,
14381709Svbart@nginx.com         offsetof(nxt_socket_conf_t, discard_unsafe_fields),
14391709Svbart@nginx.com     },
1440115Sigor@sysoev.ru };
1441115Sigor@sysoev.ru 
1442115Sigor@sysoev.ru 
14431131Smax.romanov@nginx.com static nxt_conf_map_t  nxt_router_websocket_conf[] = {
14441131Smax.romanov@nginx.com     {
14451131Smax.romanov@nginx.com         nxt_string("max_frame_size"),
14461131Smax.romanov@nginx.com         NXT_CONF_MAP_SIZE,
14471131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, max_frame_size),
14481131Smax.romanov@nginx.com     },
14491131Smax.romanov@nginx.com 
14501131Smax.romanov@nginx.com     {
14511131Smax.romanov@nginx.com         nxt_string("read_timeout"),
14521131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
14531131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, read_timeout),
14541131Smax.romanov@nginx.com     },
14551131Smax.romanov@nginx.com 
14561131Smax.romanov@nginx.com     {
14571131Smax.romanov@nginx.com         nxt_string("keepalive_interval"),
14581131Smax.romanov@nginx.com         NXT_CONF_MAP_MSEC,
14591131Smax.romanov@nginx.com         offsetof(nxt_websocket_conf_t, keepalive_interval),
14601131Smax.romanov@nginx.com     },
14611131Smax.romanov@nginx.com 
14621131Smax.romanov@nginx.com };
14631131Smax.romanov@nginx.com 
14641131Smax.romanov@nginx.com 
146553Sigor@sysoev.ru static nxt_int_t
1466115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1467115Sigor@sysoev.ru     u_char *start, u_char *end)
146853Sigor@sysoev.ru {
1469133Sigor@sysoev.ru     u_char                      *p;
1470133Sigor@sysoev.ru     size_t                      size;
14711473Svbart@nginx.com     nxt_mp_t                    *mp, *app_mp;
14721473Svbart@nginx.com     uint32_t                    next, next_target;
1473115Sigor@sysoev.ru     nxt_int_t                   ret;
14741473Svbart@nginx.com     nxt_str_t                   name, path, target;
1475133Sigor@sysoev.ru     nxt_app_t                   *app, *prev;
14761473Svbart@nginx.com     nxt_str_t                   *t, *s, *targets;
14771473Svbart@nginx.com     nxt_uint_t                  n, i;
14781547Smax.romanov@nginx.com     nxt_port_t                  *port;
1479359Sigor@sysoev.ru     nxt_router_t                *router;
1480753Smax.romanov@nginx.com     nxt_app_joint_t             *app_joint;
14811828Sa.suvorov@f5.com #if (NXT_TLS)
14821920Sa.suvorov@f5.com     nxt_tls_init_t              *tls_init;
14831920Sa.suvorov@f5.com     nxt_conf_value_t            *certificate;
14841828Sa.suvorov@f5.com #endif
14851131Smax.romanov@nginx.com     nxt_conf_value_t            *conf, *http, *value, *websocket;
1486133Sigor@sysoev.ru     nxt_conf_value_t            *applications, *application;
1487133Sigor@sysoev.ru     nxt_conf_value_t            *listeners, *listener;
14881936So.canty@f5.com     nxt_conf_value_t            *routes_conf, *static_conf, *client_ip_conf;
1489115Sigor@sysoev.ru     nxt_socket_conf_t           *skcf;
1490964Sigor@sysoev.ru     nxt_http_routes_t           *routes;
1491507Smax.romanov@nginx.com     nxt_event_engine_t          *engine;
1492216Sigor@sysoev.ru     nxt_app_lang_module_t       *lang;
1493133Sigor@sysoev.ru     nxt_router_app_conf_t       apcf;
1494630Svbart@nginx.com     nxt_router_access_log_t     *access_log;
1495115Sigor@sysoev.ru     nxt_router_listener_conf_t  lscf;
1496115Sigor@sysoev.ru 
1497716Svbart@nginx.com     static nxt_str_t  http_path = nxt_string("/settings/http");
1498133Sigor@sysoev.ru     static nxt_str_t  applications_path = nxt_string("/applications");
1499115Sigor@sysoev.ru     static nxt_str_t  listeners_path = nxt_string("/listeners");
1500964Sigor@sysoev.ru     static nxt_str_t  routes_path = nxt_string("/routes");
1501630Svbart@nginx.com     static nxt_str_t  access_log_path = nxt_string("/access_log");
1502774Svbart@nginx.com #if (NXT_TLS)
1503774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
15041885Sa.suvorov@f5.com     static nxt_str_t  conf_commands_path = nxt_string("/tls/conf_commands");
15051920Sa.suvorov@f5.com     static nxt_str_t  conf_cache_path = nxt_string("/tls/session/cache_size");
15061920Sa.suvorov@f5.com     static nxt_str_t  conf_timeout_path = nxt_string("/tls/session/timeout");
15071942Sa.suvorov@f5.com     static nxt_str_t  conf_tickets = nxt_string("/tls/session/tickets");
1508774Svbart@nginx.com #endif
15091183Svbart@nginx.com     static nxt_str_t  static_path = nxt_string("/settings/http/static");
15101131Smax.romanov@nginx.com     static nxt_str_t  websocket_path = nxt_string("/settings/http/websocket");
15111936So.canty@f5.com     static nxt_str_t  client_ip_path = nxt_string("/client_ip");
1512115Sigor@sysoev.ru 
1513208Svbart@nginx.com     conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1514115Sigor@sysoev.ru     if (conf == NULL) {
1515564Svbart@nginx.com         nxt_alert(task, "configuration parsing error");
1516115Sigor@sysoev.ru         return NXT_ERROR;
1517115Sigor@sysoev.ru     }
1518115Sigor@sysoev.ru 
1519591Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1520213Svbart@nginx.com 
1521213Svbart@nginx.com     ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1522591Sigor@sysoev.ru                               nxt_nitems(nxt_router_conf), tmcf->router_conf);
1523115Sigor@sysoev.ru     if (ret != NXT_OK) {
1524564Svbart@nginx.com         nxt_alert(task, "root map error");
1525115Sigor@sysoev.ru         return NXT_ERROR;
1526115Sigor@sysoev.ru     }
1527115Sigor@sysoev.ru 
1528591Sigor@sysoev.ru     if (tmcf->router_conf->threads == 0) {
1529591Sigor@sysoev.ru         tmcf->router_conf->threads = nxt_ncpu;
1530117Sigor@sysoev.ru     }
1531117Sigor@sysoev.ru 
15321183Svbart@nginx.com     static_conf = nxt_conf_get_path(conf, &static_path);
15331183Svbart@nginx.com 
15341183Svbart@nginx.com     ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
15351183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
15361183Svbart@nginx.com         return NXT_ERROR;
15371183Svbart@nginx.com     }
15381183Svbart@nginx.com 
15391115Svbart@nginx.com     router = tmcf->router_conf->router;
15401115Svbart@nginx.com 
1541133Sigor@sysoev.ru     applications = nxt_conf_get_path(conf, &applications_path);
15421115Svbart@nginx.com 
15431115Svbart@nginx.com     if (applications != NULL) {
15441115Svbart@nginx.com         next = 0;
15451115Svbart@nginx.com 
15461115Svbart@nginx.com         for ( ;; ) {
15471235Sigor@sysoev.ru             application = nxt_conf_next_object_member(applications,
15481235Sigor@sysoev.ru                                                       &name, &next);
15491115Svbart@nginx.com             if (application == NULL) {
15501115Svbart@nginx.com                 break;
15511115Svbart@nginx.com             }
15521115Svbart@nginx.com 
15531115Svbart@nginx.com             nxt_debug(task, "application \"%V\"", &name);
15541115Svbart@nginx.com 
15551115Svbart@nginx.com             size = nxt_conf_json_length(application, NULL);
15561115Svbart@nginx.com 
15571473Svbart@nginx.com             app_mp = nxt_mp_create(4096, 128, 1024, 64);
15581473Svbart@nginx.com             if (nxt_slow_path(app_mp == NULL)) {
15591473Svbart@nginx.com                 goto fail;
15601473Svbart@nginx.com             }
15611473Svbart@nginx.com 
15621473Svbart@nginx.com             app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size);
15631115Svbart@nginx.com             if (app == NULL) {
15641473Svbart@nginx.com                 goto app_fail;
15651115Svbart@nginx.com             }
15661115Svbart@nginx.com 
15671115Svbart@nginx.com             nxt_memzero(app, sizeof(nxt_app_t));
15681115Svbart@nginx.com 
15691473Svbart@nginx.com             app->mem_pool = app_mp;
15701473Svbart@nginx.com 
15711115Svbart@nginx.com             app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
15721115Svbart@nginx.com             app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
15731115Svbart@nginx.com                                                   + name.length);
15741115Svbart@nginx.com 
15751115Svbart@nginx.com             p = nxt_conf_json_print(app->conf.start, application, NULL);
15761115Svbart@nginx.com             app->conf.length = p - app->conf.start;
15771115Svbart@nginx.com 
15781115Svbart@nginx.com             nxt_assert(app->conf.length <= size);
15791115Svbart@nginx.com 
15801115Svbart@nginx.com             nxt_debug(task, "application conf \"%V\"", &app->conf);
15811115Svbart@nginx.com 
15821115Svbart@nginx.com             prev = nxt_router_app_find(&router->apps, &name);
15831115Svbart@nginx.com 
15841115Svbart@nginx.com             if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
15851473Svbart@nginx.com                 nxt_mp_destroy(app_mp);
15861115Svbart@nginx.com 
15871115Svbart@nginx.com                 nxt_queue_remove(&prev->link);
15881115Svbart@nginx.com                 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
15891563Svbart@nginx.com 
15901563Svbart@nginx.com                 ret = nxt_router_apps_hash_add(tmcf->router_conf, prev);
15911563Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
15921563Svbart@nginx.com                     goto fail;
15931563Svbart@nginx.com                 }
15941563Svbart@nginx.com 
15951115Svbart@nginx.com                 continue;
15961115Svbart@nginx.com             }
15971115Svbart@nginx.com 
15981115Svbart@nginx.com             apcf.processes = 1;
15991115Svbart@nginx.com             apcf.max_processes = 1;
16001115Svbart@nginx.com             apcf.spare_processes = 0;
16011115Svbart@nginx.com             apcf.timeout = 0;
16021115Svbart@nginx.com             apcf.idle_timeout = 15000;
16031115Svbart@nginx.com             apcf.limits_value = NULL;
16041115Svbart@nginx.com             apcf.processes_value = NULL;
16051473Svbart@nginx.com             apcf.targets_value = NULL;
16061115Svbart@nginx.com 
16071115Svbart@nginx.com             app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
16081115Svbart@nginx.com             if (nxt_slow_path(app_joint == NULL)) {
1609318Smax.romanov@nginx.com                 goto app_fail;
1610318Smax.romanov@nginx.com             }
1611318Smax.romanov@nginx.com 
16121115Svbart@nginx.com             nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
16131115Svbart@nginx.com 
16141115Svbart@nginx.com             ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
16151115Svbart@nginx.com                                       nxt_nitems(nxt_router_app_conf), &apcf);
1616318Smax.romanov@nginx.com             if (ret != NXT_OK) {
16171115Svbart@nginx.com                 nxt_alert(task, "application map error");
1618318Smax.romanov@nginx.com                 goto app_fail;
1619318Smax.romanov@nginx.com             }
16201115Svbart@nginx.com 
16211115Svbart@nginx.com             if (apcf.limits_value != NULL) {
16221115Svbart@nginx.com 
16231115Svbart@nginx.com                 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
16241115Svbart@nginx.com                     nxt_alert(task, "application limits is not object");
16251115Svbart@nginx.com                     goto app_fail;
16261115Svbart@nginx.com                 }
16271115Svbart@nginx.com 
16281115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.limits_value,
16291115Svbart@nginx.com                                         nxt_router_app_limits_conf,
16301115Svbart@nginx.com                                         nxt_nitems(nxt_router_app_limits_conf),
16311115Svbart@nginx.com                                         &apcf);
16321115Svbart@nginx.com                 if (ret != NXT_OK) {
16331115Svbart@nginx.com                     nxt_alert(task, "application limits map error");
16341115Svbart@nginx.com                     goto app_fail;
16351115Svbart@nginx.com                 }
16361115Svbart@nginx.com             }
16371115Svbart@nginx.com 
16381115Svbart@nginx.com             if (apcf.processes_value != NULL
16391115Svbart@nginx.com                 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
16401115Svbart@nginx.com             {
16411115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, apcf.processes_value,
16421115Svbart@nginx.com                                      nxt_router_app_processes_conf,
16431115Svbart@nginx.com                                      nxt_nitems(nxt_router_app_processes_conf),
16441115Svbart@nginx.com                                      &apcf);
16451115Svbart@nginx.com                 if (ret != NXT_OK) {
16461115Svbart@nginx.com                     nxt_alert(task, "application processes map error");
16471115Svbart@nginx.com                     goto app_fail;
16481115Svbart@nginx.com                 }
16491115Svbart@nginx.com 
16501115Svbart@nginx.com             } else {
16511115Svbart@nginx.com                 apcf.max_processes = apcf.processes;
16521115Svbart@nginx.com                 apcf.spare_processes = apcf.processes;
16531115Svbart@nginx.com             }
16541115Svbart@nginx.com 
16551473Svbart@nginx.com             if (apcf.targets_value != NULL) {
16561473Svbart@nginx.com                 n = nxt_conf_object_members_count(apcf.targets_value);
16571473Svbart@nginx.com 
16581473Svbart@nginx.com                 targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n);
16591473Svbart@nginx.com                 if (nxt_slow_path(targets == NULL)) {
16601473Svbart@nginx.com                     goto app_fail;
16611473Svbart@nginx.com                 }
16621473Svbart@nginx.com 
16631473Svbart@nginx.com                 next_target = 0;
16641473Svbart@nginx.com 
16651473Svbart@nginx.com                 for (i = 0; i < n; i++) {
16661480Svbart@nginx.com                     (void) nxt_conf_next_object_member(apcf.targets_value,
16671480Svbart@nginx.com                                                        &target, &next_target);
16681473Svbart@nginx.com 
16691473Svbart@nginx.com                     s = nxt_str_dup(app_mp, &targets[i], &target);
16701473Svbart@nginx.com                     if (nxt_slow_path(s == NULL)) {
16711473Svbart@nginx.com                         goto app_fail;
16721473Svbart@nginx.com                     }
16731473Svbart@nginx.com                 }
16741473Svbart@nginx.com 
16751473Svbart@nginx.com             } else {
16761473Svbart@nginx.com                 targets = NULL;
16771473Svbart@nginx.com             }
16781473Svbart@nginx.com 
16791115Svbart@nginx.com             nxt_debug(task, "application type: %V", &apcf.type);
16801115Svbart@nginx.com             nxt_debug(task, "application processes: %D", apcf.processes);
16811115Svbart@nginx.com             nxt_debug(task, "application request timeout: %M", apcf.timeout);
16821115Svbart@nginx.com 
16831115Svbart@nginx.com             lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
16841115Svbart@nginx.com 
16851115Svbart@nginx.com             if (lang == NULL) {
16861115Svbart@nginx.com                 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1687507Smax.romanov@nginx.com                 goto app_fail;
1688507Smax.romanov@nginx.com             }
1689507Smax.romanov@nginx.com 
16901115Svbart@nginx.com             nxt_debug(task, "application language module: \"%s\"", lang->file);
16911115Svbart@nginx.com 
16921115Svbart@nginx.com             ret = nxt_thread_mutex_create(&app->mutex);
16931115Svbart@nginx.com             if (ret != NXT_OK) {
16941115Svbart@nginx.com                 goto app_fail;
16951115Svbart@nginx.com             }
16961115Svbart@nginx.com 
16971115Svbart@nginx.com             nxt_queue_init(&app->ports);
16981115Svbart@nginx.com             nxt_queue_init(&app->spare_ports);
16991115Svbart@nginx.com             nxt_queue_init(&app->idle_ports);
17001561Smax.romanov@nginx.com             nxt_queue_init(&app->ack_waiting_req);
17011115Svbart@nginx.com 
17021115Svbart@nginx.com             app->name.length = name.length;
17031115Svbart@nginx.com             nxt_memcpy(app->name.start, name.start, name.length);
17041115Svbart@nginx.com 
17051115Svbart@nginx.com             app->type = lang->type;
17061115Svbart@nginx.com             app->max_processes = apcf.max_processes;
17071115Svbart@nginx.com             app->spare_processes = apcf.spare_processes;
17081115Svbart@nginx.com             app->max_pending_processes = apcf.spare_processes
17091115Svbart@nginx.com                                          ? apcf.spare_processes : 1;
17101115Svbart@nginx.com             app->timeout = apcf.timeout;
17111115Svbart@nginx.com             app->idle_timeout = apcf.idle_timeout;
17121115Svbart@nginx.com 
17131473Svbart@nginx.com             app->targets = targets;
17141473Svbart@nginx.com 
17151115Svbart@nginx.com             engine = task->thread->engine;
17161115Svbart@nginx.com 
17171115Svbart@nginx.com             app->engine = engine;
17181115Svbart@nginx.com 
17191115Svbart@nginx.com             app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
17201115Svbart@nginx.com             app->adjust_idle_work.task = &engine->task;
17211115Svbart@nginx.com             app->adjust_idle_work.obj = app;
17221115Svbart@nginx.com 
17231115Svbart@nginx.com             nxt_queue_insert_tail(&tmcf->apps, &app->link);
17241115Svbart@nginx.com 
17251563Svbart@nginx.com             ret = nxt_router_apps_hash_add(tmcf->router_conf, app);
17261563Svbart@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
17271563Svbart@nginx.com                 goto app_fail;
17281563Svbart@nginx.com             }
17291563Svbart@nginx.com 
17301115Svbart@nginx.com             nxt_router_app_use(task, app, 1);
17311115Svbart@nginx.com 
17321115Svbart@nginx.com             app->joint = app_joint;
17331115Svbart@nginx.com 
17341115Svbart@nginx.com             app_joint->use_count = 1;
17351115Svbart@nginx.com             app_joint->app = app;
17361115Svbart@nginx.com 
17371115Svbart@nginx.com             app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
17381115Svbart@nginx.com             app_joint->idle_timer.work_queue = &engine->fast_work_queue;
17391115Svbart@nginx.com             app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
17401115Svbart@nginx.com             app_joint->idle_timer.task = &engine->task;
17411115Svbart@nginx.com             app_joint->idle_timer.log = app_joint->idle_timer.task->log;
17421115Svbart@nginx.com 
17431115Svbart@nginx.com             app_joint->free_app_work.handler = nxt_router_free_app;
17441115Svbart@nginx.com             app_joint->free_app_work.task = &engine->task;
17451115Svbart@nginx.com             app_joint->free_app_work.obj = app_joint;
17461547Smax.romanov@nginx.com 
17471926Smax.romanov@nginx.com             port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
17481547Smax.romanov@nginx.com                                 NXT_PROCESS_APP);
17491547Smax.romanov@nginx.com             if (nxt_slow_path(port == NULL)) {
17501547Smax.romanov@nginx.com                 return NXT_ERROR;
17511547Smax.romanov@nginx.com             }
17521547Smax.romanov@nginx.com 
17531547Smax.romanov@nginx.com             ret = nxt_port_socket_init(task, port, 0);
17541547Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
17551547Smax.romanov@nginx.com                 nxt_port_use(task, port, -1);
17561547Smax.romanov@nginx.com                 return NXT_ERROR;
17571547Smax.romanov@nginx.com             }
17581547Smax.romanov@nginx.com 
17591555Smax.romanov@nginx.com             ret = nxt_router_app_queue_init(task, port);
17601555Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
17611777Smax.romanov@nginx.com                 nxt_port_write_close(port);
17621777Smax.romanov@nginx.com                 nxt_port_read_close(port);
17631555Smax.romanov@nginx.com                 nxt_port_use(task, port, -1);
17641555Smax.romanov@nginx.com                 return NXT_ERROR;
17651555Smax.romanov@nginx.com             }
17661555Smax.romanov@nginx.com 
17671547Smax.romanov@nginx.com             nxt_port_write_enable(task, port);
17681547Smax.romanov@nginx.com             port->app = app;
17691547Smax.romanov@nginx.com 
17701547Smax.romanov@nginx.com             app->shared_port = port;
17711547Smax.romanov@nginx.com 
17721547Smax.romanov@nginx.com             nxt_thread_mutex_create(&app->outgoing.mutex);
1773133Sigor@sysoev.ru         }
1774133Sigor@sysoev.ru     }
1775133Sigor@sysoev.ru 
1776964Sigor@sysoev.ru     routes_conf = nxt_conf_get_path(conf, &routes_path);
1777964Sigor@sysoev.ru     if (nxt_fast_path(routes_conf != NULL)) {
1778964Sigor@sysoev.ru         routes = nxt_http_routes_create(task, tmcf, routes_conf);
1779964Sigor@sysoev.ru         if (nxt_slow_path(routes == NULL)) {
1780964Sigor@sysoev.ru             return NXT_ERROR;
1781964Sigor@sysoev.ru         }
1782964Sigor@sysoev.ru         tmcf->router_conf->routes = routes;
1783964Sigor@sysoev.ru     }
1784964Sigor@sysoev.ru 
17851394Sigor@sysoev.ru     ret = nxt_upstreams_create(task, tmcf, conf);
17861394Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
17871394Sigor@sysoev.ru         return ret;
17881394Sigor@sysoev.ru     }
17891394Sigor@sysoev.ru 
1790133Sigor@sysoev.ru     http = nxt_conf_get_path(conf, &http_path);
1791133Sigor@sysoev.ru #if 0
1792133Sigor@sysoev.ru     if (http == NULL) {
1793564Svbart@nginx.com         nxt_alert(task, "no \"http\" block");
1794133Sigor@sysoev.ru         return NXT_ERROR;
1795133Sigor@sysoev.ru     }
1796133Sigor@sysoev.ru #endif
1797133Sigor@sysoev.ru 
17981131Smax.romanov@nginx.com     websocket = nxt_conf_get_path(conf, &websocket_path);
17991131Smax.romanov@nginx.com 
1800133Sigor@sysoev.ru     listeners = nxt_conf_get_path(conf, &listeners_path);
18011115Svbart@nginx.com 
18021115Svbart@nginx.com     if (listeners != NULL) {
18031115Svbart@nginx.com         next = 0;
18041115Svbart@nginx.com 
18051115Svbart@nginx.com         for ( ;; ) {
18061115Svbart@nginx.com             listener = nxt_conf_next_object_member(listeners, &name, &next);
18071115Svbart@nginx.com             if (listener == NULL) {
18081115Svbart@nginx.com                 break;
18091115Svbart@nginx.com             }
18101115Svbart@nginx.com 
18111115Svbart@nginx.com             skcf = nxt_router_socket_conf(task, tmcf, &name);
18121115Svbart@nginx.com             if (skcf == NULL) {
18131115Svbart@nginx.com                 goto fail;
18141115Svbart@nginx.com             }
18151115Svbart@nginx.com 
18161115Svbart@nginx.com             nxt_memzero(&lscf, sizeof(lscf));
18171115Svbart@nginx.com 
18181115Svbart@nginx.com             ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
18191115Svbart@nginx.com                                       nxt_nitems(nxt_router_listener_conf),
18201115Svbart@nginx.com                                       &lscf);
1821133Sigor@sysoev.ru             if (ret != NXT_OK) {
18221115Svbart@nginx.com                 nxt_alert(task, "listener map error");
1823133Sigor@sysoev.ru                 goto fail;
1824133Sigor@sysoev.ru             }
18251115Svbart@nginx.com 
18261115Svbart@nginx.com             nxt_debug(task, "application: %V", &lscf.application);
18271115Svbart@nginx.com 
18281115Svbart@nginx.com             // STUB, default values if http block is not defined.
18291115Svbart@nginx.com             skcf->header_buffer_size = 2048;
18301115Svbart@nginx.com             skcf->large_header_buffer_size = 8192;
18311115Svbart@nginx.com             skcf->large_header_buffers = 4;
18321709Svbart@nginx.com             skcf->discard_unsafe_fields = 1;
18331115Svbart@nginx.com             skcf->body_buffer_size = 16 * 1024;
18341115Svbart@nginx.com             skcf->max_body_size = 8 * 1024 * 1024;
18351270Sigor@sysoev.ru             skcf->proxy_header_buffer_size = 64 * 1024;
18361270Sigor@sysoev.ru             skcf->proxy_buffer_size = 4096;
18371270Sigor@sysoev.ru             skcf->proxy_buffers = 256;
18381115Svbart@nginx.com             skcf->idle_timeout = 180 * 1000;
18391115Svbart@nginx.com             skcf->header_read_timeout = 30 * 1000;
18401115Svbart@nginx.com             skcf->body_read_timeout = 30 * 1000;
18411115Svbart@nginx.com             skcf->send_timeout = 30 * 1000;
18421270Sigor@sysoev.ru             skcf->proxy_timeout = 60 * 1000;
18431270Sigor@sysoev.ru             skcf->proxy_send_timeout = 30 * 1000;
18441270Sigor@sysoev.ru             skcf->proxy_read_timeout = 30 * 1000;
18451115Svbart@nginx.com 
18461131Smax.romanov@nginx.com             skcf->websocket_conf.max_frame_size = 1024 * 1024;
18471131Smax.romanov@nginx.com             skcf->websocket_conf.read_timeout = 60 * 1000;
18481131Smax.romanov@nginx.com             skcf->websocket_conf.keepalive_interval = 30 * 1000;
18491131Smax.romanov@nginx.com 
18501403Smax.romanov@nginx.com             nxt_str_null(&skcf->body_temp_path);
18511403Smax.romanov@nginx.com 
18521115Svbart@nginx.com             if (http != NULL) {
18531115Svbart@nginx.com                 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
18541115Svbart@nginx.com                                           nxt_nitems(nxt_router_http_conf),
18551115Svbart@nginx.com                                           skcf);
18561115Svbart@nginx.com                 if (ret != NXT_OK) {
18571115Svbart@nginx.com                     nxt_alert(task, "http map error");
18581115Svbart@nginx.com                     goto fail;
18591115Svbart@nginx.com                 }
18601115Svbart@nginx.com             }
1861115Sigor@sysoev.ru 
18621131Smax.romanov@nginx.com             if (websocket != NULL) {
18631131Smax.romanov@nginx.com                 ret = nxt_conf_map_object(mp, websocket,
18641131Smax.romanov@nginx.com                                           nxt_router_websocket_conf,
18651131Smax.romanov@nginx.com                                           nxt_nitems(nxt_router_websocket_conf),
18661131Smax.romanov@nginx.com                                           &skcf->websocket_conf);
18671131Smax.romanov@nginx.com                 if (ret != NXT_OK) {
18681131Smax.romanov@nginx.com                     nxt_alert(task, "websocket map error");
18691131Smax.romanov@nginx.com                     goto fail;
18701131Smax.romanov@nginx.com                 }
18711131Smax.romanov@nginx.com             }
18721131Smax.romanov@nginx.com 
18731403Smax.romanov@nginx.com             t = &skcf->body_temp_path;
18741403Smax.romanov@nginx.com 
18751403Smax.romanov@nginx.com             if (t->length == 0) {
18761403Smax.romanov@nginx.com                 t->start = (u_char *) task->thread->runtime->tmp;
18771403Smax.romanov@nginx.com                 t->length = nxt_strlen(t->start);
18781403Smax.romanov@nginx.com             }
18791403Smax.romanov@nginx.com 
18801936So.canty@f5.com             client_ip_conf = nxt_conf_get_path(listener, &client_ip_path);
18811936So.canty@f5.com             ret = nxt_router_conf_process_client_ip(task, tmcf, skcf,
18821936So.canty@f5.com                                                     client_ip_conf);
18831936So.canty@f5.com             if (nxt_slow_path(ret != NXT_OK)) {
18841936So.canty@f5.com                 return NXT_ERROR;
18851936So.canty@f5.com             }
18861936So.canty@f5.com 
1887774Svbart@nginx.com #if (NXT_TLS)
18881828Sa.suvorov@f5.com             certificate = nxt_conf_get_path(listener, &certificate_path);
18891828Sa.suvorov@f5.com 
18901828Sa.suvorov@f5.com             if (certificate != NULL) {
18911920Sa.suvorov@f5.com                 tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t));
18921920Sa.suvorov@f5.com                 if (nxt_slow_path(tls_init == NULL)) {
18931920Sa.suvorov@f5.com                     return NXT_ERROR;
18941920Sa.suvorov@f5.com                 }
18951920Sa.suvorov@f5.com 
18961920Sa.suvorov@f5.com                 tls_init->cache_size = 0;
18971920Sa.suvorov@f5.com                 tls_init->timeout = 300;
18981920Sa.suvorov@f5.com 
18991920Sa.suvorov@f5.com                 value = nxt_conf_get_path(listener, &conf_cache_path);
19001920Sa.suvorov@f5.com                 if (value != NULL) {
19011920Sa.suvorov@f5.com                     tls_init->cache_size = nxt_conf_get_number(value);
19021920Sa.suvorov@f5.com                 }
19031920Sa.suvorov@f5.com 
19041920Sa.suvorov@f5.com                 value = nxt_conf_get_path(listener, &conf_timeout_path);
19051920Sa.suvorov@f5.com                 if (value != NULL) {
19061920Sa.suvorov@f5.com                     tls_init->timeout = nxt_conf_get_number(value);
19071920Sa.suvorov@f5.com                 }
19081920Sa.suvorov@f5.com 
19091920Sa.suvorov@f5.com                 tls_init->conf_cmds = nxt_conf_get_path(listener,
19101920Sa.suvorov@f5.com                                                         &conf_commands_path);
19111885Sa.suvorov@f5.com 
19121942Sa.suvorov@f5.com                 tls_init->tickets_conf = nxt_conf_get_path(listener,
19131942Sa.suvorov@f5.com                                                            &conf_tickets);
19141942Sa.suvorov@f5.com 
19151828Sa.suvorov@f5.com                 if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) {
19161828Sa.suvorov@f5.com                     n = nxt_conf_array_elements_count(certificate);
19171828Sa.suvorov@f5.com 
19181828Sa.suvorov@f5.com                     for (i = 0; i < n; i++) {
19191828Sa.suvorov@f5.com                         value = nxt_conf_get_array_element(certificate, i);
19201828Sa.suvorov@f5.com 
19211828Sa.suvorov@f5.com                         nxt_assert(value != NULL);
19221828Sa.suvorov@f5.com 
19231885Sa.suvorov@f5.com                         ret = nxt_router_conf_tls_insert(tmcf, value, skcf,
19241920Sa.suvorov@f5.com                                                          tls_init, i == 0);
19251828Sa.suvorov@f5.com                         if (nxt_slow_path(ret != NXT_OK)) {
19261828Sa.suvorov@f5.com                             goto fail;
19271828Sa.suvorov@f5.com                         }
19281828Sa.suvorov@f5.com                     }
19291828Sa.suvorov@f5.com 
19301828Sa.suvorov@f5.com                 } else {
19311828Sa.suvorov@f5.com                     /* NXT_CONF_STRING */
19321885Sa.suvorov@f5.com                     ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf,
19331920Sa.suvorov@f5.com                                                      tls_init, 1);
19341828Sa.suvorov@f5.com                     if (nxt_slow_path(ret != NXT_OK)) {
19351828Sa.suvorov@f5.com                         goto fail;
19361828Sa.suvorov@f5.com                     }
19371115Svbart@nginx.com                 }
1938774Svbart@nginx.com             }
1939774Svbart@nginx.com #endif
1940774Svbart@nginx.com 
19411115Svbart@nginx.com             skcf->listen->handler = nxt_http_conn_init;
19421115Svbart@nginx.com             skcf->router_conf = tmcf->router_conf;
19431115Svbart@nginx.com             skcf->router_conf->count++;
19441115Svbart@nginx.com 
19451115Svbart@nginx.com             if (lscf.pass.length != 0) {
19461264Sigor@sysoev.ru                 skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass);
19471115Svbart@nginx.com 
19481115Svbart@nginx.com             /* COMPATIBILITY: listener application. */
19491115Svbart@nginx.com             } else if (lscf.application.length > 0) {
19501563Svbart@nginx.com                 skcf->action = nxt_http_pass_application(task,
19511563Svbart@nginx.com                                                          tmcf->router_conf,
19521264Sigor@sysoev.ru                                                          &lscf.application);
19531115Svbart@nginx.com             }
19541597Shongzhidao@gmail.com 
19551597Shongzhidao@gmail.com             if (nxt_slow_path(skcf->action == NULL)) {
19561597Shongzhidao@gmail.com                 goto fail;
19571597Shongzhidao@gmail.com             }
1958770Smax.romanov@nginx.com         }
1959115Sigor@sysoev.ru     }
196053Sigor@sysoev.ru 
19611472Svbart@nginx.com     ret = nxt_http_routes_resolve(task, tmcf);
19621472Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
19631472Svbart@nginx.com         goto fail;
19641472Svbart@nginx.com     }
19651472Svbart@nginx.com 
1966630Svbart@nginx.com     value = nxt_conf_get_path(conf, &access_log_path);
1967630Svbart@nginx.com 
1968630Svbart@nginx.com     if (value != NULL) {
1969630Svbart@nginx.com         nxt_conf_get_string(value, &path);
1970630Svbart@nginx.com 
1971630Svbart@nginx.com         access_log = router->access_log;
1972630Svbart@nginx.com 
1973630Svbart@nginx.com         if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1974630Svbart@nginx.com             nxt_thread_spin_lock(&router->lock);
1975630Svbart@nginx.com             access_log->count++;
1976630Svbart@nginx.com             nxt_thread_spin_unlock(&router->lock);
1977630Svbart@nginx.com 
1978630Svbart@nginx.com         } else {
1979630Svbart@nginx.com             access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1980630Svbart@nginx.com                                     + path.length);
1981630Svbart@nginx.com             if (access_log == NULL) {
1982630Svbart@nginx.com                 nxt_alert(task, "failed to allocate access log structure");
1983630Svbart@nginx.com                 goto fail;
1984630Svbart@nginx.com             }
1985630Svbart@nginx.com 
1986630Svbart@nginx.com             access_log->fd = -1;
1987630Svbart@nginx.com             access_log->handler = &nxt_router_access_log_writer;
1988630Svbart@nginx.com             access_log->count = 1;
1989630Svbart@nginx.com 
1990630Svbart@nginx.com             access_log->path.length = path.length;
1991630Svbart@nginx.com             access_log->path.start = (u_char *) access_log
1992630Svbart@nginx.com                                      + sizeof(nxt_router_access_log_t);
1993630Svbart@nginx.com 
1994630Svbart@nginx.com             nxt_memcpy(access_log->path.start, path.start, path.length);
1995630Svbart@nginx.com         }
1996630Svbart@nginx.com 
1997630Svbart@nginx.com         tmcf->router_conf->access_log = access_log;
1998630Svbart@nginx.com     }
1999630Svbart@nginx.com 
20001509Sigor@sysoev.ru     nxt_queue_add(&deleting_sockets, &router->sockets);
2001359Sigor@sysoev.ru     nxt_queue_init(&router->sockets);
2002198Sigor@sysoev.ru 
200353Sigor@sysoev.ru     return NXT_OK;
2004133Sigor@sysoev.ru 
2005133Sigor@sysoev.ru app_fail:
2006133Sigor@sysoev.ru 
20071473Svbart@nginx.com     nxt_mp_destroy(app_mp);
2008133Sigor@sysoev.ru 
2009133Sigor@sysoev.ru fail:
2010133Sigor@sysoev.ru 
2011141Smax.romanov@nginx.com     nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
2012141Smax.romanov@nginx.com 
2013141Smax.romanov@nginx.com         nxt_queue_remove(&app->link);
2014133Sigor@sysoev.ru         nxt_thread_mutex_destroy(&app->mutex);
20151473Svbart@nginx.com         nxt_mp_destroy(app->mem_pool);
2016141Smax.romanov@nginx.com 
2017141Smax.romanov@nginx.com     } nxt_queue_loop;
2018133Sigor@sysoev.ru 
2019133Sigor@sysoev.ru     return NXT_ERROR;
2020133Sigor@sysoev.ru }
2021133Sigor@sysoev.ru 
2022133Sigor@sysoev.ru 
20231828Sa.suvorov@f5.com #if (NXT_TLS)
20241828Sa.suvorov@f5.com 
20251828Sa.suvorov@f5.com static nxt_int_t
20261828Sa.suvorov@f5.com nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
20271885Sa.suvorov@f5.com     nxt_conf_value_t *value, nxt_socket_conf_t *skcf,
20281920Sa.suvorov@f5.com     nxt_tls_init_t *tls_init, nxt_bool_t last)
20291828Sa.suvorov@f5.com {
20301828Sa.suvorov@f5.com     nxt_router_tlssock_t  *tls;
20311828Sa.suvorov@f5.com 
20321885Sa.suvorov@f5.com     tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t));
20331828Sa.suvorov@f5.com     if (nxt_slow_path(tls == NULL)) {
20341828Sa.suvorov@f5.com         return NXT_ERROR;
20351828Sa.suvorov@f5.com     }
20361828Sa.suvorov@f5.com 
20371920Sa.suvorov@f5.com     tls->tls_init = tls_init;
20381885Sa.suvorov@f5.com     tls->socket_conf = skcf;
20391885Sa.suvorov@f5.com     tls->temp_conf = tmcf;
20401904Smax.romanov@nginx.com     tls->last = last;
20411885Sa.suvorov@f5.com     nxt_conf_get_string(value, &tls->name);
20421828Sa.suvorov@f5.com 
20431828Sa.suvorov@f5.com     nxt_queue_insert_tail(&tmcf->tls, &tls->link);
20441828Sa.suvorov@f5.com 
20451828Sa.suvorov@f5.com     return NXT_OK;
20461828Sa.suvorov@f5.com }
20471828Sa.suvorov@f5.com 
20481828Sa.suvorov@f5.com #endif
20491828Sa.suvorov@f5.com 
20501828Sa.suvorov@f5.com 
20511183Svbart@nginx.com static nxt_int_t
20521183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
20531183Svbart@nginx.com     nxt_conf_value_t *conf)
20541183Svbart@nginx.com {
20551183Svbart@nginx.com     uint32_t          next, i;
20561183Svbart@nginx.com     nxt_mp_t          *mp;
20571923Sz.hong@f5.com     nxt_str_t         *type, exten, str;
20581183Svbart@nginx.com     nxt_int_t         ret;
20591183Svbart@nginx.com     nxt_uint_t        exts;
20601183Svbart@nginx.com     nxt_conf_value_t  *mtypes_conf, *ext_conf, *value;
20611183Svbart@nginx.com 
20621183Svbart@nginx.com     static nxt_str_t  mtypes_path = nxt_string("/mime_types");
20631183Svbart@nginx.com 
20641183Svbart@nginx.com     mp = rtcf->mem_pool;
20651183Svbart@nginx.com 
20661183Svbart@nginx.com     ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
20671183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
20681183Svbart@nginx.com         return NXT_ERROR;
20691183Svbart@nginx.com     }
20701183Svbart@nginx.com 
20711183Svbart@nginx.com     if (conf == NULL) {
20721183Svbart@nginx.com         return NXT_OK;
20731183Svbart@nginx.com     }
20741183Svbart@nginx.com 
20751183Svbart@nginx.com     mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
20761183Svbart@nginx.com 
20771183Svbart@nginx.com     if (mtypes_conf != NULL) {
20781183Svbart@nginx.com         next = 0;
20791183Svbart@nginx.com 
20801183Svbart@nginx.com         for ( ;; ) {
20811183Svbart@nginx.com             ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
20821183Svbart@nginx.com 
20831183Svbart@nginx.com             if (ext_conf == NULL) {
20841183Svbart@nginx.com                 break;
20851183Svbart@nginx.com             }
20861183Svbart@nginx.com 
20871183Svbart@nginx.com             type = nxt_str_dup(mp, NULL, &str);
20881183Svbart@nginx.com             if (nxt_slow_path(type == NULL)) {
20891183Svbart@nginx.com                 return NXT_ERROR;
20901183Svbart@nginx.com             }
20911183Svbart@nginx.com 
20921183Svbart@nginx.com             if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
20931183Svbart@nginx.com                 nxt_conf_get_string(ext_conf, &str);
20941183Svbart@nginx.com 
20951923Sz.hong@f5.com                 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
20961183Svbart@nginx.com                     return NXT_ERROR;
20971183Svbart@nginx.com                 }
20981183Svbart@nginx.com 
20991183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
21001923Sz.hong@f5.com                                                       &exten, type);
21011183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
21021183Svbart@nginx.com                     return NXT_ERROR;
21031183Svbart@nginx.com                 }
21041183Svbart@nginx.com 
21051183Svbart@nginx.com                 continue;
21061183Svbart@nginx.com             }
21071183Svbart@nginx.com 
21081183Svbart@nginx.com             exts = nxt_conf_array_elements_count(ext_conf);
21091183Svbart@nginx.com 
21101183Svbart@nginx.com             for (i = 0; i < exts; i++) {
21111183Svbart@nginx.com                 value = nxt_conf_get_array_element(ext_conf, i);
21121183Svbart@nginx.com 
21131183Svbart@nginx.com                 nxt_conf_get_string(value, &str);
21141183Svbart@nginx.com 
21151923Sz.hong@f5.com                 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
21161183Svbart@nginx.com                     return NXT_ERROR;
21171183Svbart@nginx.com                 }
21181183Svbart@nginx.com 
21191183Svbart@nginx.com                 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
21201923Sz.hong@f5.com                                                       &exten, type);
21211183Svbart@nginx.com                 if (nxt_slow_path(ret != NXT_OK)) {
21221183Svbart@nginx.com                     return NXT_ERROR;
21231183Svbart@nginx.com                 }
21241183Svbart@nginx.com             }
21251183Svbart@nginx.com         }
21261183Svbart@nginx.com     }
21271183Svbart@nginx.com 
21281183Svbart@nginx.com     return NXT_OK;
21291183Svbart@nginx.com }
21301183Svbart@nginx.com 
21311183Svbart@nginx.com 
21321936So.canty@f5.com static nxt_int_t
21331936So.canty@f5.com nxt_router_conf_process_client_ip(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
21341936So.canty@f5.com     nxt_socket_conf_t *skcf, nxt_conf_value_t *conf)
21351936So.canty@f5.com {
21361936So.canty@f5.com     char                        c;
21371936So.canty@f5.com     size_t                      i;
21381936So.canty@f5.com     nxt_mp_t                    *mp;
21391936So.canty@f5.com     uint32_t                    hash;
21401936So.canty@f5.com     nxt_str_t                   header;
21411936So.canty@f5.com     nxt_conf_value_t            *source_conf, *header_conf, *recursive_conf;
21421936So.canty@f5.com     nxt_http_client_ip_t        *client_ip;
21431936So.canty@f5.com     nxt_http_route_addr_rule_t  *source;
21441936So.canty@f5.com 
21451936So.canty@f5.com     static nxt_str_t  header_path = nxt_string("/header");
21461936So.canty@f5.com     static nxt_str_t  source_path = nxt_string("/source");
21471936So.canty@f5.com     static nxt_str_t  recursive_path = nxt_string("/recursive");
21481936So.canty@f5.com 
21491936So.canty@f5.com     if (conf == NULL) {
21501936So.canty@f5.com         skcf->client_ip = NULL;
21511936So.canty@f5.com 
21521936So.canty@f5.com         return NXT_OK;
21531936So.canty@f5.com     }
21541936So.canty@f5.com 
21551936So.canty@f5.com     mp = tmcf->router_conf->mem_pool;
21561936So.canty@f5.com 
21571936So.canty@f5.com     source_conf = nxt_conf_get_path(conf, &source_path);
21581936So.canty@f5.com     header_conf = nxt_conf_get_path(conf, &header_path);
21591936So.canty@f5.com     recursive_conf = nxt_conf_get_path(conf, &recursive_path);
21601936So.canty@f5.com 
21611936So.canty@f5.com     if (source_conf == NULL || header_conf == NULL) {
21621936So.canty@f5.com         return NXT_ERROR;
21631936So.canty@f5.com     }
21641936So.canty@f5.com 
21651936So.canty@f5.com     client_ip = nxt_mp_zget(mp, sizeof(nxt_http_client_ip_t));
21661936So.canty@f5.com     if (nxt_slow_path(client_ip == NULL)) {
21671936So.canty@f5.com         return NXT_ERROR;
21681936So.canty@f5.com     }
21691936So.canty@f5.com 
21701936So.canty@f5.com     source = nxt_http_route_addr_rule_create(task, mp, source_conf);
21711936So.canty@f5.com     if (nxt_slow_path(source == NULL)) {
21721936So.canty@f5.com         return NXT_ERROR;
21731936So.canty@f5.com     }
21741936So.canty@f5.com 
21751936So.canty@f5.com     client_ip->source = source;
21761936So.canty@f5.com 
21771936So.canty@f5.com     nxt_conf_get_string(header_conf, &header);
21781936So.canty@f5.com 
21791936So.canty@f5.com     if (recursive_conf != NULL) {
21801936So.canty@f5.com         client_ip->recursive = nxt_conf_get_boolean(recursive_conf);
21811936So.canty@f5.com     }
21821936So.canty@f5.com 
21831936So.canty@f5.com     client_ip->header = nxt_str_dup(mp, NULL, &header);
21841936So.canty@f5.com     if (nxt_slow_path(client_ip->header == NULL)) {
21851936So.canty@f5.com         return NXT_ERROR;
21861936So.canty@f5.com     }
21871936So.canty@f5.com 
21881936So.canty@f5.com     hash = NXT_HTTP_FIELD_HASH_INIT;
21891936So.canty@f5.com 
21901936So.canty@f5.com     for (i = 0; i < client_ip->header->length; i++) {
21911936So.canty@f5.com         c = client_ip->header->start[i];
21921936So.canty@f5.com         hash = nxt_http_field_hash_char(hash, nxt_lowcase(c));
21931936So.canty@f5.com     }
21941936So.canty@f5.com 
21951936So.canty@f5.com     hash = nxt_http_field_hash_end(hash) & 0xFFFF;
21961936So.canty@f5.com 
21971936So.canty@f5.com     client_ip->header_hash = hash;
21981936So.canty@f5.com 
21991936So.canty@f5.com     skcf->client_ip = client_ip;
22001936So.canty@f5.com 
22011936So.canty@f5.com     return NXT_OK;
22021936So.canty@f5.com }
22031936So.canty@f5.com 
22041936So.canty@f5.com 
2205133Sigor@sysoev.ru static nxt_app_t *
2206133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
2207133Sigor@sysoev.ru {
2208141Smax.romanov@nginx.com     nxt_app_t  *app;
2209141Smax.romanov@nginx.com 
2210141Smax.romanov@nginx.com     nxt_queue_each(app, queue, nxt_app_t, link) {
2211133Sigor@sysoev.ru 
2212133Sigor@sysoev.ru         if (nxt_strstr_eq(name, &app->name)) {
2213133Sigor@sysoev.ru             return app;
2214133Sigor@sysoev.ru         }
2215141Smax.romanov@nginx.com 
2216141Smax.romanov@nginx.com     } nxt_queue_loop;
2217133Sigor@sysoev.ru 
2218133Sigor@sysoev.ru     return NULL;
2219133Sigor@sysoev.ru }
2220133Sigor@sysoev.ru 
2221133Sigor@sysoev.ru 
22221555Smax.romanov@nginx.com static nxt_int_t
22231555Smax.romanov@nginx.com nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port)
22241555Smax.romanov@nginx.com {
22251555Smax.romanov@nginx.com     void       *mem;
22261555Smax.romanov@nginx.com     nxt_int_t  fd;
22271555Smax.romanov@nginx.com 
22281555Smax.romanov@nginx.com     fd = nxt_shm_open(task, sizeof(nxt_app_queue_t));
22291555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
22301555Smax.romanov@nginx.com         return NXT_ERROR;
22311555Smax.romanov@nginx.com     }
22321555Smax.romanov@nginx.com 
22331555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t),
22341555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
22351555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
22361555Smax.romanov@nginx.com         nxt_fd_close(fd);
22371555Smax.romanov@nginx.com 
22381555Smax.romanov@nginx.com         return NXT_ERROR;
22391555Smax.romanov@nginx.com     }
22401555Smax.romanov@nginx.com 
22411555Smax.romanov@nginx.com     nxt_app_queue_init(mem);
22421555Smax.romanov@nginx.com 
22431555Smax.romanov@nginx.com     port->queue_fd = fd;
22441555Smax.romanov@nginx.com     port->queue = mem;
22451555Smax.romanov@nginx.com 
22461555Smax.romanov@nginx.com     return NXT_OK;
22471555Smax.romanov@nginx.com }
22481555Smax.romanov@nginx.com 
22491555Smax.romanov@nginx.com 
22501555Smax.romanov@nginx.com static nxt_int_t
22511555Smax.romanov@nginx.com nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port)
22521555Smax.romanov@nginx.com {
22531555Smax.romanov@nginx.com     void       *mem;
22541555Smax.romanov@nginx.com     nxt_int_t  fd;
22551555Smax.romanov@nginx.com 
22561555Smax.romanov@nginx.com     fd = nxt_shm_open(task, sizeof(nxt_port_queue_t));
22571555Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
22581555Smax.romanov@nginx.com         return NXT_ERROR;
22591555Smax.romanov@nginx.com     }
22601555Smax.romanov@nginx.com 
22611555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
22621555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
22631555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
22641555Smax.romanov@nginx.com         nxt_fd_close(fd);
22651555Smax.romanov@nginx.com 
22661555Smax.romanov@nginx.com         return NXT_ERROR;
22671555Smax.romanov@nginx.com     }
22681555Smax.romanov@nginx.com 
22691555Smax.romanov@nginx.com     nxt_port_queue_init(mem);
22701555Smax.romanov@nginx.com 
22711555Smax.romanov@nginx.com     port->queue_fd = fd;
22721555Smax.romanov@nginx.com     port->queue = mem;
22731555Smax.romanov@nginx.com 
22741555Smax.romanov@nginx.com     return NXT_OK;
22751555Smax.romanov@nginx.com }
22761555Smax.romanov@nginx.com 
22771555Smax.romanov@nginx.com 
22781555Smax.romanov@nginx.com static nxt_int_t
22791555Smax.romanov@nginx.com nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd)
22801555Smax.romanov@nginx.com {
22811555Smax.romanov@nginx.com     void  *mem;
22821555Smax.romanov@nginx.com 
22831555Smax.romanov@nginx.com     nxt_assert(fd != -1);
22841555Smax.romanov@nginx.com 
22851555Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
22861555Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
22871555Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
22881555Smax.romanov@nginx.com 
22891555Smax.romanov@nginx.com         return NXT_ERROR;
22901555Smax.romanov@nginx.com     }
22911555Smax.romanov@nginx.com 
22921555Smax.romanov@nginx.com     port->queue = mem;
22931555Smax.romanov@nginx.com 
22941555Smax.romanov@nginx.com     return NXT_OK;
22951555Smax.romanov@nginx.com }
22961555Smax.romanov@nginx.com 
22971555Smax.romanov@nginx.com 
22981563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_router_apps_hash_proto  nxt_aligned(64) = {
22991563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
23001563Svbart@nginx.com     nxt_router_apps_hash_test,
23011563Svbart@nginx.com     nxt_mp_lvlhsh_alloc,
23021563Svbart@nginx.com     nxt_mp_lvlhsh_free,
23031563Svbart@nginx.com };
23041563Svbart@nginx.com 
23051563Svbart@nginx.com 
23061563Svbart@nginx.com static nxt_int_t
23071563Svbart@nginx.com nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
23081563Svbart@nginx.com {
23091563Svbart@nginx.com     nxt_app_t  *app;
23101563Svbart@nginx.com 
23111563Svbart@nginx.com     app = data;
23121563Svbart@nginx.com 
23131563Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED;
23141563Svbart@nginx.com }
23151563Svbart@nginx.com 
23161563Svbart@nginx.com 
23171563Svbart@nginx.com static nxt_int_t
23181563Svbart@nginx.com nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app)
23191563Svbart@nginx.com {
23201563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
23211563Svbart@nginx.com 
23221563Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length);
23231563Svbart@nginx.com     lhq.replace = 0;
23241563Svbart@nginx.com     lhq.key = app->name;
23251563Svbart@nginx.com     lhq.value = app;
23261563Svbart@nginx.com     lhq.proto = &nxt_router_apps_hash_proto;
23271563Svbart@nginx.com     lhq.pool = rtcf->mem_pool;
23281563Svbart@nginx.com 
23291563Svbart@nginx.com     switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) {
23301563Svbart@nginx.com 
23311563Svbart@nginx.com     case NXT_OK:
23321563Svbart@nginx.com         return NXT_OK;
23331563Svbart@nginx.com 
23341563Svbart@nginx.com     case NXT_DECLINED:
23351563Svbart@nginx.com         nxt_thread_log_alert("router app hash adding failed: "
23361563Svbart@nginx.com                              "\"%V\" is already in hash", &lhq.key);
23371563Svbart@nginx.com         /* Fall through. */
23381563Svbart@nginx.com     default:
23391563Svbart@nginx.com         return NXT_ERROR;
23401563Svbart@nginx.com     }
23411563Svbart@nginx.com }
23421563Svbart@nginx.com 
23431563Svbart@nginx.com 
23441563Svbart@nginx.com static nxt_app_t *
23451563Svbart@nginx.com nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name)
23461563Svbart@nginx.com {
23471563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
23481563Svbart@nginx.com 
23491563Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
23501563Svbart@nginx.com     lhq.key = *name;
23511563Svbart@nginx.com     lhq.proto = &nxt_router_apps_hash_proto;
23521563Svbart@nginx.com 
23531563Svbart@nginx.com     if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) {
23541563Svbart@nginx.com         return NULL;
23551563Svbart@nginx.com     }
23561563Svbart@nginx.com 
23571563Svbart@nginx.com     return lhq.value;
23581563Svbart@nginx.com }
23591563Svbart@nginx.com 
23601563Svbart@nginx.com 
23611563Svbart@nginx.com static void
23621563Svbart@nginx.com nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i)
23631563Svbart@nginx.com {
23641563Svbart@nginx.com     nxt_app_t          *app;
23651563Svbart@nginx.com     nxt_lvlhsh_each_t  lhe;
23661563Svbart@nginx.com 
23671563Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto);
23681563Svbart@nginx.com 
23691563Svbart@nginx.com     for ( ;; ) {
23701563Svbart@nginx.com         app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe);
23711563Svbart@nginx.com 
23721563Svbart@nginx.com         if (app == NULL) {
23731563Svbart@nginx.com             break;
23741563Svbart@nginx.com         }
23751563Svbart@nginx.com 
23761563Svbart@nginx.com         nxt_router_app_use(task, app, i);
23771563Svbart@nginx.com     }
23781563Svbart@nginx.com }
23791563Svbart@nginx.com 
23801563Svbart@nginx.com 
23811925Sz.hong@f5.com typedef struct {
23821925Sz.hong@f5.com     nxt_app_t  *app;
23831925Sz.hong@f5.com     nxt_int_t  target;
23841925Sz.hong@f5.com } nxt_http_app_conf_t;
23851925Sz.hong@f5.com 
23861563Svbart@nginx.com 
23871563Svbart@nginx.com nxt_int_t
23881925Sz.hong@f5.com nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name,
23891925Sz.hong@f5.com     nxt_str_t *target, nxt_http_action_t *action)
2390133Sigor@sysoev.ru {
23911925Sz.hong@f5.com     nxt_app_t            *app;
23921925Sz.hong@f5.com     nxt_str_t            *targets;
23931925Sz.hong@f5.com     nxt_uint_t           i;
23941925Sz.hong@f5.com     nxt_http_app_conf_t  *conf;
2395133Sigor@sysoev.ru 
23961563Svbart@nginx.com     app = nxt_router_apps_hash_get(rtcf, name);
2397133Sigor@sysoev.ru     if (app == NULL) {
23981563Svbart@nginx.com         return NXT_DECLINED;
2399133Sigor@sysoev.ru     }
2400133Sigor@sysoev.ru 
24011925Sz.hong@f5.com     conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t));
24021925Sz.hong@f5.com     if (nxt_slow_path(conf == NULL)) {
24031925Sz.hong@f5.com         return NXT_ERROR;
24041925Sz.hong@f5.com     }
24051925Sz.hong@f5.com 
24061392Sigor@sysoev.ru     action->handler = nxt_http_application_handler;
24071925Sz.hong@f5.com     action->u.conf = conf;
24081925Sz.hong@f5.com 
24091925Sz.hong@f5.com     conf->app = app;
24101925Sz.hong@f5.com 
24111925Sz.hong@f5.com     if (target != NULL && target->length != 0) {
24121925Sz.hong@f5.com         targets = app->targets;
24131925Sz.hong@f5.com 
24141925Sz.hong@f5.com         for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++);
24151925Sz.hong@f5.com 
24161925Sz.hong@f5.com         conf->target = i;
24171925Sz.hong@f5.com 
24181925Sz.hong@f5.com     } else {
24191925Sz.hong@f5.com         conf->target = 0;
24201925Sz.hong@f5.com     }
24211563Svbart@nginx.com 
24221563Svbart@nginx.com     return NXT_OK;
242353Sigor@sysoev.ru }
242453Sigor@sysoev.ru 
242553Sigor@sysoev.ru 
242653Sigor@sysoev.ru static nxt_socket_conf_t *
2427359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2428359Sigor@sysoev.ru     nxt_str_t *name)
242953Sigor@sysoev.ru {
2430359Sigor@sysoev.ru     size_t               size;
2431359Sigor@sysoev.ru     nxt_int_t            ret;
2432359Sigor@sysoev.ru     nxt_bool_t           wildcard;
2433359Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
2434359Sigor@sysoev.ru     nxt_socket_conf_t    *skcf;
2435359Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
2436359Sigor@sysoev.ru 
2437359Sigor@sysoev.ru     sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
2438359Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
2439564Svbart@nginx.com         nxt_alert(task, "invalid listener \"%V\"", name);
2440359Sigor@sysoev.ru         return NULL;
2441359Sigor@sysoev.ru     }
2442359Sigor@sysoev.ru 
2443359Sigor@sysoev.ru     sa->type = SOCK_STREAM;
2444359Sigor@sysoev.ru 
2445359Sigor@sysoev.ru     nxt_debug(task, "router listener: \"%*s\"",
2446493Spluknet@nginx.com               (size_t) sa->length, nxt_sockaddr_start(sa));
2447359Sigor@sysoev.ru 
2448591Sigor@sysoev.ru     skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
2449163Smax.romanov@nginx.com     if (nxt_slow_path(skcf == NULL)) {
245053Sigor@sysoev.ru         return NULL;
245153Sigor@sysoev.ru     }
245253Sigor@sysoev.ru 
2453359Sigor@sysoev.ru     size = nxt_sockaddr_size(sa);
2454359Sigor@sysoev.ru 
2455359Sigor@sysoev.ru     ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
2456359Sigor@sysoev.ru 
2457359Sigor@sysoev.ru     if (ret != NXT_OK) {
2458359Sigor@sysoev.ru 
2459359Sigor@sysoev.ru         ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
2460359Sigor@sysoev.ru         if (nxt_slow_path(ls == NULL)) {
2461359Sigor@sysoev.ru             return NULL;
2462359Sigor@sysoev.ru         }
2463359Sigor@sysoev.ru 
2464359Sigor@sysoev.ru         skcf->listen = ls;
2465359Sigor@sysoev.ru 
2466359Sigor@sysoev.ru         ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
2467359Sigor@sysoev.ru         nxt_memcpy(ls->sockaddr, sa, size);
2468359Sigor@sysoev.ru 
2469359Sigor@sysoev.ru         nxt_listen_socket_remote_size(ls);
2470359Sigor@sysoev.ru 
2471359Sigor@sysoev.ru         ls->socket = -1;
2472359Sigor@sysoev.ru         ls->backlog = NXT_LISTEN_BACKLOG;
2473359Sigor@sysoev.ru         ls->flags = NXT_NONBLOCK;
2474359Sigor@sysoev.ru         ls->read_after_accept = 1;
2475359Sigor@sysoev.ru     }
2476359Sigor@sysoev.ru 
2477359Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
2478359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
2479359Sigor@sysoev.ru     case AF_UNIX:
2480359Sigor@sysoev.ru         wildcard = 0;
2481359Sigor@sysoev.ru         break;
2482359Sigor@sysoev.ru #endif
2483359Sigor@sysoev.ru #if (NXT_INET6)
2484359Sigor@sysoev.ru     case AF_INET6:
2485359Sigor@sysoev.ru         wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
2486359Sigor@sysoev.ru         break;
2487359Sigor@sysoev.ru #endif
2488359Sigor@sysoev.ru     case AF_INET:
2489359Sigor@sysoev.ru     default:
2490359Sigor@sysoev.ru         wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
2491359Sigor@sysoev.ru         break;
2492359Sigor@sysoev.ru     }
2493359Sigor@sysoev.ru 
2494359Sigor@sysoev.ru     if (!wildcard) {
2495591Sigor@sysoev.ru         skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
2496359Sigor@sysoev.ru         if (nxt_slow_path(skcf->sockaddr == NULL)) {
2497359Sigor@sysoev.ru             return NULL;
2498359Sigor@sysoev.ru         }
2499359Sigor@sysoev.ru 
2500359Sigor@sysoev.ru         nxt_memcpy(skcf->sockaddr, sa, size);
2501359Sigor@sysoev.ru     }
2502163Smax.romanov@nginx.com 
2503163Smax.romanov@nginx.com     return skcf;
250453Sigor@sysoev.ru }
250553Sigor@sysoev.ru 
250653Sigor@sysoev.ru 
2507359Sigor@sysoev.ru static nxt_int_t
2508359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
2509359Sigor@sysoev.ru     nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
251053Sigor@sysoev.ru {
2511359Sigor@sysoev.ru     nxt_router_t       *router;
2512359Sigor@sysoev.ru     nxt_queue_link_t   *qlk;
2513359Sigor@sysoev.ru     nxt_socket_conf_t  *skcf;
2514359Sigor@sysoev.ru 
2515591Sigor@sysoev.ru     router = tmcf->router_conf->router;
2516359Sigor@sysoev.ru 
2517359Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->sockets);
2518359Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->sockets);
2519359Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
252053Sigor@sysoev.ru     {
2521359Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2522359Sigor@sysoev.ru 
2523359Sigor@sysoev.ru         if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2524359Sigor@sysoev.ru             nskcf->listen = skcf->listen;
2525359Sigor@sysoev.ru 
2526359Sigor@sysoev.ru             nxt_queue_remove(qlk);
25271509Sigor@sysoev.ru             nxt_queue_insert_tail(&keeping_sockets, qlk);
25281509Sigor@sysoev.ru 
25291509Sigor@sysoev.ru             nxt_queue_insert_tail(&updating_sockets, &nskcf->link);
2530359Sigor@sysoev.ru 
2531359Sigor@sysoev.ru             return NXT_OK;
253253Sigor@sysoev.ru         }
253353Sigor@sysoev.ru     }
253453Sigor@sysoev.ru 
25351509Sigor@sysoev.ru     nxt_queue_insert_tail(&pending_sockets, &nskcf->link);
2536359Sigor@sysoev.ru 
2537359Sigor@sysoev.ru     return NXT_DECLINED;
253853Sigor@sysoev.ru }
253953Sigor@sysoev.ru 
254053Sigor@sysoev.ru 
2541198Sigor@sysoev.ru static void
2542198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2543198Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2544198Sigor@sysoev.ru {
2545358Sigor@sysoev.ru     size_t            size;
2546198Sigor@sysoev.ru     uint32_t          stream;
2547648Svbart@nginx.com     nxt_int_t         ret;
2548198Sigor@sysoev.ru     nxt_buf_t         *b;
2549198Sigor@sysoev.ru     nxt_port_t        *main_port, *router_port;
2550198Sigor@sysoev.ru     nxt_runtime_t     *rt;
2551198Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
2552198Sigor@sysoev.ru 
2553198Sigor@sysoev.ru     rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2554198Sigor@sysoev.ru     if (rpc == NULL) {
2555198Sigor@sysoev.ru         goto fail;
2556198Sigor@sysoev.ru     }
2557198Sigor@sysoev.ru 
2558198Sigor@sysoev.ru     rpc->socket_conf = skcf;
2559198Sigor@sysoev.ru     rpc->temp_conf = tmcf;
2560198Sigor@sysoev.ru 
2561359Sigor@sysoev.ru     size = nxt_sockaddr_size(skcf->listen->sockaddr);
2562358Sigor@sysoev.ru 
2563358Sigor@sysoev.ru     b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2564198Sigor@sysoev.ru     if (b == NULL) {
2565198Sigor@sysoev.ru         goto fail;
2566198Sigor@sysoev.ru     }
2567198Sigor@sysoev.ru 
25681940Sz.hong@f5.com     b->completion_handler = nxt_buf_dummy_completion;
25691566Smax.romanov@nginx.com 
2570359Sigor@sysoev.ru     b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2571198Sigor@sysoev.ru 
2572198Sigor@sysoev.ru     rt = task->thread->runtime;
2573240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2574198Sigor@sysoev.ru     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2575198Sigor@sysoev.ru 
2576198Sigor@sysoev.ru     stream = nxt_port_rpc_register_handler(task, router_port,
2577198Sigor@sysoev.ru                                            nxt_router_listen_socket_ready,
2578198Sigor@sysoev.ru                                            nxt_router_listen_socket_error,
2579198Sigor@sysoev.ru                                            main_port->pid, rpc);
2580645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
2581198Sigor@sysoev.ru         goto fail;
2582198Sigor@sysoev.ru     }
2583198Sigor@sysoev.ru 
2584648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2585648Svbart@nginx.com                                 stream, router_port->id, b);
2586648Svbart@nginx.com 
2587648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2588648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2589648Svbart@nginx.com         goto fail;
2590648Svbart@nginx.com     }
2591198Sigor@sysoev.ru 
2592198Sigor@sysoev.ru     return;
2593198Sigor@sysoev.ru 
2594198Sigor@sysoev.ru fail:
2595198Sigor@sysoev.ru 
2596198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
2597198Sigor@sysoev.ru }
2598198Sigor@sysoev.ru 
2599198Sigor@sysoev.ru 
2600198Sigor@sysoev.ru static void
2601198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2602198Sigor@sysoev.ru     void *data)
260353Sigor@sysoev.ru {
2604359Sigor@sysoev.ru     nxt_int_t         ret;
2605359Sigor@sysoev.ru     nxt_socket_t      s;
2606359Sigor@sysoev.ru     nxt_socket_rpc_t  *rpc;
260753Sigor@sysoev.ru 
2608198Sigor@sysoev.ru     rpc = data;
2609198Sigor@sysoev.ru 
26101558Smax.romanov@nginx.com     s = msg->fd[0];
2611198Sigor@sysoev.ru 
2612198Sigor@sysoev.ru     ret = nxt_socket_nonblocking(task, s);
2613198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2614198Sigor@sysoev.ru         goto fail;
261553Sigor@sysoev.ru     }
261653Sigor@sysoev.ru 
2617359Sigor@sysoev.ru     nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2618198Sigor@sysoev.ru 
2619198Sigor@sysoev.ru     ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2620198Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
2621198Sigor@sysoev.ru         goto fail;
2622198Sigor@sysoev.ru     }
2623198Sigor@sysoev.ru 
2624359Sigor@sysoev.ru     rpc->socket_conf->listen->socket = s;
2625198Sigor@sysoev.ru 
2626198Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2627198Sigor@sysoev.ru                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2628198Sigor@sysoev.ru 
2629198Sigor@sysoev.ru     return;
2630148Sigor@sysoev.ru 
2631148Sigor@sysoev.ru fail:
2632148Sigor@sysoev.ru 
2633148Sigor@sysoev.ru     nxt_socket_close(task, s);
2634148Sigor@sysoev.ru 
2635198Sigor@sysoev.ru     nxt_router_conf_error(task, rpc->temp_conf);
2636198Sigor@sysoev.ru }
2637198Sigor@sysoev.ru 
2638198Sigor@sysoev.ru 
2639198Sigor@sysoev.ru static void
2640198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2641198Sigor@sysoev.ru     void *data)
2642198Sigor@sysoev.ru {
2643955Svbart@nginx.com     nxt_socket_rpc_t        *rpc;
2644955Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
2645955Svbart@nginx.com 
2646955Svbart@nginx.com     rpc = data;
2647955Svbart@nginx.com     tmcf = rpc->temp_conf;
2648955Svbart@nginx.com 
2649955Svbart@nginx.com #if 0
2650198Sigor@sysoev.ru     u_char                  *p;
2651198Sigor@sysoev.ru     size_t                  size;
2652198Sigor@sysoev.ru     uint8_t                 error;
2653198Sigor@sysoev.ru     nxt_buf_t               *in, *out;
2654198Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
2655198Sigor@sysoev.ru 
2656198Sigor@sysoev.ru     static nxt_str_t  socket_errors[] = {
2657198Sigor@sysoev.ru         nxt_string("ListenerSystem"),
2658198Sigor@sysoev.ru         nxt_string("ListenerNoIPv6"),
2659198Sigor@sysoev.ru         nxt_string("ListenerPort"),
2660198Sigor@sysoev.ru         nxt_string("ListenerInUse"),
2661198Sigor@sysoev.ru         nxt_string("ListenerNoAddress"),
2662198Sigor@sysoev.ru         nxt_string("ListenerNoAccess"),
2663198Sigor@sysoev.ru         nxt_string("ListenerPath"),
2664198Sigor@sysoev.ru     };
2665198Sigor@sysoev.ru 
2666359Sigor@sysoev.ru     sa = rpc->socket_conf->listen->sockaddr;
2667352Smax.romanov@nginx.com 
2668352Smax.romanov@nginx.com     in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2669352Smax.romanov@nginx.com 
2670551Smax.romanov@nginx.com     if (nxt_slow_path(in == NULL)) {
2671551Smax.romanov@nginx.com         return;
2672551Smax.romanov@nginx.com     }
2673352Smax.romanov@nginx.com 
2674198Sigor@sysoev.ru     p = in->mem.pos;
2675198Sigor@sysoev.ru 
2676198Sigor@sysoev.ru     error = *p++;
2677198Sigor@sysoev.ru 
2678703Svbart@nginx.com     size = nxt_length("listen socket error: ")
2679703Svbart@nginx.com            + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2680198Sigor@sysoev.ru            + sa->length + socket_errors[error].length + (in->mem.free - p);
2681198Sigor@sysoev.ru 
2682198Sigor@sysoev.ru     out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2683198Sigor@sysoev.ru     if (nxt_slow_path(out == NULL)) {
2684198Sigor@sysoev.ru         return;
2685198Sigor@sysoev.ru     }
2686198Sigor@sysoev.ru 
2687198Sigor@sysoev.ru     out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2688198Sigor@sysoev.ru                         "listen socket error: "
2689198Sigor@sysoev.ru                         "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2690493Spluknet@nginx.com                         (size_t) sa->length, nxt_sockaddr_start(sa),
2691198Sigor@sysoev.ru                         &socket_errors[error], in->mem.free - p, p);
2692198Sigor@sysoev.ru 
2693198Sigor@sysoev.ru     nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2694955Svbart@nginx.com #endif
2695198Sigor@sysoev.ru 
2696198Sigor@sysoev.ru     nxt_router_conf_error(task, tmcf);
269753Sigor@sysoev.ru }
269853Sigor@sysoev.ru 
269953Sigor@sysoev.ru 
2700774Svbart@nginx.com #if (NXT_TLS)
2701774Svbart@nginx.com 
2702774Svbart@nginx.com static void
2703774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2704774Svbart@nginx.com     void *data)
2705774Svbart@nginx.com {
27061828Sa.suvorov@f5.com     nxt_mp_t                *mp;
27071828Sa.suvorov@f5.com     nxt_int_t               ret;
27081828Sa.suvorov@f5.com     nxt_tls_conf_t          *tlscf;
27091885Sa.suvorov@f5.com     nxt_router_tlssock_t    *tls;
27101828Sa.suvorov@f5.com     nxt_tls_bundle_conf_t   *bundle;
27111828Sa.suvorov@f5.com     nxt_router_temp_conf_t  *tmcf;
2712774Svbart@nginx.com 
2713774Svbart@nginx.com     nxt_debug(task, "tls rpc handler");
2714774Svbart@nginx.com 
27151885Sa.suvorov@f5.com     tls = data;
27161885Sa.suvorov@f5.com     tmcf = tls->temp_conf;
2717774Svbart@nginx.com 
2718774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2719774Svbart@nginx.com         goto fail;
2720774Svbart@nginx.com     }
2721774Svbart@nginx.com 
2722774Svbart@nginx.com     mp = tmcf->router_conf->mem_pool;
2723774Svbart@nginx.com 
27241885Sa.suvorov@f5.com     if (tls->socket_conf->tls == NULL){
27251828Sa.suvorov@f5.com         tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
27261828Sa.suvorov@f5.com         if (nxt_slow_path(tlscf == NULL)) {
27271828Sa.suvorov@f5.com             goto fail;
27281828Sa.suvorov@f5.com         }
27291828Sa.suvorov@f5.com 
27301884Sa.suvorov@f5.com         tlscf->no_wait_shutdown = 1;
27311885Sa.suvorov@f5.com         tls->socket_conf->tls = tlscf;
27321828Sa.suvorov@f5.com 
27331828Sa.suvorov@f5.com     } else {
27341885Sa.suvorov@f5.com         tlscf = tls->socket_conf->tls;
27351828Sa.suvorov@f5.com     }
27361828Sa.suvorov@f5.com 
27371920Sa.suvorov@f5.com     tls->tls_init->conf = tlscf;
27381920Sa.suvorov@f5.com 
27391828Sa.suvorov@f5.com     bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t));
27401828Sa.suvorov@f5.com     if (nxt_slow_path(bundle == NULL)) {
2741774Svbart@nginx.com         goto fail;
2742774Svbart@nginx.com     }
2743774Svbart@nginx.com 
27441885Sa.suvorov@f5.com     if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) {
27451885Sa.suvorov@f5.com         goto fail;
27461885Sa.suvorov@f5.com     }
27471885Sa.suvorov@f5.com 
27481828Sa.suvorov@f5.com     bundle->chain_file = msg->fd[0];
27491828Sa.suvorov@f5.com     bundle->next = tlscf->bundle;
27501828Sa.suvorov@f5.com     tlscf->bundle = bundle;
27511828Sa.suvorov@f5.com 
27521920Sa.suvorov@f5.com     ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init,
27531920Sa.suvorov@f5.com                                                   tls->last);
2754774Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2755774Svbart@nginx.com         goto fail;
2756774Svbart@nginx.com     }
2757774Svbart@nginx.com 
2758774Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2759774Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
2760774Svbart@nginx.com     return;
2761774Svbart@nginx.com 
2762774Svbart@nginx.com fail:
2763774Svbart@nginx.com 
2764774Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
2765774Svbart@nginx.com }
2766774Svbart@nginx.com 
2767774Svbart@nginx.com #endif
2768774Svbart@nginx.com 
2769774Svbart@nginx.com 
2770507Smax.romanov@nginx.com static void
2771507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task,
2772507Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2773507Smax.romanov@nginx.com {
2774507Smax.romanov@nginx.com     size_t         size;
2775507Smax.romanov@nginx.com     uint32_t       stream;
2776648Svbart@nginx.com     nxt_int_t      ret;
2777507Smax.romanov@nginx.com     nxt_buf_t      *b;
2778*1998St.nateldemoura@f5.com     nxt_port_t     *router_port, *dport;
2779507Smax.romanov@nginx.com     nxt_runtime_t  *rt;
2780507Smax.romanov@nginx.com     nxt_app_rpc_t  *rpc;
2781507Smax.romanov@nginx.com 
2782*1998St.nateldemoura@f5.com     rt = task->thread->runtime;
2783*1998St.nateldemoura@f5.com 
2784*1998St.nateldemoura@f5.com     dport = app->proto_port;
2785*1998St.nateldemoura@f5.com 
2786*1998St.nateldemoura@f5.com     if (dport == NULL) {
2787*1998St.nateldemoura@f5.com         nxt_debug(task, "app '%V' prototype prefork", &app->name);
2788*1998St.nateldemoura@f5.com 
2789*1998St.nateldemoura@f5.com         size = app->name.length + 1 + app->conf.length;
2790*1998St.nateldemoura@f5.com 
2791*1998St.nateldemoura@f5.com         b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2792*1998St.nateldemoura@f5.com         if (nxt_slow_path(b == NULL)) {
2793*1998St.nateldemoura@f5.com             goto fail;
2794*1998St.nateldemoura@f5.com         }
2795*1998St.nateldemoura@f5.com 
2796*1998St.nateldemoura@f5.com         b->completion_handler = nxt_buf_dummy_completion;
2797*1998St.nateldemoura@f5.com 
2798*1998St.nateldemoura@f5.com         nxt_buf_cpystr(b, &app->name);
2799*1998St.nateldemoura@f5.com         *b->mem.free++ = '\0';
2800*1998St.nateldemoura@f5.com         nxt_buf_cpystr(b, &app->conf);
2801*1998St.nateldemoura@f5.com 
2802*1998St.nateldemoura@f5.com         dport = rt->port_by_type[NXT_PROCESS_MAIN];
2803*1998St.nateldemoura@f5.com 
2804*1998St.nateldemoura@f5.com     } else {
2805*1998St.nateldemoura@f5.com         nxt_debug(task, "app '%V' prefork", &app->name);
2806*1998St.nateldemoura@f5.com 
2807*1998St.nateldemoura@f5.com         b = NULL;
2808*1998St.nateldemoura@f5.com     }
2809*1998St.nateldemoura@f5.com 
2810*1998St.nateldemoura@f5.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2811*1998St.nateldemoura@f5.com 
2812*1998St.nateldemoura@f5.com     rpc = nxt_port_rpc_register_handler_ex(task, router_port,
2813*1998St.nateldemoura@f5.com                                            nxt_router_app_prefork_ready,
2814*1998St.nateldemoura@f5.com                                            nxt_router_app_prefork_error,
2815*1998St.nateldemoura@f5.com                                            sizeof(nxt_app_rpc_t));
2816*1998St.nateldemoura@f5.com     if (nxt_slow_path(rpc == NULL)) {
2817507Smax.romanov@nginx.com         goto fail;
2818507Smax.romanov@nginx.com     }
2819507Smax.romanov@nginx.com 
2820507Smax.romanov@nginx.com     rpc->app = app;
2821507Smax.romanov@nginx.com     rpc->temp_conf = tmcf;
2822*1998St.nateldemoura@f5.com     rpc->proto = (b != NULL);
2823*1998St.nateldemoura@f5.com 
2824*1998St.nateldemoura@f5.com     stream = nxt_port_rpc_ex_stream(rpc);
2825*1998St.nateldemoura@f5.com 
2826*1998St.nateldemoura@f5.com     ret = nxt_port_socket_write(task, dport,
2827*1998St.nateldemoura@f5.com                                 NXT_PORT_MSG_START_PROCESS,
28281488St.nateldemoura@f5.com                                 -1, stream, router_port->id, b);
2829648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
2830648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
2831648Svbart@nginx.com         goto fail;
2832648Svbart@nginx.com     }
2833648Svbart@nginx.com 
2834*1998St.nateldemoura@f5.com     if (b == NULL) {
2835*1998St.nateldemoura@f5.com         nxt_port_rpc_ex_set_peer(task, router_port, rpc, dport->pid);
2836*1998St.nateldemoura@f5.com 
2837*1998St.nateldemoura@f5.com         app->pending_processes++;
2838*1998St.nateldemoura@f5.com     }
2839507Smax.romanov@nginx.com 
2840507Smax.romanov@nginx.com     return;
2841507Smax.romanov@nginx.com 
2842507Smax.romanov@nginx.com fail:
2843507Smax.romanov@nginx.com 
2844507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2845507Smax.romanov@nginx.com }
2846507Smax.romanov@nginx.com 
2847507Smax.romanov@nginx.com 
2848507Smax.romanov@nginx.com static void
2849507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2850507Smax.romanov@nginx.com     void *data)
2851507Smax.romanov@nginx.com {
2852507Smax.romanov@nginx.com     nxt_app_t           *app;
2853507Smax.romanov@nginx.com     nxt_port_t          *port;
2854507Smax.romanov@nginx.com     nxt_app_rpc_t       *rpc;
2855507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
2856507Smax.romanov@nginx.com 
2857507Smax.romanov@nginx.com     rpc = data;
2858507Smax.romanov@nginx.com     app = rpc->app;
2859507Smax.romanov@nginx.com 
2860507Smax.romanov@nginx.com     port = msg->u.new_port;
28611547Smax.romanov@nginx.com 
28621547Smax.romanov@nginx.com     nxt_assert(port != NULL);
2863*1998St.nateldemoura@f5.com     nxt_assert(port->id == 0);
2864*1998St.nateldemoura@f5.com 
2865*1998St.nateldemoura@f5.com     if (rpc->proto) {
2866*1998St.nateldemoura@f5.com         nxt_assert(app->proto_port == NULL);
2867*1998St.nateldemoura@f5.com         nxt_assert(port->type == NXT_PROCESS_PROTOTYPE);
2868*1998St.nateldemoura@f5.com 
2869*1998St.nateldemoura@f5.com         nxt_port_inc_use(port);
2870*1998St.nateldemoura@f5.com 
2871*1998St.nateldemoura@f5.com         app->proto_port = port;
2872*1998St.nateldemoura@f5.com         port->app = app;
2873*1998St.nateldemoura@f5.com 
2874*1998St.nateldemoura@f5.com         nxt_router_app_rpc_create(task, rpc->temp_conf, app);
2875*1998St.nateldemoura@f5.com 
2876*1998St.nateldemoura@f5.com         return;
2877*1998St.nateldemoura@f5.com     }
2878*1998St.nateldemoura@f5.com 
28791547Smax.romanov@nginx.com     nxt_assert(port->type == NXT_PROCESS_APP);
28801547Smax.romanov@nginx.com 
2881507Smax.romanov@nginx.com     port->app = app;
28821547Smax.romanov@nginx.com     port->main_app_port = port;
2883507Smax.romanov@nginx.com 
2884507Smax.romanov@nginx.com     app->pending_processes--;
2885507Smax.romanov@nginx.com     app->processes++;
2886507Smax.romanov@nginx.com     app->idle_processes++;
2887507Smax.romanov@nginx.com 
2888507Smax.romanov@nginx.com     engine = task->thread->engine;
2889507Smax.romanov@nginx.com 
2890507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ports, &port->app_link);
2891507Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
28921549Smax.romanov@nginx.com 
28931549Smax.romanov@nginx.com     nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports",
28941549Smax.romanov@nginx.com               &app->name, port->pid, port->id);
28951549Smax.romanov@nginx.com 
28961547Smax.romanov@nginx.com     nxt_port_hash_add(&app->port_hash, port);
28971547Smax.romanov@nginx.com     app->port_hash_count++;
2898507Smax.romanov@nginx.com 
2899507Smax.romanov@nginx.com     port->idle_start = 0;
2900507Smax.romanov@nginx.com 
2901507Smax.romanov@nginx.com     nxt_port_inc_use(port);
2902507Smax.romanov@nginx.com 
29031547Smax.romanov@nginx.com     nxt_router_app_shared_port_send(task, port);
29041547Smax.romanov@nginx.com 
2905507Smax.romanov@nginx.com     nxt_work_queue_add(&engine->fast_work_queue,
2906507Smax.romanov@nginx.com                        nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2907507Smax.romanov@nginx.com }
2908507Smax.romanov@nginx.com 
2909507Smax.romanov@nginx.com 
2910507Smax.romanov@nginx.com static void
2911507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2912507Smax.romanov@nginx.com     void *data)
2913507Smax.romanov@nginx.com {
2914507Smax.romanov@nginx.com     nxt_app_t               *app;
2915507Smax.romanov@nginx.com     nxt_app_rpc_t           *rpc;
2916507Smax.romanov@nginx.com     nxt_router_temp_conf_t  *tmcf;
2917507Smax.romanov@nginx.com 
2918507Smax.romanov@nginx.com     rpc = data;
2919507Smax.romanov@nginx.com     app = rpc->app;
2920507Smax.romanov@nginx.com     tmcf = rpc->temp_conf;
2921507Smax.romanov@nginx.com 
2922*1998St.nateldemoura@f5.com     if (rpc->proto) {
2923*1998St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_WARN, "failed to start prototype \"%V\"",
2924*1998St.nateldemoura@f5.com                 &app->name);
2925*1998St.nateldemoura@f5.com 
2926*1998St.nateldemoura@f5.com     } else {
2927*1998St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2928*1998St.nateldemoura@f5.com                 &app->name);
2929*1998St.nateldemoura@f5.com 
2930*1998St.nateldemoura@f5.com         app->pending_processes--;
2931*1998St.nateldemoura@f5.com     }
2932507Smax.romanov@nginx.com 
2933507Smax.romanov@nginx.com     nxt_router_conf_error(task, tmcf);
2934507Smax.romanov@nginx.com }
2935507Smax.romanov@nginx.com 
2936507Smax.romanov@nginx.com 
293753Sigor@sysoev.ru static nxt_int_t
293853Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
293953Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
294053Sigor@sysoev.ru {
294153Sigor@sysoev.ru     nxt_int_t                 ret;
294253Sigor@sysoev.ru     nxt_uint_t                n, threads;
294353Sigor@sysoev.ru     nxt_queue_link_t          *qlk;
294453Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
294553Sigor@sysoev.ru 
2946591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
294753Sigor@sysoev.ru 
294853Sigor@sysoev.ru     tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
294953Sigor@sysoev.ru                                      sizeof(nxt_router_engine_conf_t));
295053Sigor@sysoev.ru     if (nxt_slow_path(tmcf->engines == NULL)) {
295153Sigor@sysoev.ru         return NXT_ERROR;
295253Sigor@sysoev.ru     }
295353Sigor@sysoev.ru 
295453Sigor@sysoev.ru     n = 0;
295553Sigor@sysoev.ru 
295653Sigor@sysoev.ru     for (qlk = nxt_queue_first(&router->engines);
295753Sigor@sysoev.ru          qlk != nxt_queue_tail(&router->engines);
295853Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
295953Sigor@sysoev.ru     {
296053Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
296153Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
296253Sigor@sysoev.ru             return NXT_ERROR;
296353Sigor@sysoev.ru         }
296453Sigor@sysoev.ru 
2965115Sigor@sysoev.ru         recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
296653Sigor@sysoev.ru 
296753Sigor@sysoev.ru         if (n < threads) {
2968315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_KEEP;
2969115Sigor@sysoev.ru             ret = nxt_router_engine_conf_update(tmcf, recf);
297053Sigor@sysoev.ru 
297153Sigor@sysoev.ru         } else {
2972315Sigor@sysoev.ru             recf->action = NXT_ROUTER_ENGINE_DELETE;
2973115Sigor@sysoev.ru             ret = nxt_router_engine_conf_delete(tmcf, recf);
297453Sigor@sysoev.ru         }
297553Sigor@sysoev.ru 
297653Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
297753Sigor@sysoev.ru             return ret;
297853Sigor@sysoev.ru         }
297953Sigor@sysoev.ru 
298053Sigor@sysoev.ru         n++;
298153Sigor@sysoev.ru     }
298253Sigor@sysoev.ru 
298353Sigor@sysoev.ru     tmcf->new_threads = n;
298453Sigor@sysoev.ru 
298553Sigor@sysoev.ru     while (n < threads) {
298653Sigor@sysoev.ru         recf = nxt_array_zero_add(tmcf->engines);
298753Sigor@sysoev.ru         if (nxt_slow_path(recf == NULL)) {
298853Sigor@sysoev.ru             return NXT_ERROR;
298953Sigor@sysoev.ru         }
299053Sigor@sysoev.ru 
2991315Sigor@sysoev.ru         recf->action = NXT_ROUTER_ENGINE_ADD;
2992315Sigor@sysoev.ru 
299353Sigor@sysoev.ru         recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
299453Sigor@sysoev.ru         if (nxt_slow_path(recf->engine == NULL)) {
299553Sigor@sysoev.ru             return NXT_ERROR;
299653Sigor@sysoev.ru         }
299753Sigor@sysoev.ru 
2998115Sigor@sysoev.ru         ret = nxt_router_engine_conf_create(tmcf, recf);
299953Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
300053Sigor@sysoev.ru             return ret;
300153Sigor@sysoev.ru         }
300253Sigor@sysoev.ru 
300353Sigor@sysoev.ru         n++;
300453Sigor@sysoev.ru     }
300553Sigor@sysoev.ru 
300653Sigor@sysoev.ru     return NXT_OK;
300753Sigor@sysoev.ru }
300853Sigor@sysoev.ru 
300953Sigor@sysoev.ru 
301053Sigor@sysoev.ru static nxt_int_t
3011115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
3012115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
301353Sigor@sysoev.ru {
3014359Sigor@sysoev.ru     nxt_int_t  ret;
301553Sigor@sysoev.ru 
30161509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
3017154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
3018115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
3019115Sigor@sysoev.ru         return ret;
3020115Sigor@sysoev.ru     }
3021115Sigor@sysoev.ru 
30221509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
3023154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
302453Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
302553Sigor@sysoev.ru         return ret;
302653Sigor@sysoev.ru     }
302753Sigor@sysoev.ru 
3028115Sigor@sysoev.ru     return ret;
302953Sigor@sysoev.ru }
303053Sigor@sysoev.ru 
303153Sigor@sysoev.ru 
303253Sigor@sysoev.ru static nxt_int_t
3033115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
3034115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
303553Sigor@sysoev.ru {
3036359Sigor@sysoev.ru     nxt_int_t  ret;
303753Sigor@sysoev.ru 
30381509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
3039154Sigor@sysoev.ru                                           nxt_router_listen_socket_create);
304053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
304153Sigor@sysoev.ru         return ret;
304253Sigor@sysoev.ru     }
304353Sigor@sysoev.ru 
30441509Sigor@sysoev.ru     ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
3045154Sigor@sysoev.ru                                           nxt_router_listen_socket_update);
304653Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
304753Sigor@sysoev.ru         return ret;
304853Sigor@sysoev.ru     }
304953Sigor@sysoev.ru 
30501509Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
3051115Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
3052115Sigor@sysoev.ru         return ret;
3053115Sigor@sysoev.ru     }
3054115Sigor@sysoev.ru 
3055115Sigor@sysoev.ru     return ret;
305653Sigor@sysoev.ru }
305753Sigor@sysoev.ru 
305853Sigor@sysoev.ru 
305953Sigor@sysoev.ru static nxt_int_t
3060115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
3061115Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
306253Sigor@sysoev.ru {
306353Sigor@sysoev.ru     nxt_int_t  ret;
306453Sigor@sysoev.ru 
3065313Sigor@sysoev.ru     ret = nxt_router_engine_quit(tmcf, recf);
3066313Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
3067313Sigor@sysoev.ru         return ret;
3068313Sigor@sysoev.ru     }
3069313Sigor@sysoev.ru 
30701509Sigor@sysoev.ru     ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets);
307153Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
307253Sigor@sysoev.ru         return ret;
307353Sigor@sysoev.ru     }
307453Sigor@sysoev.ru 
30751509Sigor@sysoev.ru     return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
307653Sigor@sysoev.ru }
307753Sigor@sysoev.ru 
307853Sigor@sysoev.ru 
307953Sigor@sysoev.ru static nxt_int_t
3080154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
3081154Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
308253Sigor@sysoev.ru     nxt_work_handler_t handler)
308353Sigor@sysoev.ru {
30841394Sigor@sysoev.ru     nxt_int_t                ret;
3085153Sigor@sysoev.ru     nxt_joint_job_t          *job;
308653Sigor@sysoev.ru     nxt_queue_link_t         *qlk;
3087155Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
308853Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
308953Sigor@sysoev.ru 
309053Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
309153Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
309253Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
309353Sigor@sysoev.ru     {
3094154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
3095153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
3096139Sigor@sysoev.ru             return NXT_ERROR;
3097139Sigor@sysoev.ru         }
3098139Sigor@sysoev.ru 
3099154Sigor@sysoev.ru         job->work.next = recf->jobs;
3100154Sigor@sysoev.ru         recf->jobs = &job->work;
3101154Sigor@sysoev.ru 
3102153Sigor@sysoev.ru         job->task = tmcf->engine->task;
3103153Sigor@sysoev.ru         job->work.handler = handler;
3104153Sigor@sysoev.ru         job->work.task = &job->task;
3105153Sigor@sysoev.ru         job->work.obj = job;
3106153Sigor@sysoev.ru         job->tmcf = tmcf;
310753Sigor@sysoev.ru 
3108154Sigor@sysoev.ru         tmcf->count++;
3109154Sigor@sysoev.ru 
3110591Sigor@sysoev.ru         joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
3111154Sigor@sysoev.ru                              sizeof(nxt_socket_conf_joint_t));
311253Sigor@sysoev.ru         if (nxt_slow_path(joint == NULL)) {
311353Sigor@sysoev.ru             return NXT_ERROR;
311453Sigor@sysoev.ru         }
311553Sigor@sysoev.ru 
3116153Sigor@sysoev.ru         job->work.data = joint;
311753Sigor@sysoev.ru 
31181394Sigor@sysoev.ru         ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams);
31191394Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
31201394Sigor@sysoev.ru             return ret;
31211394Sigor@sysoev.ru         }
31221394Sigor@sysoev.ru 
312353Sigor@sysoev.ru         joint->count = 1;
3124155Sigor@sysoev.ru 
3125155Sigor@sysoev.ru         skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
3126155Sigor@sysoev.ru         skcf->count++;
3127155Sigor@sysoev.ru         joint->socket_conf = skcf;
3128155Sigor@sysoev.ru 
312988Smax.romanov@nginx.com         joint->engine = recf->engine;
313053Sigor@sysoev.ru     }
313153Sigor@sysoev.ru 
313220Sigor@sysoev.ru     return NXT_OK;
313320Sigor@sysoev.ru }
313420Sigor@sysoev.ru 
313520Sigor@sysoev.ru 
313620Sigor@sysoev.ru static nxt_int_t
3137313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
3138313Sigor@sysoev.ru     nxt_router_engine_conf_t *recf)
3139313Sigor@sysoev.ru {
3140313Sigor@sysoev.ru     nxt_joint_job_t  *job;
3141313Sigor@sysoev.ru 
3142313Sigor@sysoev.ru     job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
3143313Sigor@sysoev.ru     if (nxt_slow_path(job == NULL)) {
3144313Sigor@sysoev.ru         return NXT_ERROR;
3145313Sigor@sysoev.ru     }
3146313Sigor@sysoev.ru 
3147313Sigor@sysoev.ru     job->work.next = recf->jobs;
3148313Sigor@sysoev.ru     recf->jobs = &job->work;
3149313Sigor@sysoev.ru 
3150313Sigor@sysoev.ru     job->task = tmcf->engine->task;
3151313Sigor@sysoev.ru     job->work.handler = nxt_router_worker_thread_quit;
3152313Sigor@sysoev.ru     job->work.task = &job->task;
3153313Sigor@sysoev.ru     job->work.obj = NULL;
3154313Sigor@sysoev.ru     job->work.data = NULL;
3155313Sigor@sysoev.ru     job->tmcf = NULL;
3156313Sigor@sysoev.ru 
3157313Sigor@sysoev.ru     return NXT_OK;
3158313Sigor@sysoev.ru }
3159313Sigor@sysoev.ru 
3160313Sigor@sysoev.ru 
3161313Sigor@sysoev.ru static nxt_int_t
3162139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
3163139Sigor@sysoev.ru     nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
316420Sigor@sysoev.ru {
3165153Sigor@sysoev.ru     nxt_joint_job_t   *job;
316653Sigor@sysoev.ru     nxt_queue_link_t  *qlk;
316720Sigor@sysoev.ru 
316853Sigor@sysoev.ru     for (qlk = nxt_queue_first(sockets);
316953Sigor@sysoev.ru          qlk != nxt_queue_tail(sockets);
317053Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
317153Sigor@sysoev.ru     {
3172154Sigor@sysoev.ru         job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
3173153Sigor@sysoev.ru         if (nxt_slow_path(job == NULL)) {
3174139Sigor@sysoev.ru             return NXT_ERROR;
3175139Sigor@sysoev.ru         }
3176139Sigor@sysoev.ru 
3177154Sigor@sysoev.ru         job->work.next = recf->jobs;
3178154Sigor@sysoev.ru         recf->jobs = &job->work;
3179154Sigor@sysoev.ru 
3180153Sigor@sysoev.ru         job->task = tmcf->engine->task;
3181153Sigor@sysoev.ru         job->work.handler = nxt_router_listen_socket_delete;
3182153Sigor@sysoev.ru         job->work.task = &job->task;
3183153Sigor@sysoev.ru         job->work.obj = job;
3184153Sigor@sysoev.ru         job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
3185153Sigor@sysoev.ru         job->tmcf = tmcf;
3186154Sigor@sysoev.ru 
3187154Sigor@sysoev.ru         tmcf->count++;
318820Sigor@sysoev.ru     }
318920Sigor@sysoev.ru 
319053Sigor@sysoev.ru     return NXT_OK;
319153Sigor@sysoev.ru }
319220Sigor@sysoev.ru 
319320Sigor@sysoev.ru 
319453Sigor@sysoev.ru static nxt_int_t
319553Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
319653Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf)
319753Sigor@sysoev.ru {
319853Sigor@sysoev.ru     nxt_int_t                 ret;
319953Sigor@sysoev.ru     nxt_uint_t                i, threads;
320053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
320120Sigor@sysoev.ru 
320253Sigor@sysoev.ru     recf = tmcf->engines->elts;
3203591Sigor@sysoev.ru     threads = tmcf->router_conf->threads;
320420Sigor@sysoev.ru 
320553Sigor@sysoev.ru     for (i = tmcf->new_threads; i < threads; i++) {
320653Sigor@sysoev.ru         ret = nxt_router_thread_create(task, rt, recf[i].engine);
320753Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
320853Sigor@sysoev.ru             return ret;
320953Sigor@sysoev.ru         }
321020Sigor@sysoev.ru     }
321120Sigor@sysoev.ru 
321220Sigor@sysoev.ru     return NXT_OK;
321320Sigor@sysoev.ru }
321453Sigor@sysoev.ru 
321553Sigor@sysoev.ru 
321653Sigor@sysoev.ru static nxt_int_t
321753Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
321853Sigor@sysoev.ru     nxt_event_engine_t *engine)
321953Sigor@sysoev.ru {
322053Sigor@sysoev.ru     nxt_int_t            ret;
322153Sigor@sysoev.ru     nxt_thread_link_t    *link;
322253Sigor@sysoev.ru     nxt_thread_handle_t  handle;
322353Sigor@sysoev.ru 
322453Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
322553Sigor@sysoev.ru 
322653Sigor@sysoev.ru     if (nxt_slow_path(link == NULL)) {
322753Sigor@sysoev.ru         return NXT_ERROR;
322853Sigor@sysoev.ru     }
322953Sigor@sysoev.ru 
323053Sigor@sysoev.ru     link->start = nxt_router_thread_start;
323153Sigor@sysoev.ru     link->engine = engine;
323253Sigor@sysoev.ru     link->work.handler = nxt_router_thread_exit_handler;
323353Sigor@sysoev.ru     link->work.task = task;
323453Sigor@sysoev.ru     link->work.data = link;
323553Sigor@sysoev.ru 
323653Sigor@sysoev.ru     nxt_queue_insert_tail(&rt->engines, &engine->link);
323753Sigor@sysoev.ru 
323853Sigor@sysoev.ru     ret = nxt_thread_create(&handle, link);
323953Sigor@sysoev.ru 
324053Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
324153Sigor@sysoev.ru         nxt_queue_remove(&engine->link);
324253Sigor@sysoev.ru     }
324353Sigor@sysoev.ru 
324453Sigor@sysoev.ru     return ret;
324553Sigor@sysoev.ru }
324653Sigor@sysoev.ru 
324753Sigor@sysoev.ru 
324853Sigor@sysoev.ru static void
3249343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
3250343Smax.romanov@nginx.com     nxt_router_temp_conf_t *tmcf)
3251133Sigor@sysoev.ru {
3252507Smax.romanov@nginx.com     nxt_app_t  *app;
3253141Smax.romanov@nginx.com 
3254141Smax.romanov@nginx.com     nxt_queue_each(app, &router->apps, nxt_app_t, link) {
3255133Sigor@sysoev.ru 
3256753Smax.romanov@nginx.com         nxt_router_app_unlink(task, app);
3257343Smax.romanov@nginx.com 
3258141Smax.romanov@nginx.com     } nxt_queue_loop;
3259133Sigor@sysoev.ru 
3260133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->previous);
3261133Sigor@sysoev.ru     nxt_queue_add(&router->apps, &tmcf->apps);
3262133Sigor@sysoev.ru }
3263133Sigor@sysoev.ru 
3264133Sigor@sysoev.ru 
3265133Sigor@sysoev.ru static void
3266315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
326753Sigor@sysoev.ru {
326853Sigor@sysoev.ru     nxt_uint_t                n;
3269315Sigor@sysoev.ru     nxt_event_engine_t        *engine;
327053Sigor@sysoev.ru     nxt_router_engine_conf_t  *recf;
327153Sigor@sysoev.ru 
327253Sigor@sysoev.ru     recf = tmcf->engines->elts;
327353Sigor@sysoev.ru 
327453Sigor@sysoev.ru     for (n = tmcf->engines->nelts; n != 0; n--) {
3275315Sigor@sysoev.ru         engine = recf->engine;
3276315Sigor@sysoev.ru 
3277315Sigor@sysoev.ru         switch (recf->action) {
3278315Sigor@sysoev.ru 
3279315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_KEEP:
3280315Sigor@sysoev.ru             break;
3281315Sigor@sysoev.ru 
3282315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_ADD:
3283315Sigor@sysoev.ru             nxt_queue_insert_tail(&router->engines, &engine->link0);
3284315Sigor@sysoev.ru             break;
3285315Sigor@sysoev.ru 
3286315Sigor@sysoev.ru         case NXT_ROUTER_ENGINE_DELETE:
3287315Sigor@sysoev.ru             nxt_queue_remove(&engine->link0);
3288315Sigor@sysoev.ru             break;
3289315Sigor@sysoev.ru         }
3290315Sigor@sysoev.ru 
3291316Sigor@sysoev.ru         nxt_router_engine_post(engine, recf->jobs);
3292316Sigor@sysoev.ru 
329353Sigor@sysoev.ru         recf++;
329453Sigor@sysoev.ru     }
329553Sigor@sysoev.ru }
329653Sigor@sysoev.ru 
329753Sigor@sysoev.ru 
329853Sigor@sysoev.ru static void
3299315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
330053Sigor@sysoev.ru {
3301154Sigor@sysoev.ru     nxt_work_t  *work, *next;
3302154Sigor@sysoev.ru 
3303315Sigor@sysoev.ru     for (work = jobs; work != NULL; work = next) {
3304154Sigor@sysoev.ru         next = work->next;
3305154Sigor@sysoev.ru         work->next = NULL;
3306154Sigor@sysoev.ru 
3307315Sigor@sysoev.ru         nxt_event_engine_post(engine, work);
330853Sigor@sysoev.ru     }
330953Sigor@sysoev.ru }
331053Sigor@sysoev.ru 
331153Sigor@sysoev.ru 
3312320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_router_app_port_handlers = {
33131547Smax.romanov@nginx.com     .rpc_error       = nxt_port_rpc_handler,
33141547Smax.romanov@nginx.com     .mmap            = nxt_port_mmap_handler,
33151547Smax.romanov@nginx.com     .data            = nxt_port_rpc_handler,
33161547Smax.romanov@nginx.com     .oosm            = nxt_router_oosm_handler,
33171547Smax.romanov@nginx.com     .req_headers_ack = nxt_port_rpc_handler,
331888Smax.romanov@nginx.com };
331988Smax.romanov@nginx.com 
332088Smax.romanov@nginx.com 
332188Smax.romanov@nginx.com static void
332253Sigor@sysoev.ru nxt_router_thread_start(void *data)
332353Sigor@sysoev.ru {
3324141Smax.romanov@nginx.com     nxt_int_t           ret;
3325141Smax.romanov@nginx.com     nxt_port_t          *port;
332688Smax.romanov@nginx.com     nxt_task_t          *task;
33271545Smax.romanov@nginx.com     nxt_work_t          *work;
332853Sigor@sysoev.ru     nxt_thread_t        *thread;
332953Sigor@sysoev.ru     nxt_thread_link_t   *link;
333053Sigor@sysoev.ru     nxt_event_engine_t  *engine;
333153Sigor@sysoev.ru 
333253Sigor@sysoev.ru     link = data;
333353Sigor@sysoev.ru     engine = link->engine;
333488Smax.romanov@nginx.com     task = &engine->task;
333553Sigor@sysoev.ru 
333653Sigor@sysoev.ru     thread = nxt_thread();
333753Sigor@sysoev.ru 
3338165Smax.romanov@nginx.com     nxt_event_engine_thread_adopt(engine);
3339165Smax.romanov@nginx.com 
334053Sigor@sysoev.ru     /* STUB */
334153Sigor@sysoev.ru     thread->runtime = engine->task.thread->runtime;
334253Sigor@sysoev.ru 
334353Sigor@sysoev.ru     engine->task.thread = thread;
334453Sigor@sysoev.ru     engine->task.log = thread->log;
334553Sigor@sysoev.ru     thread->engine = engine;
334663Sigor@sysoev.ru     thread->task = &engine->task;
3347326Svbart@nginx.com #if 0
334853Sigor@sysoev.ru     thread->fiber = &engine->fibers->fiber;
3349326Svbart@nginx.com #endif
335053Sigor@sysoev.ru 
335163Sigor@sysoev.ru     engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
3352337Sigor@sysoev.ru     if (nxt_slow_path(engine->mem_pool == NULL)) {
3353337Sigor@sysoev.ru         return;
3354337Sigor@sysoev.ru     }
335553Sigor@sysoev.ru 
3356197Smax.romanov@nginx.com     port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
3357197Smax.romanov@nginx.com                         NXT_PROCESS_ROUTER);
3358141Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
3359141Smax.romanov@nginx.com         return;
3360141Smax.romanov@nginx.com     }
3361141Smax.romanov@nginx.com 
3362141Smax.romanov@nginx.com     ret = nxt_port_socket_init(task, port, 0);
3363141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3364343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
3365141Smax.romanov@nginx.com         return;
3366141Smax.romanov@nginx.com     }
3367141Smax.romanov@nginx.com 
33681555Smax.romanov@nginx.com     ret = nxt_router_port_queue_init(task, port);
33691555Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
33701555Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
33711555Smax.romanov@nginx.com         return;
33721555Smax.romanov@nginx.com     }
33731555Smax.romanov@nginx.com 
3374141Smax.romanov@nginx.com     engine->port = port;
3375141Smax.romanov@nginx.com 
3376320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_router_app_port_handlers);
3377141Smax.romanov@nginx.com 
33781545Smax.romanov@nginx.com     work = nxt_zalloc(sizeof(nxt_work_t));
33791545Smax.romanov@nginx.com     if (nxt_slow_path(work == NULL)) {
33801545Smax.romanov@nginx.com         return;
33811545Smax.romanov@nginx.com     }
33821545Smax.romanov@nginx.com 
33831545Smax.romanov@nginx.com     work->handler = nxt_router_rt_add_port;
33841545Smax.romanov@nginx.com     work->task = link->work.task;
33851545Smax.romanov@nginx.com     work->obj = work;
33861545Smax.romanov@nginx.com     work->data = port;
33871545Smax.romanov@nginx.com 
33881545Smax.romanov@nginx.com     nxt_event_engine_post(link->work.task->thread->engine, work);
33891545Smax.romanov@nginx.com 
339053Sigor@sysoev.ru     nxt_event_engine_start(engine);
339153Sigor@sysoev.ru }
339253Sigor@sysoev.ru 
339353Sigor@sysoev.ru 
339453Sigor@sysoev.ru static void
33951545Smax.romanov@nginx.com nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data)
33961545Smax.romanov@nginx.com {
33971545Smax.romanov@nginx.com     nxt_int_t      res;
33981545Smax.romanov@nginx.com     nxt_port_t     *port;
33991545Smax.romanov@nginx.com     nxt_runtime_t  *rt;
34001545Smax.romanov@nginx.com 
34011545Smax.romanov@nginx.com     rt = task->thread->runtime;
34021545Smax.romanov@nginx.com     port = data;
34031545Smax.romanov@nginx.com 
34041545Smax.romanov@nginx.com     nxt_free(obj);
34051545Smax.romanov@nginx.com 
34061545Smax.romanov@nginx.com     res = nxt_port_hash_add(&rt->ports, port);
34071545Smax.romanov@nginx.com 
34081545Smax.romanov@nginx.com     if (nxt_fast_path(res == NXT_OK)) {
34091545Smax.romanov@nginx.com         nxt_port_use(task, port, 1);
34101545Smax.romanov@nginx.com     }
34111545Smax.romanov@nginx.com }
34121545Smax.romanov@nginx.com 
34131545Smax.romanov@nginx.com 
34141545Smax.romanov@nginx.com static void
341553Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
341653Sigor@sysoev.ru {
3417153Sigor@sysoev.ru     nxt_joint_job_t          *job;
3418359Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
3419359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
342053Sigor@sysoev.ru     nxt_listen_socket_t      *ls;
3421359Sigor@sysoev.ru     nxt_thread_spinlock_t    *lock;
342253Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
342353Sigor@sysoev.ru 
3424153Sigor@sysoev.ru     job = obj;
342553Sigor@sysoev.ru     joint = data;
342653Sigor@sysoev.ru 
3427159Sigor@sysoev.ru     nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
3428159Sigor@sysoev.ru 
3429359Sigor@sysoev.ru     skcf = joint->socket_conf;
3430359Sigor@sysoev.ru     ls = skcf->listen;
3431359Sigor@sysoev.ru 
3432359Sigor@sysoev.ru     lev = nxt_listen_event(task, ls);
3433359Sigor@sysoev.ru     if (nxt_slow_path(lev == NULL)) {
3434359Sigor@sysoev.ru         nxt_router_listen_socket_release(task, skcf);
343553Sigor@sysoev.ru         return;
343653Sigor@sysoev.ru     }
343753Sigor@sysoev.ru 
3438359Sigor@sysoev.ru     lev->socket.data = joint;
3439359Sigor@sysoev.ru 
3440359Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
3441359Sigor@sysoev.ru 
3442359Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
3443359Sigor@sysoev.ru     ls->count++;
3444359Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
3445139Sigor@sysoev.ru 
3446153Sigor@sysoev.ru     job->work.next = NULL;
3447153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
3448153Sigor@sysoev.ru 
3449153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
345053Sigor@sysoev.ru }
345153Sigor@sysoev.ru 
345253Sigor@sysoev.ru 
345353Sigor@sysoev.ru nxt_inline nxt_listen_event_t *
345453Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections,
345553Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
345653Sigor@sysoev.ru {
3457115Sigor@sysoev.ru     nxt_socket_t        fd;
3458115Sigor@sysoev.ru     nxt_queue_link_t    *qlk;
3459359Sigor@sysoev.ru     nxt_listen_event_t  *lev;
3460359Sigor@sysoev.ru 
3461359Sigor@sysoev.ru     fd = skcf->listen->socket;
346253Sigor@sysoev.ru 
3463115Sigor@sysoev.ru     for (qlk = nxt_queue_first(listen_connections);
3464115Sigor@sysoev.ru          qlk != nxt_queue_tail(listen_connections);
3465115Sigor@sysoev.ru          qlk = nxt_queue_next(qlk))
346653Sigor@sysoev.ru     {
3467359Sigor@sysoev.ru         lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
3468359Sigor@sysoev.ru 
3469359Sigor@sysoev.ru         if (fd == lev->socket.fd) {
3470359Sigor@sysoev.ru             return lev;
347153Sigor@sysoev.ru         }
347253Sigor@sysoev.ru     }
347353Sigor@sysoev.ru 
347453Sigor@sysoev.ru     return NULL;
347553Sigor@sysoev.ru }
347653Sigor@sysoev.ru 
347753Sigor@sysoev.ru 
347853Sigor@sysoev.ru static void
347953Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
348053Sigor@sysoev.ru {
3481153Sigor@sysoev.ru     nxt_joint_job_t          *job;
348253Sigor@sysoev.ru     nxt_event_engine_t       *engine;
3483359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
348453Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint, *old;
348553Sigor@sysoev.ru 
3486153Sigor@sysoev.ru     job = obj;
348753Sigor@sysoev.ru     joint = data;
348853Sigor@sysoev.ru 
3489139Sigor@sysoev.ru     engine = task->thread->engine;
3490139Sigor@sysoev.ru 
3491159Sigor@sysoev.ru     nxt_queue_insert_tail(&engine->joints, &joint->link);
3492159Sigor@sysoev.ru 
3493359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections,
3494359Sigor@sysoev.ru                                   joint->socket_conf);
3495359Sigor@sysoev.ru 
3496359Sigor@sysoev.ru     old = lev->socket.data;
3497359Sigor@sysoev.ru     lev->socket.data = joint;
3498359Sigor@sysoev.ru     lev->listen = joint->socket_conf->listen;
349953Sigor@sysoev.ru 
3500153Sigor@sysoev.ru     job->work.next = NULL;
3501153Sigor@sysoev.ru     job->work.handler = nxt_router_conf_wait;
3502153Sigor@sysoev.ru 
3503153Sigor@sysoev.ru     nxt_event_engine_post(job->tmcf->engine, &job->work);
3504139Sigor@sysoev.ru 
3505181Smax.romanov@nginx.com     /*
3506181Smax.romanov@nginx.com      * The task is allocated from configuration temporary
3507181Smax.romanov@nginx.com      * memory pool so it can be freed after engine post operation.
3508181Smax.romanov@nginx.com      */
3509181Smax.romanov@nginx.com 
3510181Smax.romanov@nginx.com     nxt_router_conf_release(&engine->task, old);
351153Sigor@sysoev.ru }
351253Sigor@sysoev.ru 
351353Sigor@sysoev.ru 
351453Sigor@sysoev.ru static void
351553Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
351653Sigor@sysoev.ru {
35171867Smax.romanov@nginx.com     nxt_socket_conf_t        *skcf;
35181867Smax.romanov@nginx.com     nxt_listen_event_t       *lev;
35191867Smax.romanov@nginx.com     nxt_event_engine_t       *engine;
35201867Smax.romanov@nginx.com     nxt_socket_conf_joint_t  *joint;
35211867Smax.romanov@nginx.com 
352253Sigor@sysoev.ru     skcf = data;
352353Sigor@sysoev.ru 
3524139Sigor@sysoev.ru     engine = task->thread->engine;
3525139Sigor@sysoev.ru 
3526359Sigor@sysoev.ru     lev = nxt_router_listen_event(&engine->listen_connections, skcf);
3527359Sigor@sysoev.ru 
3528359Sigor@sysoev.ru     nxt_fd_event_delete(engine, &lev->socket);
352953Sigor@sysoev.ru 
3530163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket delete: %d", engine,
3531359Sigor@sysoev.ru               lev->socket.fd);
3532359Sigor@sysoev.ru 
35331867Smax.romanov@nginx.com     joint = lev->socket.data;
35341867Smax.romanov@nginx.com     joint->close_job = obj;
35351867Smax.romanov@nginx.com 
3536359Sigor@sysoev.ru     lev->timer.handler = nxt_router_listen_socket_close;
3537359Sigor@sysoev.ru     lev->timer.work_queue = &engine->fast_work_queue;
3538359Sigor@sysoev.ru 
3539359Sigor@sysoev.ru     nxt_timer_add(engine, &lev->timer, 0);
354053Sigor@sysoev.ru }
354153Sigor@sysoev.ru 
354253Sigor@sysoev.ru 
354353Sigor@sysoev.ru static void
3544313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
3545313Sigor@sysoev.ru {
3546313Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3547313Sigor@sysoev.ru 
3548313Sigor@sysoev.ru     nxt_debug(task, "router worker thread quit");
3549313Sigor@sysoev.ru 
3550313Sigor@sysoev.ru     engine = task->thread->engine;
3551313Sigor@sysoev.ru 
3552313Sigor@sysoev.ru     engine->shutdown = 1;
3553313Sigor@sysoev.ru 
3554313Sigor@sysoev.ru     if (nxt_queue_is_empty(&engine->joints)) {
3555313Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3556313Sigor@sysoev.ru     }
3557313Sigor@sysoev.ru }
3558313Sigor@sysoev.ru 
3559313Sigor@sysoev.ru 
3560313Sigor@sysoev.ru static void
356153Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
356253Sigor@sysoev.ru {
356353Sigor@sysoev.ru     nxt_timer_t              *timer;
35641867Smax.romanov@nginx.com     nxt_joint_job_t          *job;
3565359Sigor@sysoev.ru     nxt_listen_event_t       *lev;
356653Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
356753Sigor@sysoev.ru 
356853Sigor@sysoev.ru     timer = obj;
3569359Sigor@sysoev.ru     lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
357053Sigor@sysoev.ru 
3571163Smax.romanov@nginx.com     nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
3572359Sigor@sysoev.ru               lev->socket.fd);
3573359Sigor@sysoev.ru 
3574359Sigor@sysoev.ru     nxt_queue_remove(&lev->link);
3575359Sigor@sysoev.ru 
3576683Sigor@sysoev.ru     joint = lev->socket.data;
3577683Sigor@sysoev.ru     lev->socket.data = NULL;
3578683Sigor@sysoev.ru 
35791881Smax.romanov@nginx.com     /* 'task' refers to lev->task and we cannot use after nxt_free() */
35801881Smax.romanov@nginx.com     task = &task->thread->engine->task;
35811881Smax.romanov@nginx.com 
35821881Smax.romanov@nginx.com     nxt_router_listen_socket_release(task, joint->socket_conf);
35831881Smax.romanov@nginx.com 
35841867Smax.romanov@nginx.com     job = joint->close_job;
35851867Smax.romanov@nginx.com     job->work.next = NULL;
35861867Smax.romanov@nginx.com     job->work.handler = nxt_router_conf_wait;
35871867Smax.romanov@nginx.com 
35881867Smax.romanov@nginx.com     nxt_event_engine_post(job->tmcf->engine, &job->work);
35891867Smax.romanov@nginx.com 
3590683Sigor@sysoev.ru     nxt_router_listen_event_release(task, lev, joint);
359153Sigor@sysoev.ru }
359253Sigor@sysoev.ru 
359353Sigor@sysoev.ru 
359453Sigor@sysoev.ru static void
3595359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
359653Sigor@sysoev.ru {
3597359Sigor@sysoev.ru     nxt_listen_socket_t    *ls;
359853Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
359953Sigor@sysoev.ru 
3600359Sigor@sysoev.ru     ls = skcf->listen;
3601118Sigor@sysoev.ru     lock = &skcf->router_conf->router->lock;
360253Sigor@sysoev.ru 
360353Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
360453Sigor@sysoev.ru 
3605359Sigor@sysoev.ru     nxt_debug(task, "engine %p: listen socket release: ls->count %D",
3606359Sigor@sysoev.ru               task->thread->engine, ls->count);
3607359Sigor@sysoev.ru 
3608359Sigor@sysoev.ru     if (--ls->count != 0) {
3609359Sigor@sysoev.ru         ls = NULL;
361053Sigor@sysoev.ru     }
361153Sigor@sysoev.ru 
361253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
361353Sigor@sysoev.ru 
3614359Sigor@sysoev.ru     if (ls != NULL) {
3615359Sigor@sysoev.ru         nxt_socket_close(task, ls->socket);
3616359Sigor@sysoev.ru         nxt_free(ls);
361753Sigor@sysoev.ru     }
361853Sigor@sysoev.ru }
361953Sigor@sysoev.ru 
362053Sigor@sysoev.ru 
3621683Sigor@sysoev.ru void
3622683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3623683Sigor@sysoev.ru     nxt_socket_conf_joint_t *joint)
3624683Sigor@sysoev.ru {
3625683Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3626683Sigor@sysoev.ru 
3627683Sigor@sysoev.ru     nxt_debug(task, "listen event count: %D", lev->count);
3628683Sigor@sysoev.ru 
36291541Smax.romanov@nginx.com     engine = task->thread->engine;
36301541Smax.romanov@nginx.com 
3631683Sigor@sysoev.ru     if (--lev->count == 0) {
36321535Smax.romanov@nginx.com         if (lev->next != NULL) {
36331541Smax.romanov@nginx.com             nxt_sockaddr_cache_free(engine, lev->next);
36341541Smax.romanov@nginx.com 
36351535Smax.romanov@nginx.com             nxt_conn_free(task, lev->next);
36361535Smax.romanov@nginx.com         }
36371535Smax.romanov@nginx.com 
3638683Sigor@sysoev.ru         nxt_free(lev);
3639683Sigor@sysoev.ru     }
3640683Sigor@sysoev.ru 
3641683Sigor@sysoev.ru     if (joint != NULL) {
3642683Sigor@sysoev.ru         nxt_router_conf_release(task, joint);
3643683Sigor@sysoev.ru     }
3644683Sigor@sysoev.ru 
3645683Sigor@sysoev.ru     if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3646683Sigor@sysoev.ru         nxt_thread_exit(task->thread);
3647683Sigor@sysoev.ru     }
3648683Sigor@sysoev.ru }
3649683Sigor@sysoev.ru 
3650683Sigor@sysoev.ru 
3651683Sigor@sysoev.ru void
365253Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
365353Sigor@sysoev.ru {
365453Sigor@sysoev.ru     nxt_socket_conf_t      *skcf;
365553Sigor@sysoev.ru     nxt_router_conf_t      *rtcf;
365653Sigor@sysoev.ru     nxt_thread_spinlock_t  *lock;
365753Sigor@sysoev.ru 
3658163Smax.romanov@nginx.com     nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
365953Sigor@sysoev.ru 
366053Sigor@sysoev.ru     if (--joint->count != 0) {
366153Sigor@sysoev.ru         return;
366253Sigor@sysoev.ru     }
366353Sigor@sysoev.ru 
366453Sigor@sysoev.ru     nxt_queue_remove(&joint->link);
366553Sigor@sysoev.ru 
3666530Sigor@sysoev.ru     /*
3667530Sigor@sysoev.ru      * The joint content can not be safely used after the critical
3668530Sigor@sysoev.ru      * section protected by the spinlock because its memory pool may
3669530Sigor@sysoev.ru      * be already destroyed by another thread.
3670530Sigor@sysoev.ru      */
367153Sigor@sysoev.ru     skcf = joint->socket_conf;
367253Sigor@sysoev.ru     rtcf = skcf->router_conf;
367353Sigor@sysoev.ru     lock = &rtcf->router->lock;
367453Sigor@sysoev.ru 
367553Sigor@sysoev.ru     nxt_thread_spin_lock(lock);
367653Sigor@sysoev.ru 
3677163Smax.romanov@nginx.com     nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3678163Smax.romanov@nginx.com               rtcf, rtcf->count);
3679163Smax.romanov@nginx.com 
368053Sigor@sysoev.ru     if (--skcf->count != 0) {
3681952Sigor@sysoev.ru         skcf = NULL;
368253Sigor@sysoev.ru         rtcf = NULL;
368353Sigor@sysoev.ru 
368453Sigor@sysoev.ru     } else {
368553Sigor@sysoev.ru         nxt_queue_remove(&skcf->link);
368653Sigor@sysoev.ru 
368753Sigor@sysoev.ru         if (--rtcf->count != 0) {
368853Sigor@sysoev.ru             rtcf = NULL;
368953Sigor@sysoev.ru         }
369053Sigor@sysoev.ru     }
369153Sigor@sysoev.ru 
369253Sigor@sysoev.ru     nxt_thread_spin_unlock(lock);
369353Sigor@sysoev.ru 
3694952Sigor@sysoev.ru #if (NXT_TLS)
36951563Svbart@nginx.com     if (skcf != NULL && skcf->tls != NULL) {
36961563Svbart@nginx.com         task->thread->runtime->tls->server_free(task, skcf->tls);
36971563Svbart@nginx.com     }
3698952Sigor@sysoev.ru #endif
3699952Sigor@sysoev.ru 
3700141Smax.romanov@nginx.com     /* TODO remove engine->port */
3701141Smax.romanov@nginx.com 
370253Sigor@sysoev.ru     if (rtcf != NULL) {
3703115Sigor@sysoev.ru         nxt_debug(task, "old router conf is destroyed");
3704131Smax.romanov@nginx.com 
37051563Svbart@nginx.com         nxt_router_apps_hash_use(task, rtcf, -1);
3706964Sigor@sysoev.ru 
3707630Svbart@nginx.com         nxt_router_access_log_release(task, lock, rtcf->access_log);
3708630Svbart@nginx.com 
3709131Smax.romanov@nginx.com         nxt_mp_thread_adopt(rtcf->mem_pool);
3710131Smax.romanov@nginx.com 
371165Sigor@sysoev.ru         nxt_mp_destroy(rtcf->mem_pool);
371253Sigor@sysoev.ru     }
371353Sigor@sysoev.ru }
371453Sigor@sysoev.ru 
371553Sigor@sysoev.ru 
371653Sigor@sysoev.ru static void
3717630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3718630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3719630Svbart@nginx.com {
3720630Svbart@nginx.com     size_t     size;
3721630Svbart@nginx.com     u_char     *buf, *p;
3722630Svbart@nginx.com     nxt_off_t  bytes;
3723630Svbart@nginx.com 
3724630Svbart@nginx.com     static nxt_time_string_t  date_cache = {
3725630Svbart@nginx.com         (nxt_atomic_uint_t) -1,
3726630Svbart@nginx.com         nxt_router_access_log_date,
3727630Svbart@nginx.com         "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3728703Svbart@nginx.com         nxt_length("31/Dec/1986:19:40:00 +0300"),
3729630Svbart@nginx.com         NXT_THREAD_TIME_LOCAL,
3730630Svbart@nginx.com         NXT_THREAD_TIME_SEC,
3731630Svbart@nginx.com     };
3732630Svbart@nginx.com 
3733630Svbart@nginx.com     size = r->remote->address_length
3734630Svbart@nginx.com            + 6                  /* ' - - [' */
3735630Svbart@nginx.com            + date_cache.size
3736630Svbart@nginx.com            + 3                  /* '] "' */
3737630Svbart@nginx.com            + r->method->length
3738630Svbart@nginx.com            + 1                  /* space */
3739630Svbart@nginx.com            + r->target.length
3740630Svbart@nginx.com            + 1                  /* space */
3741630Svbart@nginx.com            + r->version.length
3742630Svbart@nginx.com            + 2                  /* '" ' */
3743630Svbart@nginx.com            + 3                  /* status */
3744630Svbart@nginx.com            + 1                  /* space */
3745630Svbart@nginx.com            + NXT_OFF_T_LEN
3746630Svbart@nginx.com            + 2                  /* ' "' */
3747630Svbart@nginx.com            + (r->referer != NULL ? r->referer->value_length : 1)
3748630Svbart@nginx.com            + 3                  /* '" "' */
3749630Svbart@nginx.com            + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3750630Svbart@nginx.com            + 2                  /* '"\n' */
3751630Svbart@nginx.com     ;
3752630Svbart@nginx.com 
3753630Svbart@nginx.com     buf = nxt_mp_nget(r->mem_pool, size);
3754630Svbart@nginx.com     if (nxt_slow_path(buf == NULL)) {
3755630Svbart@nginx.com         return;
3756630Svbart@nginx.com     }
3757630Svbart@nginx.com 
3758630Svbart@nginx.com     p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3759630Svbart@nginx.com                    r->remote->address_length);
3760630Svbart@nginx.com 
3761630Svbart@nginx.com     p = nxt_cpymem(p, " - - [", 6);
3762630Svbart@nginx.com 
3763630Svbart@nginx.com     p = nxt_thread_time_string(task->thread, &date_cache, p);
3764630Svbart@nginx.com 
3765630Svbart@nginx.com     p = nxt_cpymem(p, "] \"", 3);
3766630Svbart@nginx.com 
3767630Svbart@nginx.com     if (r->method->length != 0) {
3768630Svbart@nginx.com         p = nxt_cpymem(p, r->method->start, r->method->length);
3769630Svbart@nginx.com 
3770630Svbart@nginx.com         if (r->target.length != 0) {
3771630Svbart@nginx.com             *p++ = ' ';
3772630Svbart@nginx.com             p = nxt_cpymem(p, r->target.start, r->target.length);
3773630Svbart@nginx.com 
3774630Svbart@nginx.com             if (r->version.length != 0) {
3775630Svbart@nginx.com                 *p++ = ' ';
3776630Svbart@nginx.com                 p = nxt_cpymem(p, r->version.start, r->version.length);
3777630Svbart@nginx.com             }
3778630Svbart@nginx.com         }
3779630Svbart@nginx.com 
3780630Svbart@nginx.com     } else {
3781630Svbart@nginx.com         *p++ = '-';
3782630Svbart@nginx.com     }
3783630Svbart@nginx.com 
3784630Svbart@nginx.com     p = nxt_cpymem(p, "\" ", 2);
3785630Svbart@nginx.com 
3786630Svbart@nginx.com     p = nxt_sprintf(p, p + 3, "%03d", r->status);
3787630Svbart@nginx.com 
3788630Svbart@nginx.com     *p++ = ' ';
3789630Svbart@nginx.com 
37901112Sigor@sysoev.ru     bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3791630Svbart@nginx.com 
3792630Svbart@nginx.com     p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3793630Svbart@nginx.com 
3794630Svbart@nginx.com     p = nxt_cpymem(p, " \"", 2);
3795630Svbart@nginx.com 
3796630Svbart@nginx.com     if (r->referer != NULL) {
3797630Svbart@nginx.com         p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3798630Svbart@nginx.com 
3799630Svbart@nginx.com     } else {
3800630Svbart@nginx.com         *p++ = '-';
3801630Svbart@nginx.com     }
3802630Svbart@nginx.com 
3803630Svbart@nginx.com     p = nxt_cpymem(p, "\" \"", 3);
3804630Svbart@nginx.com 
3805630Svbart@nginx.com     if (r->user_agent != NULL) {
3806630Svbart@nginx.com         p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3807630Svbart@nginx.com 
3808630Svbart@nginx.com     } else {
3809630Svbart@nginx.com         *p++ = '-';
3810630Svbart@nginx.com     }
3811630Svbart@nginx.com 
3812630Svbart@nginx.com     p = nxt_cpymem(p, "\"\n", 2);
3813630Svbart@nginx.com 
3814630Svbart@nginx.com     nxt_fd_write(access_log->fd, buf, p - buf);
3815630Svbart@nginx.com }
3816630Svbart@nginx.com 
3817630Svbart@nginx.com 
3818630Svbart@nginx.com static u_char *
3819630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3820630Svbart@nginx.com     size_t size, const char *format)
3821630Svbart@nginx.com {
3822630Svbart@nginx.com     u_char  sign;
3823630Svbart@nginx.com     time_t  gmtoff;
3824630Svbart@nginx.com 
3825630Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3826630Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3827630Svbart@nginx.com 
3828630Svbart@nginx.com     gmtoff = nxt_timezone(tm) / 60;
3829630Svbart@nginx.com 
3830630Svbart@nginx.com     if (gmtoff < 0) {
3831630Svbart@nginx.com         gmtoff = -gmtoff;
3832630Svbart@nginx.com         sign = '-';
3833630Svbart@nginx.com 
3834630Svbart@nginx.com     } else {
3835630Svbart@nginx.com         sign = '+';
3836630Svbart@nginx.com     }
3837630Svbart@nginx.com 
3838630Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
3839630Svbart@nginx.com                        tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3840630Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec,
3841630Svbart@nginx.com                        sign, gmtoff / 60, gmtoff % 60);
3842630Svbart@nginx.com }
3843630Svbart@nginx.com 
3844630Svbart@nginx.com 
3845630Svbart@nginx.com static void
3846630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3847630Svbart@nginx.com {
3848630Svbart@nginx.com     uint32_t                 stream;
3849648Svbart@nginx.com     nxt_int_t                ret;
3850630Svbart@nginx.com     nxt_buf_t                *b;
3851630Svbart@nginx.com     nxt_port_t               *main_port, *router_port;
3852630Svbart@nginx.com     nxt_runtime_t            *rt;
3853630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3854630Svbart@nginx.com 
3855630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3856630Svbart@nginx.com 
3857630Svbart@nginx.com     b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3858630Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3859630Svbart@nginx.com         goto fail;
3860630Svbart@nginx.com     }
3861630Svbart@nginx.com 
38621940Sz.hong@f5.com     b->completion_handler = nxt_buf_dummy_completion;
38631566Smax.romanov@nginx.com 
3864630Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3865630Svbart@nginx.com     *b->mem.free++ = '\0';
3866630Svbart@nginx.com 
3867630Svbart@nginx.com     rt = task->thread->runtime;
3868630Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3869630Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3870630Svbart@nginx.com 
3871630Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
3872630Svbart@nginx.com                                            nxt_router_access_log_ready,
3873630Svbart@nginx.com                                            nxt_router_access_log_error,
3874630Svbart@nginx.com                                            -1, tmcf);
3875630Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
3876630Svbart@nginx.com         goto fail;
3877630Svbart@nginx.com     }
3878630Svbart@nginx.com 
3879648Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3880648Svbart@nginx.com                                 stream, router_port->id, b);
3881648Svbart@nginx.com 
3882648Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3883648Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
3884648Svbart@nginx.com         goto fail;
3885648Svbart@nginx.com     }
3886630Svbart@nginx.com 
3887630Svbart@nginx.com     return;
3888630Svbart@nginx.com 
3889630Svbart@nginx.com fail:
3890630Svbart@nginx.com 
3891630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3892630Svbart@nginx.com }
3893630Svbart@nginx.com 
3894630Svbart@nginx.com 
3895630Svbart@nginx.com static void
3896630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3897630Svbart@nginx.com     void *data)
3898630Svbart@nginx.com {
3899630Svbart@nginx.com     nxt_router_temp_conf_t   *tmcf;
3900630Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3901630Svbart@nginx.com 
3902630Svbart@nginx.com     tmcf = data;
3903630Svbart@nginx.com 
3904630Svbart@nginx.com     access_log = tmcf->router_conf->access_log;
3905630Svbart@nginx.com 
39061558Smax.romanov@nginx.com     access_log->fd = msg->fd[0];
3907630Svbart@nginx.com 
3908630Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3909630Svbart@nginx.com                        nxt_router_conf_apply, task, tmcf, NULL);
3910630Svbart@nginx.com }
3911630Svbart@nginx.com 
3912630Svbart@nginx.com 
3913630Svbart@nginx.com static void
3914630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3915630Svbart@nginx.com     void *data)
3916630Svbart@nginx.com {
3917630Svbart@nginx.com     nxt_router_temp_conf_t  *tmcf;
3918630Svbart@nginx.com 
3919630Svbart@nginx.com     tmcf = data;
3920630Svbart@nginx.com 
3921630Svbart@nginx.com     nxt_router_conf_error(task, tmcf);
3922630Svbart@nginx.com }
3923630Svbart@nginx.com 
3924630Svbart@nginx.com 
3925630Svbart@nginx.com static void
3926630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3927630Svbart@nginx.com     nxt_router_access_log_t *access_log)
3928630Svbart@nginx.com {
3929630Svbart@nginx.com     if (access_log == NULL) {
3930630Svbart@nginx.com         return;
3931630Svbart@nginx.com     }
3932630Svbart@nginx.com 
3933630Svbart@nginx.com     nxt_thread_spin_lock(lock);
3934630Svbart@nginx.com 
3935630Svbart@nginx.com     if (--access_log->count != 0) {
3936630Svbart@nginx.com         access_log = NULL;
3937630Svbart@nginx.com     }
3938630Svbart@nginx.com 
3939630Svbart@nginx.com     nxt_thread_spin_unlock(lock);
3940630Svbart@nginx.com 
3941630Svbart@nginx.com     if (access_log != NULL) {
3942630Svbart@nginx.com 
3943630Svbart@nginx.com         if (access_log->fd != -1) {
3944630Svbart@nginx.com             nxt_fd_close(access_log->fd);
3945630Svbart@nginx.com         }
3946630Svbart@nginx.com 
3947630Svbart@nginx.com         nxt_free(access_log);
3948630Svbart@nginx.com     }
3949630Svbart@nginx.com }
3950630Svbart@nginx.com 
3951630Svbart@nginx.com 
3952631Svbart@nginx.com typedef struct {
3953631Svbart@nginx.com     nxt_mp_t                 *mem_pool;
3954631Svbart@nginx.com     nxt_router_access_log_t  *access_log;
3955631Svbart@nginx.com } nxt_router_access_log_reopen_t;
3956631Svbart@nginx.com 
3957631Svbart@nginx.com 
39581552Smax.romanov@nginx.com static void
3959631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3960631Svbart@nginx.com {
3961631Svbart@nginx.com     nxt_mp_t                        *mp;
3962631Svbart@nginx.com     uint32_t                        stream;
3963631Svbart@nginx.com     nxt_int_t                       ret;
3964631Svbart@nginx.com     nxt_buf_t                       *b;
3965631Svbart@nginx.com     nxt_port_t                      *main_port, *router_port;
3966631Svbart@nginx.com     nxt_runtime_t                   *rt;
3967631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
3968631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
3969631Svbart@nginx.com 
3970631Svbart@nginx.com     access_log = nxt_router->access_log;
3971631Svbart@nginx.com 
3972631Svbart@nginx.com     if (access_log == NULL) {
3973631Svbart@nginx.com         return;
3974631Svbart@nginx.com     }
3975631Svbart@nginx.com 
3976631Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
3977631Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
3978631Svbart@nginx.com         return;
3979631Svbart@nginx.com     }
3980631Svbart@nginx.com 
3981631Svbart@nginx.com     reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3982631Svbart@nginx.com     if (nxt_slow_path(reopen == NULL)) {
3983631Svbart@nginx.com         goto fail;
3984631Svbart@nginx.com     }
3985631Svbart@nginx.com 
3986631Svbart@nginx.com     reopen->mem_pool = mp;
3987631Svbart@nginx.com     reopen->access_log = access_log;
3988631Svbart@nginx.com 
3989631Svbart@nginx.com     b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3990631Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
3991631Svbart@nginx.com         goto fail;
3992631Svbart@nginx.com     }
3993631Svbart@nginx.com 
3994651Svbart@nginx.com     b->completion_handler = nxt_router_access_log_reopen_completion;
3995651Svbart@nginx.com 
3996631Svbart@nginx.com     nxt_buf_cpystr(b, &access_log->path);
3997631Svbart@nginx.com     *b->mem.free++ = '\0';
3998631Svbart@nginx.com 
3999631Svbart@nginx.com     rt = task->thread->runtime;
4000631Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
4001631Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
4002631Svbart@nginx.com 
4003631Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, router_port,
4004631Svbart@nginx.com                                            nxt_router_access_log_reopen_ready,
4005631Svbart@nginx.com                                            nxt_router_access_log_reopen_error,
4006631Svbart@nginx.com                                            -1, reopen);
4007631Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
4008631Svbart@nginx.com         goto fail;
4009631Svbart@nginx.com     }
4010631Svbart@nginx.com 
4011631Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
4012631Svbart@nginx.com                                 stream, router_port->id, b);
4013631Svbart@nginx.com 
4014631Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4015631Svbart@nginx.com         nxt_port_rpc_cancel(task, router_port, stream);
4016631Svbart@nginx.com         goto fail;
4017631Svbart@nginx.com     }
4018631Svbart@nginx.com 
4019651Svbart@nginx.com     nxt_mp_retain(mp);
4020651Svbart@nginx.com 
4021631Svbart@nginx.com     return;
4022631Svbart@nginx.com 
4023631Svbart@nginx.com fail:
4024631Svbart@nginx.com 
4025631Svbart@nginx.com     nxt_mp_destroy(mp);
4026631Svbart@nginx.com }
4027631Svbart@nginx.com 
4028631Svbart@nginx.com 
4029631Svbart@nginx.com static void
4030651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
4031651Svbart@nginx.com {
4032651Svbart@nginx.com     nxt_mp_t   *mp;
4033651Svbart@nginx.com     nxt_buf_t  *b;
4034651Svbart@nginx.com 
4035651Svbart@nginx.com     b = obj;
4036651Svbart@nginx.com     mp = b->data;
4037651Svbart@nginx.com 
4038651Svbart@nginx.com     nxt_mp_release(mp);
4039651Svbart@nginx.com }
4040651Svbart@nginx.com 
4041651Svbart@nginx.com 
4042651Svbart@nginx.com static void
4043631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4044631Svbart@nginx.com     void *data)
4045631Svbart@nginx.com {
4046631Svbart@nginx.com     nxt_router_access_log_t         *access_log;
4047631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
4048631Svbart@nginx.com 
4049631Svbart@nginx.com     reopen = data;
4050631Svbart@nginx.com 
4051631Svbart@nginx.com     access_log = reopen->access_log;
4052631Svbart@nginx.com 
4053631Svbart@nginx.com     if (access_log == nxt_router->access_log) {
4054631Svbart@nginx.com 
40551558Smax.romanov@nginx.com         if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
4056631Svbart@nginx.com             nxt_alert(task, "dup2(%FD, %FD) failed %E",
40571558Smax.romanov@nginx.com                       msg->fd[0], access_log->fd, nxt_errno);
4058631Svbart@nginx.com         }
4059631Svbart@nginx.com     }
4060631Svbart@nginx.com 
40611558Smax.romanov@nginx.com     nxt_fd_close(msg->fd[0]);
4062651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
4063631Svbart@nginx.com }
4064631Svbart@nginx.com 
4065631Svbart@nginx.com 
4066631Svbart@nginx.com static void
4067631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4068631Svbart@nginx.com     void *data)
4069631Svbart@nginx.com {
4070631Svbart@nginx.com     nxt_router_access_log_reopen_t  *reopen;
4071631Svbart@nginx.com 
4072631Svbart@nginx.com     reopen = data;
4073631Svbart@nginx.com 
4074651Svbart@nginx.com     nxt_mp_release(reopen->mem_pool);
4075631Svbart@nginx.com }
4076631Svbart@nginx.com 
4077631Svbart@nginx.com 
4078630Svbart@nginx.com static void
407953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
408053Sigor@sysoev.ru {
4081141Smax.romanov@nginx.com     nxt_port_t           *port;
408253Sigor@sysoev.ru     nxt_thread_link_t    *link;
408353Sigor@sysoev.ru     nxt_event_engine_t   *engine;
408453Sigor@sysoev.ru     nxt_thread_handle_t  handle;
408553Sigor@sysoev.ru 
40861810Smax.romanov@nginx.com     handle = (nxt_thread_handle_t) (uintptr_t) obj;
408753Sigor@sysoev.ru     link = data;
408853Sigor@sysoev.ru 
408953Sigor@sysoev.ru     nxt_thread_wait(handle);
409053Sigor@sysoev.ru 
409153Sigor@sysoev.ru     engine = link->engine;
409253Sigor@sysoev.ru 
409353Sigor@sysoev.ru     nxt_queue_remove(&engine->link);
409453Sigor@sysoev.ru 
4095141Smax.romanov@nginx.com     port = engine->port;
4096141Smax.romanov@nginx.com 
4097141Smax.romanov@nginx.com     // TODO notify all apps
4098141Smax.romanov@nginx.com 
4099343Smax.romanov@nginx.com     port->engine = task->thread->engine;
4100163Smax.romanov@nginx.com     nxt_mp_thread_adopt(port->mem_pool);
4101343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
4102163Smax.romanov@nginx.com 
4103163Smax.romanov@nginx.com     nxt_mp_thread_adopt(engine->mem_pool);
410463Sigor@sysoev.ru     nxt_mp_destroy(engine->mem_pool);
410553Sigor@sysoev.ru 
410653Sigor@sysoev.ru     nxt_event_engine_free(engine);
410753Sigor@sysoev.ru 
410853Sigor@sysoev.ru     nxt_free(link);
410953Sigor@sysoev.ru }
411053Sigor@sysoev.ru 
411153Sigor@sysoev.ru 
411253Sigor@sysoev.ru static void
4113318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4114318Smax.romanov@nginx.com     void *data)
411588Smax.romanov@nginx.com {
41161661Smax.romanov@nginx.com     size_t                  b_size, count;
41171123Smax.romanov@nginx.com     nxt_int_t               ret;
41181547Smax.romanov@nginx.com     nxt_app_t               *app;
41191269Sigor@sysoev.ru     nxt_buf_t               *b, *next;
41201131Smax.romanov@nginx.com     nxt_port_t              *app_port;
41211123Smax.romanov@nginx.com     nxt_unit_field_t        *f;
41221123Smax.romanov@nginx.com     nxt_http_field_t        *field;
41231123Smax.romanov@nginx.com     nxt_http_request_t      *r;
41241123Smax.romanov@nginx.com     nxt_unit_response_t     *resp;
41251123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
412688Smax.romanov@nginx.com 
41271123Smax.romanov@nginx.com     req_rpc_data = data;
412888Smax.romanov@nginx.com 
41291123Smax.romanov@nginx.com     r = req_rpc_data->request;
41301007Salexander.borisov@nginx.com     if (nxt_slow_path(r == NULL)) {
4131570Smax.romanov@nginx.com         return;
4132570Smax.romanov@nginx.com     }
4133425Smax.romanov@nginx.com 
41341007Salexander.borisov@nginx.com     if (r->error) {
41351123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
4136608Sigor@sysoev.ru         return;
4137608Sigor@sysoev.ru     }
4138608Sigor@sysoev.ru 
41391547Smax.romanov@nginx.com     app = req_rpc_data->app;
41401547Smax.romanov@nginx.com     nxt_assert(app != NULL);
41411547Smax.romanov@nginx.com 
41421547Smax.romanov@nginx.com     if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) {
41431547Smax.romanov@nginx.com         nxt_router_req_headers_ack_handler(task, msg, req_rpc_data);
41441547Smax.romanov@nginx.com 
41451547Smax.romanov@nginx.com         return;
41461547Smax.romanov@nginx.com     }
41471547Smax.romanov@nginx.com 
41481547Smax.romanov@nginx.com     b = (msg->size == 0) ? NULL : msg->buf;
41491547Smax.romanov@nginx.com 
415088Smax.romanov@nginx.com     if (msg->port_msg.last != 0) {
415188Smax.romanov@nginx.com         nxt_debug(task, "router data create last buf");
415288Smax.romanov@nginx.com 
41531007Salexander.borisov@nginx.com         nxt_buf_chain_add(&b, nxt_http_buf_last(r));
4154167Smax.romanov@nginx.com 
41551547Smax.romanov@nginx.com         req_rpc_data->rpc_cancel = 0;
41561780Smax.romanov@nginx.com 
41571780Smax.romanov@nginx.com         if (req_rpc_data->apr_action == NXT_APR_REQUEST_FAILED) {
41581780Smax.romanov@nginx.com             req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE;
41591780Smax.romanov@nginx.com         }
41601547Smax.romanov@nginx.com 
41611123Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, req_rpc_data);
4162425Smax.romanov@nginx.com 
4163425Smax.romanov@nginx.com     } else {
41641547Smax.romanov@nginx.com         if (app->timeout != 0) {
41651007Salexander.borisov@nginx.com             r->timer.handler = nxt_router_app_timeout;
41661123Smax.romanov@nginx.com             r->timer_data = req_rpc_data;
41671547Smax.romanov@nginx.com             nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
4168425Smax.romanov@nginx.com         }
416988Smax.romanov@nginx.com     }
417088Smax.romanov@nginx.com 
417188Smax.romanov@nginx.com     if (b == NULL) {
417288Smax.romanov@nginx.com         return;
417388Smax.romanov@nginx.com     }
417488Smax.romanov@nginx.com 
4175206Smax.romanov@nginx.com     if (msg->buf == b) {
4176206Smax.romanov@nginx.com         /* Disable instant buffer completion/re-using by port. */
4177206Smax.romanov@nginx.com         msg->buf = NULL;
4178206Smax.romanov@nginx.com     }
4179194Smax.romanov@nginx.com 
4180431Sigor@sysoev.ru     if (r->header_sent) {
4181431Sigor@sysoev.ru         nxt_buf_chain_add(&r->out, b);
4182431Sigor@sysoev.ru         nxt_http_request_send_body(task, r, NULL);
4183277Sigor@sysoev.ru 
418488Smax.romanov@nginx.com     } else {
41851661Smax.romanov@nginx.com         b_size = nxt_buf_is_mem(b) ? nxt_buf_mem_used_size(&b->mem) : 0;
41861661Smax.romanov@nginx.com 
41871661Smax.romanov@nginx.com         if (nxt_slow_path(b_size < sizeof(nxt_unit_response_t))) {
41881661Smax.romanov@nginx.com             nxt_alert(task, "response buffer too small: %z", b_size);
4189743Smax.romanov@nginx.com             goto fail;
4190743Smax.romanov@nginx.com         }
4191743Smax.romanov@nginx.com 
4192743Smax.romanov@nginx.com         resp = (void *) b->mem.pos;
41931661Smax.romanov@nginx.com         count = (b_size - sizeof(nxt_unit_response_t))
41941661Smax.romanov@nginx.com                     / sizeof(nxt_unit_field_t);
41951661Smax.romanov@nginx.com 
41961661Smax.romanov@nginx.com         if (nxt_slow_path(count < resp->fields_count)) {
41971661Smax.romanov@nginx.com             nxt_alert(task, "response buffer too small for fields count: %D",
41981661Smax.romanov@nginx.com                       resp->fields_count);
4199743Smax.romanov@nginx.com             goto fail;
4200743Smax.romanov@nginx.com         }
4201743Smax.romanov@nginx.com 
42021126Smax.romanov@nginx.com         field = NULL;
42031126Smax.romanov@nginx.com 
4204743Smax.romanov@nginx.com         for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
42051126Smax.romanov@nginx.com             if (f->skip) {
42061126Smax.romanov@nginx.com                 continue;
42071126Smax.romanov@nginx.com             }
42081126Smax.romanov@nginx.com 
42091007Salexander.borisov@nginx.com             field = nxt_list_add(r->resp.fields);
4210743Smax.romanov@nginx.com 
4211743Smax.romanov@nginx.com             if (nxt_slow_path(field == NULL)) {
4212743Smax.romanov@nginx.com                 goto fail;
4213743Smax.romanov@nginx.com             }
4214743Smax.romanov@nginx.com 
4215743Smax.romanov@nginx.com             field->hash = f->hash;
42161126Smax.romanov@nginx.com             field->skip = 0;
42171270Sigor@sysoev.ru             field->hopbyhop = 0;
4218743Smax.romanov@nginx.com 
4219743Smax.romanov@nginx.com             field->name_length = f->name_length;
4220743Smax.romanov@nginx.com             field->value_length = f->value_length;
4221743Smax.romanov@nginx.com             field->name = nxt_unit_sptr_get(&f->name);
4222743Smax.romanov@nginx.com             field->value = nxt_unit_sptr_get(&f->value);
4223743Smax.romanov@nginx.com 
42241126Smax.romanov@nginx.com             ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
42251126Smax.romanov@nginx.com             if (nxt_slow_path(ret != NXT_OK)) {
42261126Smax.romanov@nginx.com                 goto fail;
42271126Smax.romanov@nginx.com             }
42281126Smax.romanov@nginx.com 
42291126Smax.romanov@nginx.com             nxt_debug(task, "header%s: %*s: %*s",
42301126Smax.romanov@nginx.com                       (field->skip ? " skipped" : ""),
4231743Smax.romanov@nginx.com                       (size_t) field->name_length, field->name,
4232743Smax.romanov@nginx.com                       (size_t) field->value_length, field->value);
42331126Smax.romanov@nginx.com 
42341126Smax.romanov@nginx.com             if (field->skip) {
42351126Smax.romanov@nginx.com                 r->resp.fields->last->nelts--;
42361126Smax.romanov@nginx.com             }
4237743Smax.romanov@nginx.com         }
42381007Salexander.borisov@nginx.com 
4239743Smax.romanov@nginx.com         r->status = resp->status;
4240743Smax.romanov@nginx.com 
4241743Smax.romanov@nginx.com         if (resp->piggyback_content_length != 0) {
4242743Smax.romanov@nginx.com             b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
4243743Smax.romanov@nginx.com             b->mem.free = b->mem.pos + resp->piggyback_content_length;
4244743Smax.romanov@nginx.com 
4245743Smax.romanov@nginx.com         } else {
4246743Smax.romanov@nginx.com             b->mem.pos = b->mem.free;
4247743Smax.romanov@nginx.com         }
4248743Smax.romanov@nginx.com 
4249435Sigor@sysoev.ru         if (nxt_buf_mem_used_size(&b->mem) == 0) {
42501269Sigor@sysoev.ru             next = b->next;
42511269Sigor@sysoev.ru             b->next = NULL;
42521269Sigor@sysoev.ru 
4253435Sigor@sysoev.ru             nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4254435Sigor@sysoev.ru                                b->completion_handler, task, b, b->parent);
4255507Smax.romanov@nginx.com 
42561269Sigor@sysoev.ru             b = next;
4257520Smax.romanov@nginx.com         }
4258520Smax.romanov@nginx.com 
4259520Smax.romanov@nginx.com         if (b != NULL) {
4260431Sigor@sysoev.ru             nxt_buf_chain_add(&r->out, b);
4261431Sigor@sysoev.ru         }
4262431Sigor@sysoev.ru 
42631270Sigor@sysoev.ru         nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL);
42641127Smax.romanov@nginx.com 
42651131Smax.romanov@nginx.com         if (r->websocket_handshake
42661131Smax.romanov@nginx.com             && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
42671131Smax.romanov@nginx.com         {
42681547Smax.romanov@nginx.com             app_port = req_rpc_data->app_port;
42691131Smax.romanov@nginx.com             if (nxt_slow_path(app_port == NULL)) {
42701131Smax.romanov@nginx.com                 goto fail;
42711131Smax.romanov@nginx.com             }
42721131Smax.romanov@nginx.com 
42731547Smax.romanov@nginx.com             nxt_thread_mutex_lock(&app->mutex);
42741547Smax.romanov@nginx.com 
42751547Smax.romanov@nginx.com             app_port->main_app_port->active_websockets++;
42761547Smax.romanov@nginx.com 
42771547Smax.romanov@nginx.com             nxt_thread_mutex_unlock(&app->mutex);
42781131Smax.romanov@nginx.com 
42791978Smax.romanov@nginx.com             nxt_router_app_port_release(task, app, app_port, NXT_APR_UPGRADE);
42801547Smax.romanov@nginx.com             req_rpc_data->apr_action = NXT_APR_CLOSE;
42811547Smax.romanov@nginx.com 
42821547Smax.romanov@nginx.com             nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream);
42831131Smax.romanov@nginx.com 
42841131Smax.romanov@nginx.com             r->state = &nxt_http_websocket;
42851131Smax.romanov@nginx.com 
42861131Smax.romanov@nginx.com         } else {
42871131Smax.romanov@nginx.com             r->state = &nxt_http_request_send_state;
42881131Smax.romanov@nginx.com         }
4289431Sigor@sysoev.ru     }
4290431Sigor@sysoev.ru 
4291431Sigor@sysoev.ru     return;
4292431Sigor@sysoev.ru 
4293431Sigor@sysoev.ru fail:
4294431Sigor@sysoev.ru 
4295615Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
4296615Smax.romanov@nginx.com 
42971123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
4298431Sigor@sysoev.ru }
4299431Sigor@sysoev.ru 
4300431Sigor@sysoev.ru 
43011547Smax.romanov@nginx.com static void
43021547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(nxt_task_t *task,
43031547Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data)
43041547Smax.romanov@nginx.com {
43051555Smax.romanov@nginx.com     int                 res;
43061547Smax.romanov@nginx.com     nxt_app_t           *app;
43071698Smax.romanov@nginx.com     nxt_buf_t           *b;
43081561Smax.romanov@nginx.com     nxt_bool_t          start_process, unlinked;
43091547Smax.romanov@nginx.com     nxt_port_t          *app_port, *main_app_port, *idle_port;
43101547Smax.romanov@nginx.com     nxt_queue_link_t    *idle_lnk;
43111547Smax.romanov@nginx.com     nxt_http_request_t  *r;
43121547Smax.romanov@nginx.com 
43131547Smax.romanov@nginx.com     nxt_debug(task, "stream #%uD: got ack from %PI:%d",
43141547Smax.romanov@nginx.com               req_rpc_data->stream,
43151547Smax.romanov@nginx.com               msg->port_msg.pid, msg->port_msg.reply_port);
43161547Smax.romanov@nginx.com 
43171547Smax.romanov@nginx.com     nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data,
43181547Smax.romanov@nginx.com                              msg->port_msg.pid);
43191547Smax.romanov@nginx.com 
43201547Smax.romanov@nginx.com     app = req_rpc_data->app;
43211561Smax.romanov@nginx.com     r = req_rpc_data->request;
43221547Smax.romanov@nginx.com 
43231547Smax.romanov@nginx.com     start_process = 0;
43241561Smax.romanov@nginx.com     unlinked = 0;
43251547Smax.romanov@nginx.com 
43261547Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
43271547Smax.romanov@nginx.com 
43281561Smax.romanov@nginx.com     if (r->app_link.next != NULL) {
43291561Smax.romanov@nginx.com         nxt_queue_remove(&r->app_link);
43301561Smax.romanov@nginx.com         r->app_link.next = NULL;
43311561Smax.romanov@nginx.com 
43321561Smax.romanov@nginx.com         unlinked = 1;
43331561Smax.romanov@nginx.com     }
43341561Smax.romanov@nginx.com 
43351547Smax.romanov@nginx.com     app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid,
43361547Smax.romanov@nginx.com                                   msg->port_msg.reply_port);
43371547Smax.romanov@nginx.com     if (nxt_slow_path(app_port == NULL)) {
43381547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
43391547Smax.romanov@nginx.com 
43401547Smax.romanov@nginx.com         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
43411547Smax.romanov@nginx.com 
43421561Smax.romanov@nginx.com         if (unlinked) {
43431561Smax.romanov@nginx.com             nxt_mp_release(r->mem_pool);
43441561Smax.romanov@nginx.com         }
43451561Smax.romanov@nginx.com 
43461547Smax.romanov@nginx.com         return;
43471547Smax.romanov@nginx.com     }
43481547Smax.romanov@nginx.com 
43491547Smax.romanov@nginx.com     main_app_port = app_port->main_app_port;
43501547Smax.romanov@nginx.com 
43511547Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&main_app_port->idle_link)) {
43521547Smax.romanov@nginx.com         app->idle_processes--;
43531547Smax.romanov@nginx.com 
43541549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)",
43551549Smax.romanov@nginx.com                   &app->name, main_app_port->pid, main_app_port->id,
43561549Smax.romanov@nginx.com                   (main_app_port->idle_start ? "idle_ports" : "spare_ports"));
43571549Smax.romanov@nginx.com 
43581547Smax.romanov@nginx.com         /* Check port was in 'spare_ports' using idle_start field. */
43591547Smax.romanov@nginx.com         if (main_app_port->idle_start == 0
43601547Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
43611547Smax.romanov@nginx.com         {
43621547Smax.romanov@nginx.com             /*
43631547Smax.romanov@nginx.com              * If there is a vacant space in spare ports,
43641547Smax.romanov@nginx.com              * move the last idle to spare_ports.
43651547Smax.romanov@nginx.com              */
43661547Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
43671547Smax.romanov@nginx.com 
43681547Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
43691547Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
43701547Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
43711547Smax.romanov@nginx.com 
43721547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
43731547Smax.romanov@nginx.com 
43741547Smax.romanov@nginx.com             idle_port->idle_start = 0;
43751549Smax.romanov@nginx.com 
43761549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
43771549Smax.romanov@nginx.com                       "to spare_ports",
43781549Smax.romanov@nginx.com                       &app->name, idle_port->pid, idle_port->id);
43791547Smax.romanov@nginx.com         }
43801547Smax.romanov@nginx.com 
43811547Smax.romanov@nginx.com         if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
43821547Smax.romanov@nginx.com             app->pending_processes++;
43831547Smax.romanov@nginx.com             start_process = 1;
43841547Smax.romanov@nginx.com         }
43851547Smax.romanov@nginx.com     }
43861547Smax.romanov@nginx.com 
43871547Smax.romanov@nginx.com     main_app_port->active_requests++;
43881547Smax.romanov@nginx.com 
43891547Smax.romanov@nginx.com     nxt_port_inc_use(app_port);
43901547Smax.romanov@nginx.com 
43911547Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
43921547Smax.romanov@nginx.com 
43931561Smax.romanov@nginx.com     if (unlinked) {
43941561Smax.romanov@nginx.com         nxt_mp_release(r->mem_pool);
43951561Smax.romanov@nginx.com     }
43961561Smax.romanov@nginx.com 
43971547Smax.romanov@nginx.com     if (start_process) {
43981547Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
43991547Smax.romanov@nginx.com     }
44001547Smax.romanov@nginx.com 
44011547Smax.romanov@nginx.com     nxt_port_use(task, req_rpc_data->app_port, -1);
44021547Smax.romanov@nginx.com 
44031547Smax.romanov@nginx.com     req_rpc_data->app_port = app_port;
44041547Smax.romanov@nginx.com 
44051698Smax.romanov@nginx.com     b = req_rpc_data->msg_info.buf;
44061698Smax.romanov@nginx.com 
44071698Smax.romanov@nginx.com     if (b != NULL) {
44081698Smax.romanov@nginx.com         /* First buffer is already sent.  Start from second. */
44091698Smax.romanov@nginx.com         b = b->next;
44101829Smax.romanov@nginx.com 
44111829Smax.romanov@nginx.com         req_rpc_data->msg_info.buf->next = NULL;
44121698Smax.romanov@nginx.com     }
44131698Smax.romanov@nginx.com 
44141698Smax.romanov@nginx.com     if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) {
44151555Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream,
44161555Smax.romanov@nginx.com                   req_rpc_data->msg_info.body_fd);
44171555Smax.romanov@nginx.com 
44181698Smax.romanov@nginx.com         if (req_rpc_data->msg_info.body_fd != -1) {
44191698Smax.romanov@nginx.com             lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET);
44201698Smax.romanov@nginx.com         }
44211555Smax.romanov@nginx.com 
44221555Smax.romanov@nginx.com         res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY,
44231555Smax.romanov@nginx.com                                     req_rpc_data->msg_info.body_fd,
44241555Smax.romanov@nginx.com                                     req_rpc_data->stream,
44251698Smax.romanov@nginx.com                                     task->thread->engine->port->id, b);
44261555Smax.romanov@nginx.com 
44271555Smax.romanov@nginx.com         if (nxt_slow_path(res != NXT_OK)) {
44281555Smax.romanov@nginx.com             nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
44291555Smax.romanov@nginx.com         }
44301555Smax.romanov@nginx.com     }
44311555Smax.romanov@nginx.com 
44321547Smax.romanov@nginx.com     if (app->timeout != 0) {
44331547Smax.romanov@nginx.com         r->timer.handler = nxt_router_app_timeout;
44341547Smax.romanov@nginx.com         r->timer_data = req_rpc_data;
44351547Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
44361547Smax.romanov@nginx.com     }
44371547Smax.romanov@nginx.com }
44381547Smax.romanov@nginx.com 
44391547Smax.romanov@nginx.com 
4440431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_send_state
4441431Sigor@sysoev.ru     nxt_aligned(64) =
4442431Sigor@sysoev.ru {
4443943Sigor@sysoev.ru     .error_handler = nxt_http_request_error_handler,
4444431Sigor@sysoev.ru };
4445431Sigor@sysoev.ru 
4446431Sigor@sysoev.ru 
4447431Sigor@sysoev.ru static void
4448431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
4449431Sigor@sysoev.ru {
4450431Sigor@sysoev.ru     nxt_buf_t           *out;
4451431Sigor@sysoev.ru     nxt_http_request_t  *r;
4452431Sigor@sysoev.ru 
4453431Sigor@sysoev.ru     r = obj;
4454431Sigor@sysoev.ru 
4455431Sigor@sysoev.ru     out = r->out;
4456431Sigor@sysoev.ru 
4457431Sigor@sysoev.ru     if (out != NULL) {
4458431Sigor@sysoev.ru         r->out = NULL;
4459431Sigor@sysoev.ru         nxt_http_request_send(task, r, out);
446088Smax.romanov@nginx.com     }
446188Smax.romanov@nginx.com }
446288Smax.romanov@nginx.com 
4463277Sigor@sysoev.ru 
4464318Smax.romanov@nginx.com static void
4465318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4466318Smax.romanov@nginx.com     void *data)
4467318Smax.romanov@nginx.com {
44681123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
44691123Smax.romanov@nginx.com 
44701123Smax.romanov@nginx.com     req_rpc_data = data;
44711123Smax.romanov@nginx.com 
44721547Smax.romanov@nginx.com     req_rpc_data->rpc_cancel = 0;
44731547Smax.romanov@nginx.com 
44741547Smax.romanov@nginx.com     /* TODO cancel message and return if cancelled. */
44751547Smax.romanov@nginx.com     // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
4476425Smax.romanov@nginx.com 
44771123Smax.romanov@nginx.com     if (req_rpc_data->request != NULL) {
44781123Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
4479616Smax.romanov@nginx.com                                NXT_HTTP_SERVICE_UNAVAILABLE);
4480616Smax.romanov@nginx.com     }
4481318Smax.romanov@nginx.com 
44821123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
4483318Smax.romanov@nginx.com }
4484318Smax.romanov@nginx.com 
4485318Smax.romanov@nginx.com 
4486141Smax.romanov@nginx.com static void
4487343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4488343Smax.romanov@nginx.com     void *data)
4489192Smax.romanov@nginx.com {
4490*1998St.nateldemoura@f5.com     uint32_t             n;
44911926Smax.romanov@nginx.com     nxt_app_t            *app;
4492*1998St.nateldemoura@f5.com     nxt_bool_t           start_process, restarted;
44931926Smax.romanov@nginx.com     nxt_port_t           *port;
44941926Smax.romanov@nginx.com     nxt_app_joint_t      *app_joint;
44951926Smax.romanov@nginx.com     nxt_app_joint_rpc_t  *app_joint_rpc;
44961926Smax.romanov@nginx.com 
44971926Smax.romanov@nginx.com     nxt_assert(data != NULL);
44981926Smax.romanov@nginx.com 
44991926Smax.romanov@nginx.com     app_joint_rpc = data;
45001926Smax.romanov@nginx.com     app_joint = app_joint_rpc->app_joint;
4501347Smax.romanov@nginx.com     port = msg->u.new_port;
4502343Smax.romanov@nginx.com 
4503753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
4504343Smax.romanov@nginx.com     nxt_assert(port != NULL);
45051547Smax.romanov@nginx.com     nxt_assert(port->id == 0);
4506343Smax.romanov@nginx.com 
4507753Smax.romanov@nginx.com     app = app_joint->app;
4508753Smax.romanov@nginx.com 
4509753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4510753Smax.romanov@nginx.com 
4511753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
4512753Smax.romanov@nginx.com         nxt_debug(task, "new port ready for released app, send QUIT");
4513753Smax.romanov@nginx.com 
4514753Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4515753Smax.romanov@nginx.com 
4516753Smax.romanov@nginx.com         return;
4517753Smax.romanov@nginx.com     }
4518753Smax.romanov@nginx.com 
4519343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4520343Smax.romanov@nginx.com 
4521*1998St.nateldemoura@f5.com     restarted = (app->generation != app_joint_rpc->generation);
4522*1998St.nateldemoura@f5.com 
4523*1998St.nateldemoura@f5.com     if (app_joint_rpc->proto) {
4524*1998St.nateldemoura@f5.com         nxt_assert(app->proto_port == NULL);
4525*1998St.nateldemoura@f5.com         nxt_assert(port->type == NXT_PROCESS_PROTOTYPE);
4526*1998St.nateldemoura@f5.com 
4527*1998St.nateldemoura@f5.com         n = app->proto_port_requests;
4528*1998St.nateldemoura@f5.com         app->proto_port_requests = 0;
4529*1998St.nateldemoura@f5.com 
4530*1998St.nateldemoura@f5.com         if (nxt_slow_path(restarted)) {
4531*1998St.nateldemoura@f5.com             nxt_thread_mutex_unlock(&app->mutex);
4532*1998St.nateldemoura@f5.com 
4533*1998St.nateldemoura@f5.com             nxt_debug(task, "proto port ready for restarted app, send QUIT");
4534*1998St.nateldemoura@f5.com 
4535*1998St.nateldemoura@f5.com             nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0,
4536*1998St.nateldemoura@f5.com                                   NULL);
4537*1998St.nateldemoura@f5.com 
4538*1998St.nateldemoura@f5.com         } else {
4539*1998St.nateldemoura@f5.com             port->app = app;
4540*1998St.nateldemoura@f5.com             app->proto_port = port;
4541*1998St.nateldemoura@f5.com 
4542*1998St.nateldemoura@f5.com             nxt_thread_mutex_unlock(&app->mutex);
4543*1998St.nateldemoura@f5.com 
4544*1998St.nateldemoura@f5.com             nxt_port_use(task, port, 1);
4545*1998St.nateldemoura@f5.com         }
4546*1998St.nateldemoura@f5.com 
4547*1998St.nateldemoura@f5.com         port = task->thread->runtime->port_by_type[NXT_PROCESS_ROUTER];
4548*1998St.nateldemoura@f5.com 
4549*1998St.nateldemoura@f5.com         while (n > 0) {
4550*1998St.nateldemoura@f5.com             nxt_router_app_use(task, app, 1);
4551*1998St.nateldemoura@f5.com 
4552*1998St.nateldemoura@f5.com             nxt_router_start_app_process_handler(task, port, app);
4553*1998St.nateldemoura@f5.com 
4554*1998St.nateldemoura@f5.com             n--;
4555*1998St.nateldemoura@f5.com         }
4556*1998St.nateldemoura@f5.com 
4557*1998St.nateldemoura@f5.com         return;
4558*1998St.nateldemoura@f5.com     }
4559*1998St.nateldemoura@f5.com 
4560*1998St.nateldemoura@f5.com     nxt_assert(port->type == NXT_PROCESS_APP);
4561507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
4562507Smax.romanov@nginx.com 
4563507Smax.romanov@nginx.com     app->pending_processes--;
45641926Smax.romanov@nginx.com 
4565*1998St.nateldemoura@f5.com     if (nxt_slow_path(restarted)) {
45661926Smax.romanov@nginx.com         nxt_debug(task, "new port ready for restarted app, send QUIT");
45671926Smax.romanov@nginx.com 
45681926Smax.romanov@nginx.com         start_process = !task->thread->engine->shutdown
45691926Smax.romanov@nginx.com                         && nxt_router_app_can_start(app)
45701926Smax.romanov@nginx.com                         && nxt_router_app_need_start(app);
45711926Smax.romanov@nginx.com 
45721926Smax.romanov@nginx.com         if (start_process) {
45731926Smax.romanov@nginx.com             app->pending_processes++;
45741926Smax.romanov@nginx.com         }
45751926Smax.romanov@nginx.com 
45761926Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
45771926Smax.romanov@nginx.com 
45781926Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
45791926Smax.romanov@nginx.com 
45801926Smax.romanov@nginx.com         if (start_process) {
45811926Smax.romanov@nginx.com             nxt_router_start_app_process(task, app);
45821926Smax.romanov@nginx.com         }
45831926Smax.romanov@nginx.com 
45841926Smax.romanov@nginx.com         return;
45851926Smax.romanov@nginx.com     }
45861926Smax.romanov@nginx.com 
45871926Smax.romanov@nginx.com     port->app = app;
45881926Smax.romanov@nginx.com     port->main_app_port = port;
45891926Smax.romanov@nginx.com 
4590507Smax.romanov@nginx.com     app->processes++;
45911547Smax.romanov@nginx.com     nxt_port_hash_add(&app->port_hash, port);
45921547Smax.romanov@nginx.com     app->port_hash_count++;
4593343Smax.romanov@nginx.com 
4594343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4595343Smax.romanov@nginx.com 
4596507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
4597507Smax.romanov@nginx.com               &app->name, port->pid, app->processes, app->pending_processes);
4598343Smax.romanov@nginx.com 
45991547Smax.romanov@nginx.com     nxt_router_app_shared_port_send(task, port);
46001547Smax.romanov@nginx.com 
46011978Smax.romanov@nginx.com     nxt_router_app_port_release(task, app, port, NXT_APR_NEW_PORT);
4602192Smax.romanov@nginx.com }
4603192Smax.romanov@nginx.com 
4604192Smax.romanov@nginx.com 
46051547Smax.romanov@nginx.com static nxt_int_t
46061547Smax.romanov@nginx.com nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port)
46071547Smax.romanov@nginx.com {
46081547Smax.romanov@nginx.com     nxt_buf_t                *b;
46091547Smax.romanov@nginx.com     nxt_port_t               *port;
46101547Smax.romanov@nginx.com     nxt_port_msg_new_port_t  *msg;
46111547Smax.romanov@nginx.com 
46121547Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
46131547Smax.romanov@nginx.com                              sizeof(nxt_port_data_t));
46141547Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
46151547Smax.romanov@nginx.com         return NXT_ERROR;
46161547Smax.romanov@nginx.com     }
46171547Smax.romanov@nginx.com 
46181547Smax.romanov@nginx.com     port = app_port->app->shared_port;
46191547Smax.romanov@nginx.com 
46201547Smax.romanov@nginx.com     nxt_debug(task, "send port %FD to process %PI",
46211547Smax.romanov@nginx.com               port->pair[0], app_port->pid);
46221547Smax.romanov@nginx.com 
46231547Smax.romanov@nginx.com     b->mem.free += sizeof(nxt_port_msg_new_port_t);
46241547Smax.romanov@nginx.com     msg = (nxt_port_msg_new_port_t *) b->mem.pos;
46251547Smax.romanov@nginx.com 
46261547Smax.romanov@nginx.com     msg->id = port->id;
46271547Smax.romanov@nginx.com     msg->pid = port->pid;
46281547Smax.romanov@nginx.com     msg->max_size = port->max_size;
46291547Smax.romanov@nginx.com     msg->max_share = port->max_share;
46301547Smax.romanov@nginx.com     msg->type = port->type;
46311547Smax.romanov@nginx.com 
46321555Smax.romanov@nginx.com     return nxt_port_socket_write2(task, app_port,
46331547Smax.romanov@nginx.com                                   NXT_PORT_MSG_NEW_PORT,
46341555Smax.romanov@nginx.com                                   port->pair[0], port->queue_fd,
46351555Smax.romanov@nginx.com                                   0, 0, b);
46361547Smax.romanov@nginx.com }
46371547Smax.romanov@nginx.com 
46381547Smax.romanov@nginx.com 
4639192Smax.romanov@nginx.com static void
4640343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4641343Smax.romanov@nginx.com     void *data)
4642192Smax.romanov@nginx.com {
46431926Smax.romanov@nginx.com     nxt_app_t            *app;
46441926Smax.romanov@nginx.com     nxt_app_joint_t      *app_joint;
46451926Smax.romanov@nginx.com     nxt_queue_link_t     *link;
46461926Smax.romanov@nginx.com     nxt_http_request_t   *r;
46471926Smax.romanov@nginx.com     nxt_app_joint_rpc_t  *app_joint_rpc;
46481926Smax.romanov@nginx.com 
46491926Smax.romanov@nginx.com     nxt_assert(data != NULL);
46501926Smax.romanov@nginx.com 
46511926Smax.romanov@nginx.com     app_joint_rpc = data;
46521926Smax.romanov@nginx.com     app_joint = app_joint_rpc->app_joint;
4653753Smax.romanov@nginx.com 
4654753Smax.romanov@nginx.com     nxt_assert(app_joint != NULL);
4655753Smax.romanov@nginx.com 
4656753Smax.romanov@nginx.com     app = app_joint->app;
4657753Smax.romanov@nginx.com 
4658753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
4659753Smax.romanov@nginx.com 
4660753Smax.romanov@nginx.com     if (nxt_slow_path(app == NULL)) {
4661753Smax.romanov@nginx.com         nxt_debug(task, "start error for released app");
4662753Smax.romanov@nginx.com 
4663753Smax.romanov@nginx.com         return;
4664753Smax.romanov@nginx.com     }
4665343Smax.romanov@nginx.com 
4666343Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p start error", &app->name, app);
4667343Smax.romanov@nginx.com 
46681561Smax.romanov@nginx.com     link = NULL;
46691561Smax.romanov@nginx.com 
4670343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4671343Smax.romanov@nginx.com 
4672507Smax.romanov@nginx.com     nxt_assert(app->pending_processes != 0);
4673507Smax.romanov@nginx.com 
4674507Smax.romanov@nginx.com     app->pending_processes--;
4675318Smax.romanov@nginx.com 
46761561Smax.romanov@nginx.com     if (app->processes == 0 && !nxt_queue_is_empty(&app->ack_waiting_req)) {
46771561Smax.romanov@nginx.com         link = nxt_queue_first(&app->ack_waiting_req);
46781561Smax.romanov@nginx.com 
46791561Smax.romanov@nginx.com         nxt_queue_remove(link);
46801561Smax.romanov@nginx.com         link->next = NULL;
46811561Smax.romanov@nginx.com     }
46821561Smax.romanov@nginx.com 
4683343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4684343Smax.romanov@nginx.com 
46851561Smax.romanov@nginx.com     while (link != NULL) {
46861561Smax.romanov@nginx.com         r = nxt_container_of(link, nxt_http_request_t, app_link);
46871561Smax.romanov@nginx.com 
46881561Smax.romanov@nginx.com         nxt_event_engine_post(r->engine, &r->err_work);
46891561Smax.romanov@nginx.com 
46901561Smax.romanov@nginx.com         link = NULL;
46911561Smax.romanov@nginx.com 
46921561Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
46931561Smax.romanov@nginx.com 
46941561Smax.romanov@nginx.com         if (app->processes == 0 && app->pending_processes == 0
46951561Smax.romanov@nginx.com             && !nxt_queue_is_empty(&app->ack_waiting_req))
46961561Smax.romanov@nginx.com         {
46971561Smax.romanov@nginx.com             link = nxt_queue_first(&app->ack_waiting_req);
46981561Smax.romanov@nginx.com 
46991561Smax.romanov@nginx.com             nxt_queue_remove(link);
47001561Smax.romanov@nginx.com             link->next = NULL;
47011561Smax.romanov@nginx.com         }
47021561Smax.romanov@nginx.com 
47031561Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
47041561Smax.romanov@nginx.com     }
4705192Smax.romanov@nginx.com }
4706192Smax.romanov@nginx.com 
4707192Smax.romanov@nginx.com 
4708507Smax.romanov@nginx.com nxt_inline nxt_port_t *
47091549Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
4710141Smax.romanov@nginx.com {
4711343Smax.romanov@nginx.com     nxt_port_t  *port;
4712141Smax.romanov@nginx.com 
4713141Smax.romanov@nginx.com     port = NULL;
4714141Smax.romanov@nginx.com 
4715141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4716141Smax.romanov@nginx.com 
4717343Smax.romanov@nginx.com     nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
4718343Smax.romanov@nginx.com 
4719507Smax.romanov@nginx.com         /* Caller is responsible to decrease port use count. */
4720507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
4721507Smax.romanov@nginx.com 
4722507Smax.romanov@nginx.com         if (nxt_queue_chk_remove(&port->idle_link)) {
4723507Smax.romanov@nginx.com             app->idle_processes--;
47241549Smax.romanov@nginx.com 
47251549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit",
47261549Smax.romanov@nginx.com                       &app->name, port->pid, port->id,
47271549Smax.romanov@nginx.com                       (port->idle_start ? "idle_ports" : "spare_ports"));
4728507Smax.romanov@nginx.com         }
4729507Smax.romanov@nginx.com 
47301547Smax.romanov@nginx.com         nxt_port_hash_remove(&app->port_hash, port);
47311547Smax.romanov@nginx.com         app->port_hash_count--;
47321547Smax.romanov@nginx.com 
4733507Smax.romanov@nginx.com         port->app = NULL;
4734507Smax.romanov@nginx.com         app->processes--;
4735343Smax.romanov@nginx.com 
4736343Smax.romanov@nginx.com         break;
4737343Smax.romanov@nginx.com 
4738343Smax.romanov@nginx.com     } nxt_queue_loop;
4739141Smax.romanov@nginx.com 
4740141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4741141Smax.romanov@nginx.com 
4742141Smax.romanov@nginx.com     return port;
4743141Smax.romanov@nginx.com }
4744141Smax.romanov@nginx.com 
4745141Smax.romanov@nginx.com 
4746141Smax.romanov@nginx.com static void
47471563Svbart@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
47481563Svbart@nginx.com {
47491563Svbart@nginx.com     int  c;
47501563Svbart@nginx.com 
47511563Svbart@nginx.com     c = nxt_atomic_fetch_add(&app->use_count, i);
47521563Svbart@nginx.com 
47531563Svbart@nginx.com     if (i < 0 && c == -i) {
47541563Svbart@nginx.com 
47551563Svbart@nginx.com         if (task->thread->engine != app->engine) {
47561563Svbart@nginx.com             nxt_event_engine_post(app->engine, &app->joint->free_app_work);
47571563Svbart@nginx.com 
47581563Svbart@nginx.com         } else {
47591563Svbart@nginx.com             nxt_router_free_app(task, app->joint, NULL);
47601563Svbart@nginx.com         }
47611563Svbart@nginx.com     }
47621563Svbart@nginx.com }
47631563Svbart@nginx.com 
47641563Svbart@nginx.com 
47651563Svbart@nginx.com static void
4766753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
4767507Smax.romanov@nginx.com {
4768753Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p unlink", &app->name, app);
4769507Smax.romanov@nginx.com 
4770507Smax.romanov@nginx.com     nxt_queue_remove(&app->link);
4771507Smax.romanov@nginx.com 
4772753Smax.romanov@nginx.com     nxt_router_app_use(task, app, -1);
4773507Smax.romanov@nginx.com }
4774507Smax.romanov@nginx.com 
4775507Smax.romanov@nginx.com 
4776507Smax.romanov@nginx.com static void
47771978Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, nxt_port_t *port,
47781123Smax.romanov@nginx.com     nxt_apr_action_t action)
4779343Smax.romanov@nginx.com {
47801547Smax.romanov@nginx.com     int         inc_use;
47811547Smax.romanov@nginx.com     uint32_t    got_response, dec_requests;
47821980Smax.romanov@nginx.com     nxt_bool_t  adjust_idle_timer;
47831547Smax.romanov@nginx.com     nxt_port_t  *main_app_port;
4784343Smax.romanov@nginx.com 
4785343Smax.romanov@nginx.com     nxt_assert(port != NULL);
4786343Smax.romanov@nginx.com 
47871123Smax.romanov@nginx.com     inc_use = 0;
47881123Smax.romanov@nginx.com     got_response = 0;
47891547Smax.romanov@nginx.com     dec_requests = 0;
47901123Smax.romanov@nginx.com 
47911123Smax.romanov@nginx.com     switch (action) {
47921123Smax.romanov@nginx.com     case NXT_APR_NEW_PORT:
47931123Smax.romanov@nginx.com         break;
47941123Smax.romanov@nginx.com     case NXT_APR_REQUEST_FAILED:
47951547Smax.romanov@nginx.com         dec_requests = 1;
47961123Smax.romanov@nginx.com         inc_use = -1;
47971123Smax.romanov@nginx.com         break;
47981123Smax.romanov@nginx.com     case NXT_APR_GOT_RESPONSE:
47991123Smax.romanov@nginx.com         got_response = 1;
48001123Smax.romanov@nginx.com         inc_use = -1;
48011123Smax.romanov@nginx.com         break;
48021131Smax.romanov@nginx.com     case NXT_APR_UPGRADE:
48031131Smax.romanov@nginx.com         got_response = 1;
48041131Smax.romanov@nginx.com         break;
48051123Smax.romanov@nginx.com     case NXT_APR_CLOSE:
48061123Smax.romanov@nginx.com         inc_use = -1;
48071123Smax.romanov@nginx.com         break;
48081123Smax.romanov@nginx.com     }
48091123Smax.romanov@nginx.com 
48101547Smax.romanov@nginx.com     nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name,
48111547Smax.romanov@nginx.com               port->pid, port->id,
48121547Smax.romanov@nginx.com               (int) inc_use, (int) got_response);
48131547Smax.romanov@nginx.com 
48141926Smax.romanov@nginx.com     if (port->id == NXT_SHARED_PORT_ID) {
48151547Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
48161547Smax.romanov@nginx.com 
48171547Smax.romanov@nginx.com         app->active_requests -= got_response + dec_requests;
48181547Smax.romanov@nginx.com 
48191547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
48201547Smax.romanov@nginx.com 
48211547Smax.romanov@nginx.com         goto adjust_use;
48221547Smax.romanov@nginx.com     }
48231547Smax.romanov@nginx.com 
48241547Smax.romanov@nginx.com     main_app_port = port->main_app_port;
48251547Smax.romanov@nginx.com 
4826343Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4827343Smax.romanov@nginx.com 
48281547Smax.romanov@nginx.com     main_app_port->active_requests -= got_response + dec_requests;
48291547Smax.romanov@nginx.com     app->active_requests -= got_response + dec_requests;
48301547Smax.romanov@nginx.com 
48311980Smax.romanov@nginx.com     if (main_app_port->pair[1] != -1 && main_app_port->app_link.next == NULL) {
48321980Smax.romanov@nginx.com         nxt_queue_insert_tail(&app->ports, &main_app_port->app_link);
48331980Smax.romanov@nginx.com 
48341980Smax.romanov@nginx.com         nxt_port_inc_use(main_app_port);
4835507Smax.romanov@nginx.com     }
4836507Smax.romanov@nginx.com 
4837507Smax.romanov@nginx.com     adjust_idle_timer = 0;
4838507Smax.romanov@nginx.com 
48391980Smax.romanov@nginx.com     if (main_app_port->pair[1] != -1
48401547Smax.romanov@nginx.com         && main_app_port->active_requests == 0
48411547Smax.romanov@nginx.com         && main_app_port->active_websockets == 0
48421547Smax.romanov@nginx.com         && main_app_port->idle_link.next == NULL)
48431131Smax.romanov@nginx.com     {
4844507Smax.romanov@nginx.com         if (app->idle_processes == app->spare_processes
4845507Smax.romanov@nginx.com             && app->adjust_idle_work.data == NULL)
4846507Smax.romanov@nginx.com         {
4847507Smax.romanov@nginx.com             adjust_idle_timer = 1;
4848507Smax.romanov@nginx.com             app->adjust_idle_work.data = app;
4849507Smax.romanov@nginx.com             app->adjust_idle_work.next = NULL;
4850507Smax.romanov@nginx.com         }
4851507Smax.romanov@nginx.com 
4852507Smax.romanov@nginx.com         if (app->idle_processes < app->spare_processes) {
48531547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link);
4854507Smax.romanov@nginx.com 
48551549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d to spare_ports",
48561549Smax.romanov@nginx.com                       &app->name, main_app_port->pid, main_app_port->id);
4857507Smax.romanov@nginx.com         } else {
48581547Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link);
48591547Smax.romanov@nginx.com 
48601547Smax.romanov@nginx.com             main_app_port->idle_start = task->thread->engine->timers.now;
48611549Smax.romanov@nginx.com 
48621549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d to idle_ports",
48631549Smax.romanov@nginx.com                       &app->name, main_app_port->pid, main_app_port->id);
4864507Smax.romanov@nginx.com         }
4865507Smax.romanov@nginx.com 
4866507Smax.romanov@nginx.com         app->idle_processes++;
4867507Smax.romanov@nginx.com     }
4868507Smax.romanov@nginx.com 
4869343Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4870343Smax.romanov@nginx.com 
4871507Smax.romanov@nginx.com     if (adjust_idle_timer) {
4872507Smax.romanov@nginx.com         nxt_router_app_use(task, app, 1);
4873507Smax.romanov@nginx.com         nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4874507Smax.romanov@nginx.com     }
4875507Smax.romanov@nginx.com 
4876343Smax.romanov@nginx.com     /* ? */
48771547Smax.romanov@nginx.com     if (main_app_port->pair[1] == -1) {
4878343Smax.romanov@nginx.com         nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
48791547Smax.romanov@nginx.com                   &app->name, app, main_app_port, main_app_port->pid);
4880343Smax.romanov@nginx.com 
4881343Smax.romanov@nginx.com         goto adjust_use;
4882163Smax.romanov@nginx.com     }
4883163Smax.romanov@nginx.com 
4884167Smax.romanov@nginx.com     nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4885167Smax.romanov@nginx.com               &app->name, app);
4886141Smax.romanov@nginx.com 
4887343Smax.romanov@nginx.com adjust_use:
4888343Smax.romanov@nginx.com 
48891123Smax.romanov@nginx.com     nxt_port_use(task, port, inc_use);
4890141Smax.romanov@nginx.com }
4891141Smax.romanov@nginx.com 
4892141Smax.romanov@nginx.com 
4893343Smax.romanov@nginx.com void
4894343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4895141Smax.romanov@nginx.com {
4896507Smax.romanov@nginx.com     nxt_app_t         *app;
4897507Smax.romanov@nginx.com     nxt_bool_t        unchain, start_process;
4898507Smax.romanov@nginx.com     nxt_port_t        *idle_port;
4899507Smax.romanov@nginx.com     nxt_queue_link_t  *idle_lnk;
4900141Smax.romanov@nginx.com 
4901141Smax.romanov@nginx.com     app = port->app;
4902343Smax.romanov@nginx.com 
4903343Smax.romanov@nginx.com     nxt_assert(app != NULL);
4904141Smax.romanov@nginx.com 
4905141Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
4906141Smax.romanov@nginx.com 
4907*1998St.nateldemoura@f5.com     if (port == app->proto_port) {
4908*1998St.nateldemoura@f5.com         app->proto_port = NULL;
4909*1998St.nateldemoura@f5.com         port->app = NULL;
4910*1998St.nateldemoura@f5.com 
4911*1998St.nateldemoura@f5.com         nxt_thread_mutex_unlock(&app->mutex);
4912*1998St.nateldemoura@f5.com 
4913*1998St.nateldemoura@f5.com         nxt_debug(task, "app '%V' prototype pid %PI closed", &app->name,
4914*1998St.nateldemoura@f5.com                   port->pid);
4915*1998St.nateldemoura@f5.com 
4916*1998St.nateldemoura@f5.com         nxt_port_use(task, port, -1);
4917*1998St.nateldemoura@f5.com 
4918*1998St.nateldemoura@f5.com         return;
4919*1998St.nateldemoura@f5.com     }
4920*1998St.nateldemoura@f5.com 
49211547Smax.romanov@nginx.com     nxt_port_hash_remove(&app->port_hash, port);
49221547Smax.romanov@nginx.com     app->port_hash_count--;
49231547Smax.romanov@nginx.com 
49241547Smax.romanov@nginx.com     if (port->id != 0) {
49251547Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
49261547Smax.romanov@nginx.com 
49271547Smax.romanov@nginx.com         nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name,
49281547Smax.romanov@nginx.com                   port->pid, port->id);
49291547Smax.romanov@nginx.com 
49301547Smax.romanov@nginx.com         return;
49311547Smax.romanov@nginx.com     }
49321547Smax.romanov@nginx.com 
4933507Smax.romanov@nginx.com     unchain = nxt_queue_chk_remove(&port->app_link);
4934507Smax.romanov@nginx.com 
4935507Smax.romanov@nginx.com     if (nxt_queue_chk_remove(&port->idle_link)) {
4936507Smax.romanov@nginx.com         app->idle_processes--;
4937507Smax.romanov@nginx.com 
49381549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of %s before close",
49391549Smax.romanov@nginx.com                   &app->name, port->pid, port->id,
49401549Smax.romanov@nginx.com                   (port->idle_start ? "idle_ports" : "spare_ports"));
49411549Smax.romanov@nginx.com 
4942507Smax.romanov@nginx.com         if (port->idle_start == 0
4943507Smax.romanov@nginx.com             && app->idle_processes >= app->spare_processes)
4944507Smax.romanov@nginx.com         {
4945507Smax.romanov@nginx.com             nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4946507Smax.romanov@nginx.com 
4947507Smax.romanov@nginx.com             idle_lnk = nxt_queue_last(&app->idle_ports);
4948507Smax.romanov@nginx.com             idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4949507Smax.romanov@nginx.com             nxt_queue_remove(idle_lnk);
4950507Smax.romanov@nginx.com 
4951507Smax.romanov@nginx.com             nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4952507Smax.romanov@nginx.com 
4953507Smax.romanov@nginx.com             idle_port->idle_start = 0;
49541549Smax.romanov@nginx.com 
49551549Smax.romanov@nginx.com             nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
49561549Smax.romanov@nginx.com                       "to spare_ports",
49571549Smax.romanov@nginx.com                       &app->name, idle_port->pid, idle_port->id);
4958507Smax.romanov@nginx.com         }
4959343Smax.romanov@nginx.com     }
4960343Smax.romanov@nginx.com 
4961507Smax.romanov@nginx.com     app->processes--;
4962507Smax.romanov@nginx.com 
4963753Smax.romanov@nginx.com     start_process = !task->thread->engine->shutdown
4964507Smax.romanov@nginx.com                     && nxt_router_app_can_start(app)
49651547Smax.romanov@nginx.com                     && nxt_router_app_need_start(app);
4966507Smax.romanov@nginx.com 
4967507Smax.romanov@nginx.com     if (start_process) {
4968507Smax.romanov@nginx.com         app->pending_processes++;
4969163Smax.romanov@nginx.com     }
4970141Smax.romanov@nginx.com 
4971141Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
4972163Smax.romanov@nginx.com 
4973507Smax.romanov@nginx.com     nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4974343Smax.romanov@nginx.com 
4975343Smax.romanov@nginx.com     if (unchain) {
4976343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
4977163Smax.romanov@nginx.com     }
4978163Smax.romanov@nginx.com 
4979507Smax.romanov@nginx.com     if (start_process) {
4980507Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
4981507Smax.romanov@nginx.com     }
4982507Smax.romanov@nginx.com }
4983507Smax.romanov@nginx.com 
4984507Smax.romanov@nginx.com 
4985507Smax.romanov@nginx.com static void
4986507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4987507Smax.romanov@nginx.com {
4988507Smax.romanov@nginx.com     nxt_app_t           *app;
4989507Smax.romanov@nginx.com     nxt_bool_t          queued;
4990507Smax.romanov@nginx.com     nxt_port_t          *port;
4991507Smax.romanov@nginx.com     nxt_msec_t          timeout, threshold;
4992507Smax.romanov@nginx.com     nxt_queue_link_t    *lnk;
4993507Smax.romanov@nginx.com     nxt_event_engine_t  *engine;
4994507Smax.romanov@nginx.com 
4995507Smax.romanov@nginx.com     app = obj;
4996507Smax.romanov@nginx.com     queued = (data == app);
4997507Smax.romanov@nginx.com 
4998507Smax.romanov@nginx.com     nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4999507Smax.romanov@nginx.com               &app->name, queued);
5000507Smax.romanov@nginx.com 
5001507Smax.romanov@nginx.com     engine = task->thread->engine;
5002507Smax.romanov@nginx.com 
5003507Smax.romanov@nginx.com     nxt_assert(app->engine == engine);
5004507Smax.romanov@nginx.com 
5005811Svbart@nginx.com     threshold = engine->timers.now + app->joint->idle_timer.bias;
5006507Smax.romanov@nginx.com     timeout = 0;
5007507Smax.romanov@nginx.com 
5008507Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
5009507Smax.romanov@nginx.com 
5010507Smax.romanov@nginx.com     if (queued) {
5011507Smax.romanov@nginx.com         app->adjust_idle_work.data = NULL;
5012343Smax.romanov@nginx.com     }
5013507Smax.romanov@nginx.com 
50141547Smax.romanov@nginx.com     nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d",
50151547Smax.romanov@nginx.com               &app->name,
50161547Smax.romanov@nginx.com               (int) app->idle_processes, (int) app->spare_processes);
50171547Smax.romanov@nginx.com 
5018507Smax.romanov@nginx.com     while (app->idle_processes > app->spare_processes) {
5019507Smax.romanov@nginx.com 
5020551Smax.romanov@nginx.com         nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
5021507Smax.romanov@nginx.com 
5022507Smax.romanov@nginx.com         lnk = nxt_queue_first(&app->idle_ports);
5023507Smax.romanov@nginx.com         port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
5024507Smax.romanov@nginx.com 
5025507Smax.romanov@nginx.com         timeout = port->idle_start + app->idle_timeout;
5026507Smax.romanov@nginx.com 
50271547Smax.romanov@nginx.com         nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M",
50281547Smax.romanov@nginx.com                   &app->name, port->pid,
50291547Smax.romanov@nginx.com                   port->idle_start, timeout, threshold);
50301547Smax.romanov@nginx.com 
5031507Smax.romanov@nginx.com         if (timeout > threshold) {
5032507Smax.romanov@nginx.com             break;
5033507Smax.romanov@nginx.com         }
5034507Smax.romanov@nginx.com 
5035507Smax.romanov@nginx.com         nxt_queue_remove(lnk);
5036507Smax.romanov@nginx.com         lnk->next = NULL;
5037507Smax.romanov@nginx.com 
50381549Smax.romanov@nginx.com         nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)",
50391549Smax.romanov@nginx.com                   &app->name, port->pid, port->id);
50401549Smax.romanov@nginx.com 
5041507Smax.romanov@nginx.com         nxt_queue_chk_remove(&port->app_link);
5042507Smax.romanov@nginx.com 
50431547Smax.romanov@nginx.com         nxt_port_hash_remove(&app->port_hash, port);
50441547Smax.romanov@nginx.com         app->port_hash_count--;
50451547Smax.romanov@nginx.com 
5046507Smax.romanov@nginx.com         app->idle_processes--;
5047507Smax.romanov@nginx.com         app->processes--;
5048507Smax.romanov@nginx.com         port->app = NULL;
5049507Smax.romanov@nginx.com 
5050507Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&app->mutex);
5051507Smax.romanov@nginx.com 
5052507Smax.romanov@nginx.com         nxt_debug(task, "app '%V' send QUIT to idle port %PI",
5053507Smax.romanov@nginx.com                   &app->name, port->pid);
5054507Smax.romanov@nginx.com 
5055507Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
5056507Smax.romanov@nginx.com 
5057507Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
5058507Smax.romanov@nginx.com 
5059507Smax.romanov@nginx.com         nxt_thread_mutex_lock(&app->mutex);
5060507Smax.romanov@nginx.com     }
5061507Smax.romanov@nginx.com 
5062507Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
5063507Smax.romanov@nginx.com 
5064507Smax.romanov@nginx.com     if (timeout > threshold) {
5065753Smax.romanov@nginx.com         nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
5066507Smax.romanov@nginx.com 
5067507Smax.romanov@nginx.com     } else {
5068753Smax.romanov@nginx.com         nxt_timer_disable(engine, &app->joint->idle_timer);
5069507Smax.romanov@nginx.com     }
5070507Smax.romanov@nginx.com 
5071507Smax.romanov@nginx.com     if (queued) {
5072507Smax.romanov@nginx.com         nxt_router_app_use(task, app, -1);
5073507Smax.romanov@nginx.com     }
5074507Smax.romanov@nginx.com }
5075507Smax.romanov@nginx.com 
5076507Smax.romanov@nginx.com 
5077507Smax.romanov@nginx.com static void
5078507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
5079507Smax.romanov@nginx.com {
5080753Smax.romanov@nginx.com     nxt_timer_t      *timer;
5081753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
5082507Smax.romanov@nginx.com 
5083507Smax.romanov@nginx.com     timer = obj;
5084753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
5085753Smax.romanov@nginx.com 
5086753Smax.romanov@nginx.com     if (nxt_fast_path(app_joint->app != NULL)) {
5087753Smax.romanov@nginx.com         nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
5088753Smax.romanov@nginx.com     }
5089753Smax.romanov@nginx.com }
5090753Smax.romanov@nginx.com 
5091753Smax.romanov@nginx.com 
5092753Smax.romanov@nginx.com static void
5093753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
5094753Smax.romanov@nginx.com {
5095753Smax.romanov@nginx.com     nxt_timer_t      *timer;
5096753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
5097753Smax.romanov@nginx.com 
5098753Smax.romanov@nginx.com     timer = obj;
5099753Smax.romanov@nginx.com     app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
5100753Smax.romanov@nginx.com 
5101753Smax.romanov@nginx.com     nxt_router_app_joint_use(task, app_joint, -1);
5102507Smax.romanov@nginx.com }
5103507Smax.romanov@nginx.com 
5104507Smax.romanov@nginx.com 
5105507Smax.romanov@nginx.com static void
5106753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
5107507Smax.romanov@nginx.com {
5108753Smax.romanov@nginx.com     nxt_app_t        *app;
5109*1998St.nateldemoura@f5.com     nxt_port_t       *port, *proto_port;
5110753Smax.romanov@nginx.com     nxt_app_joint_t  *app_joint;
5111753Smax.romanov@nginx.com 
5112753Smax.romanov@nginx.com     app_joint = obj;
5113753Smax.romanov@nginx.com     app = app_joint->app;
5114753Smax.romanov@nginx.com 
5115753Smax.romanov@nginx.com     for ( ;; ) {
51161549Smax.romanov@nginx.com         port = nxt_router_app_get_port_for_quit(task, app);
5117753Smax.romanov@nginx.com         if (port == NULL) {
5118753Smax.romanov@nginx.com             break;
5119753Smax.romanov@nginx.com         }
5120753Smax.romanov@nginx.com 
5121753Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
5122753Smax.romanov@nginx.com     }
5123753Smax.romanov@nginx.com 
51241658Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
51251658Smax.romanov@nginx.com 
51261658Smax.romanov@nginx.com     for ( ;; ) {
51271658Smax.romanov@nginx.com         port = nxt_port_hash_retrieve(&app->port_hash);
51281658Smax.romanov@nginx.com         if (port == NULL) {
51291658Smax.romanov@nginx.com             break;
51301658Smax.romanov@nginx.com         }
51311658Smax.romanov@nginx.com 
51321658Smax.romanov@nginx.com         app->port_hash_count--;
51331658Smax.romanov@nginx.com 
51341658Smax.romanov@nginx.com         port->app = NULL;
51351658Smax.romanov@nginx.com 
51361658Smax.romanov@nginx.com         nxt_port_close(task, port);
51371658Smax.romanov@nginx.com 
51381658Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
51391658Smax.romanov@nginx.com     }
51401658Smax.romanov@nginx.com 
5141*1998St.nateldemoura@f5.com     proto_port = app->proto_port;
5142*1998St.nateldemoura@f5.com 
5143*1998St.nateldemoura@f5.com     if (proto_port != NULL) {
5144*1998St.nateldemoura@f5.com         nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name,
5145*1998St.nateldemoura@f5.com                   proto_port->pid);
5146*1998St.nateldemoura@f5.com 
5147*1998St.nateldemoura@f5.com         app->proto_port = NULL;
5148*1998St.nateldemoura@f5.com         proto_port->app = NULL;
5149*1998St.nateldemoura@f5.com     }
5150*1998St.nateldemoura@f5.com 
51511658Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
51521658Smax.romanov@nginx.com 
5153*1998St.nateldemoura@f5.com     if (proto_port != NULL) {
5154*1998St.nateldemoura@f5.com         nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT,
5155*1998St.nateldemoura@f5.com                               -1, 0, 0, NULL);
5156*1998St.nateldemoura@f5.com 
5157*1998St.nateldemoura@f5.com         nxt_port_close(task, proto_port);
5158*1998St.nateldemoura@f5.com 
5159*1998St.nateldemoura@f5.com         nxt_port_use(task, proto_port, -1);
5160*1998St.nateldemoura@f5.com     }
5161*1998St.nateldemoura@f5.com 
5162*1998St.nateldemoura@f5.com     nxt_assert(app->proto_port == NULL);
5163753Smax.romanov@nginx.com     nxt_assert(app->processes == 0);
51641547Smax.romanov@nginx.com     nxt_assert(app->active_requests == 0);
51651547Smax.romanov@nginx.com     nxt_assert(app->port_hash_count == 0);
5166753Smax.romanov@nginx.com     nxt_assert(app->idle_processes == 0);
5167753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->ports));
5168753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->spare_ports));
5169753Smax.romanov@nginx.com     nxt_assert(nxt_queue_is_empty(&app->idle_ports));
5170753Smax.romanov@nginx.com 
51711547Smax.romanov@nginx.com     nxt_port_mmaps_destroy(&app->outgoing, 1);
51721547Smax.romanov@nginx.com 
51731547Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->outgoing.mutex);
51741547Smax.romanov@nginx.com 
51751547Smax.romanov@nginx.com     if (app->shared_port != NULL) {
51761547Smax.romanov@nginx.com         app->shared_port->app = NULL;
51771547Smax.romanov@nginx.com         nxt_port_close(task, app->shared_port);
51781547Smax.romanov@nginx.com         nxt_port_use(task, app->shared_port, -1);
51791926Smax.romanov@nginx.com 
51801926Smax.romanov@nginx.com         app->shared_port = NULL;
51811547Smax.romanov@nginx.com     }
51821547Smax.romanov@nginx.com 
5183753Smax.romanov@nginx.com     nxt_thread_mutex_destroy(&app->mutex);
51841473Svbart@nginx.com     nxt_mp_destroy(app->mem_pool);
5185753Smax.romanov@nginx.com 
5186753Smax.romanov@nginx.com     app_joint->app = NULL;
5187753Smax.romanov@nginx.com 
5188753Smax.romanov@nginx.com     if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
5189753Smax.romanov@nginx.com         app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
5190753Smax.romanov@nginx.com         nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
5191753Smax.romanov@nginx.com 
5192753Smax.romanov@nginx.com     } else {
5193753Smax.romanov@nginx.com         nxt_router_app_joint_use(task, app_joint, -1);
5194753Smax.romanov@nginx.com     }
5195141Smax.romanov@nginx.com }
5196141Smax.romanov@nginx.com 
5197141Smax.romanov@nginx.com 
5198427Smax.romanov@nginx.com static void
51991547Smax.romanov@nginx.com nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
52001547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
5201141Smax.romanov@nginx.com {
52021561Smax.romanov@nginx.com     nxt_bool_t          start_process;
52031561Smax.romanov@nginx.com     nxt_port_t          *port;
52041561Smax.romanov@nginx.com     nxt_http_request_t  *r;
52051547Smax.romanov@nginx.com 
52061547Smax.romanov@nginx.com     start_process = 0;
5207427Smax.romanov@nginx.com 
5208427Smax.romanov@nginx.com     nxt_thread_mutex_lock(&app->mutex);
5209427Smax.romanov@nginx.com 
52101547Smax.romanov@nginx.com     port = app->shared_port;
52111547Smax.romanov@nginx.com     nxt_port_inc_use(port);
52121547Smax.romanov@nginx.com 
52131547Smax.romanov@nginx.com     app->active_requests++;
52141547Smax.romanov@nginx.com 
52151547Smax.romanov@nginx.com     if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
52161547Smax.romanov@nginx.com         app->pending_processes++;
52171547Smax.romanov@nginx.com         start_process = 1;
52181547Smax.romanov@nginx.com     }
5219427Smax.romanov@nginx.com 
52201561Smax.romanov@nginx.com     r = req_rpc_data->request;
52211561Smax.romanov@nginx.com 
52221561Smax.romanov@nginx.com     /*
52231561Smax.romanov@nginx.com      * Put request into application-wide list to be able to cancel request
52241561Smax.romanov@nginx.com      * if something goes wrong with application processes.
52251561Smax.romanov@nginx.com      */
52261561Smax.romanov@nginx.com     nxt_queue_insert_tail(&app->ack_waiting_req, &r->app_link);
52271561Smax.romanov@nginx.com 
5228427Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&app->mutex);
5229427Smax.romanov@nginx.com 
52301561Smax.romanov@nginx.com     /*
52311561Smax.romanov@nginx.com      * Retain request memory pool while request is linked in ack_waiting_req
52321561Smax.romanov@nginx.com      * to guarantee request structure memory is accessble.
52331561Smax.romanov@nginx.com      */
52341561Smax.romanov@nginx.com     nxt_mp_retain(r->mem_pool);
52351561Smax.romanov@nginx.com 
52361547Smax.romanov@nginx.com     req_rpc_data->app_port = port;
52371547Smax.romanov@nginx.com     req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED;
52381547Smax.romanov@nginx.com 
52391547Smax.romanov@nginx.com     if (start_process) {
52401547Smax.romanov@nginx.com         nxt_router_start_app_process(task, app);
52411547Smax.romanov@nginx.com     }
5242427Smax.romanov@nginx.com }
5243427Smax.romanov@nginx.com 
5244427Smax.romanov@nginx.com 
5245431Sigor@sysoev.ru void
52461007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
52471925Sz.hong@f5.com     nxt_http_action_t *action)
524853Sigor@sysoev.ru {
52491123Smax.romanov@nginx.com     nxt_event_engine_t      *engine;
52501925Sz.hong@f5.com     nxt_http_app_conf_t     *conf;
52511123Smax.romanov@nginx.com     nxt_request_rpc_data_t  *req_rpc_data;
5252431Sigor@sysoev.ru 
52531925Sz.hong@f5.com     conf = action->u.conf;
525488Smax.romanov@nginx.com     engine = task->thread->engine;
525588Smax.romanov@nginx.com 
52561925Sz.hong@f5.com     r->app_target = conf->target;
52571925Sz.hong@f5.com 
52581123Smax.romanov@nginx.com     req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
5259318Smax.romanov@nginx.com                                           nxt_router_response_ready_handler,
5260318Smax.romanov@nginx.com                                           nxt_router_response_error_handler,
52611123Smax.romanov@nginx.com                                           sizeof(nxt_request_rpc_data_t));
52621123Smax.romanov@nginx.com     if (nxt_slow_path(req_rpc_data == NULL)) {
5263431Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
5264141Smax.romanov@nginx.com         return;
526588Smax.romanov@nginx.com     }
526688Smax.romanov@nginx.com 
52671402Smax.romanov@nginx.com     /*
52681402Smax.romanov@nginx.com      * At this point we have request req_rpc_data allocated and registered
52691402Smax.romanov@nginx.com      * in port handlers.  Need to fixup request memory pool.  Counterpart
52701402Smax.romanov@nginx.com      * release will be called via following call chain:
52711402Smax.romanov@nginx.com      *    nxt_request_rpc_data_unlink() ->
52721547Smax.romanov@nginx.com      *        nxt_router_http_request_release_post() ->
52731402Smax.romanov@nginx.com      *            nxt_router_http_request_release()
52741402Smax.romanov@nginx.com      */
52751402Smax.romanov@nginx.com     nxt_mp_retain(r->mem_pool);
52761402Smax.romanov@nginx.com 
52771402Smax.romanov@nginx.com     r->timer.task = &engine->task;
52781402Smax.romanov@nginx.com     r->timer.work_queue = &engine->fast_work_queue;
52791402Smax.romanov@nginx.com     r->timer.log = engine->task.log;
52801402Smax.romanov@nginx.com     r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
52811402Smax.romanov@nginx.com 
52821561Smax.romanov@nginx.com     r->engine = engine;
52831561Smax.romanov@nginx.com     r->err_work.handler = nxt_router_http_request_error;
52841561Smax.romanov@nginx.com     r->err_work.task = task;
52851561Smax.romanov@nginx.com     r->err_work.obj = r;
52861561Smax.romanov@nginx.com 
52871123Smax.romanov@nginx.com     req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
52881925Sz.hong@f5.com     req_rpc_data->app = conf->app;
52891547Smax.romanov@nginx.com     req_rpc_data->msg_info.body_fd = -1;
52901547Smax.romanov@nginx.com     req_rpc_data->rpc_cancel = 1;
5291425Smax.romanov@nginx.com 
52921925Sz.hong@f5.com     nxt_router_app_use(task, conf->app, 1);
5293425Smax.romanov@nginx.com 
52941123Smax.romanov@nginx.com     req_rpc_data->request = r;
52951131Smax.romanov@nginx.com     r->req_rpc_data = req_rpc_data;
52961123Smax.romanov@nginx.com 
52971547Smax.romanov@nginx.com     if (r->last != NULL) {
52981547Smax.romanov@nginx.com         r->last->completion_handler = nxt_router_http_request_done;
52991547Smax.romanov@nginx.com     }
53001547Smax.romanov@nginx.com 
53011925Sz.hong@f5.com     nxt_router_app_port_get(task, conf->app, req_rpc_data);
53021547Smax.romanov@nginx.com     nxt_router_app_prepare_request(task, req_rpc_data);
53031547Smax.romanov@nginx.com }
53041547Smax.romanov@nginx.com 
53051547Smax.romanov@nginx.com 
53061547Smax.romanov@nginx.com static void
53071561Smax.romanov@nginx.com nxt_router_http_request_error(nxt_task_t *task, void *obj, void *data)
53081561Smax.romanov@nginx.com {
53091561Smax.romanov@nginx.com     nxt_http_request_t  *r;
53101561Smax.romanov@nginx.com 
53111561Smax.romanov@nginx.com     r = obj;
53121561Smax.romanov@nginx.com 
53131561Smax.romanov@nginx.com     nxt_debug(task, "router http request error (rpc_data %p)", r->req_rpc_data);
53141561Smax.romanov@nginx.com 
53151561Smax.romanov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
53161561Smax.romanov@nginx.com 
53171561Smax.romanov@nginx.com     if (r->req_rpc_data != NULL) {
53181561Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, r->req_rpc_data);
53191561Smax.romanov@nginx.com     }
53201561Smax.romanov@nginx.com 
53211561Smax.romanov@nginx.com     nxt_mp_release(r->mem_pool);
53221561Smax.romanov@nginx.com }
53231561Smax.romanov@nginx.com 
53241561Smax.romanov@nginx.com 
53251561Smax.romanov@nginx.com static void
53261547Smax.romanov@nginx.com nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data)
53271547Smax.romanov@nginx.com {
53281547Smax.romanov@nginx.com     nxt_http_request_t  *r;
53291547Smax.romanov@nginx.com 
53301547Smax.romanov@nginx.com     r = data;
53311547Smax.romanov@nginx.com 
53321547Smax.romanov@nginx.com     nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data);
53331547Smax.romanov@nginx.com 
53341561Smax.romanov@nginx.com     if (r->req_rpc_data != NULL) {
53351547Smax.romanov@nginx.com         nxt_request_rpc_data_unlink(task, r->req_rpc_data);
53361547Smax.romanov@nginx.com     }
53371547Smax.romanov@nginx.com 
53381547Smax.romanov@nginx.com     nxt_http_request_close_handler(task, r, r->proto.any);
5339167Smax.romanov@nginx.com }
5340167Smax.romanov@nginx.com 
5341167Smax.romanov@nginx.com 
5342167Smax.romanov@nginx.com static void
53431123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task,
53441547Smax.romanov@nginx.com     nxt_request_rpc_data_t *req_rpc_data)
5345167Smax.romanov@nginx.com {
53461547Smax.romanov@nginx.com     nxt_app_t         *app;
53471547Smax.romanov@nginx.com     nxt_buf_t         *buf, *body;
53481123Smax.romanov@nginx.com     nxt_int_t         res;
53491545Smax.romanov@nginx.com     nxt_port_t        *port, *reply_port;
53501547Smax.romanov@nginx.com 
53511555Smax.romanov@nginx.com     int                   notify;
53521555Smax.romanov@nginx.com     struct {
53531555Smax.romanov@nginx.com         nxt_port_msg_t       pm;
53541555Smax.romanov@nginx.com         nxt_port_mmap_msg_t  mm;
53551555Smax.romanov@nginx.com     } msg;
53561555Smax.romanov@nginx.com 
53571555Smax.romanov@nginx.com 
53581547Smax.romanov@nginx.com     app = req_rpc_data->app;
53591547Smax.romanov@nginx.com 
53601547Smax.romanov@nginx.com     nxt_assert(app != NULL);
53611547Smax.romanov@nginx.com 
53621547Smax.romanov@nginx.com     port = req_rpc_data->app_port;
53631547Smax.romanov@nginx.com 
53641547Smax.romanov@nginx.com     nxt_assert(port != NULL);
53651555Smax.romanov@nginx.com     nxt_assert(port->queue != NULL);
53661547Smax.romanov@nginx.com 
53671547Smax.romanov@nginx.com     reply_port = task->thread->engine->port;
53681547Smax.romanov@nginx.com 
53691547Smax.romanov@nginx.com     buf = nxt_router_prepare_msg(task, req_rpc_data->request, app,
53701547Smax.romanov@nginx.com                                  nxt_app_msg_prefix[app->type]);
5371743Smax.romanov@nginx.com     if (nxt_slow_path(buf == NULL)) {
53721547Smax.romanov@nginx.com         nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message",
53731547Smax.romanov@nginx.com                   req_rpc_data->stream, &app->name);
53741547Smax.romanov@nginx.com 
53751547Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
53761547Smax.romanov@nginx.com                                NXT_HTTP_INTERNAL_SERVER_ERROR);
53771547Smax.romanov@nginx.com 
53781547Smax.romanov@nginx.com         return;
5379122Smax.romanov@nginx.com     }
538088Smax.romanov@nginx.com 
5381507Smax.romanov@nginx.com     nxt_debug(task, "about to send %O bytes buffer to app process port %d",
5382743Smax.romanov@nginx.com                     nxt_buf_used_size(buf),
5383743Smax.romanov@nginx.com                     port->socket.fd);
538488Smax.romanov@nginx.com 
53851547Smax.romanov@nginx.com     req_rpc_data->msg_info.buf = buf;
53861547Smax.romanov@nginx.com 
53871547Smax.romanov@nginx.com     body = req_rpc_data->request->body;
53881547Smax.romanov@nginx.com 
53891547Smax.romanov@nginx.com     if (body != NULL && nxt_buf_is_file(body)) {
53901547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = body->file->fd;
53911547Smax.romanov@nginx.com 
53921547Smax.romanov@nginx.com         body->file->fd = -1;
53931547Smax.romanov@nginx.com 
53941547Smax.romanov@nginx.com     } else {
53951547Smax.romanov@nginx.com         req_rpc_data->msg_info.body_fd = -1;
53961547Smax.romanov@nginx.com     }
53971547Smax.romanov@nginx.com 
53981555Smax.romanov@nginx.com     msg.pm.stream = req_rpc_data->stream;
53991555Smax.romanov@nginx.com     msg.pm.pid = reply_port->pid;
54001555Smax.romanov@nginx.com     msg.pm.reply_port = reply_port->id;
54011555Smax.romanov@nginx.com     msg.pm.type = NXT_PORT_MSG_REQ_HEADERS;
54021555Smax.romanov@nginx.com     msg.pm.last = 0;
54031555Smax.romanov@nginx.com     msg.pm.mmap = 1;
54041555Smax.romanov@nginx.com     msg.pm.nf = 0;
54051555Smax.romanov@nginx.com     msg.pm.mf = 0;
54061555Smax.romanov@nginx.com     msg.pm.tracking = 0;
54071555Smax.romanov@nginx.com 
54081555Smax.romanov@nginx.com     nxt_port_mmap_handler_t *mmap_handler = buf->parent;
54091555Smax.romanov@nginx.com     nxt_port_mmap_header_t *hdr = mmap_handler->hdr;
54101555Smax.romanov@nginx.com 
54111555Smax.romanov@nginx.com     msg.mm.mmap_id = hdr->id;
54121555Smax.romanov@nginx.com     msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos);
54131555Smax.romanov@nginx.com     msg.mm.size = nxt_buf_used_size(buf);
54141555Smax.romanov@nginx.com 
54151555Smax.romanov@nginx.com     res = nxt_app_queue_send(port->queue, &msg, sizeof(msg),
54161555Smax.romanov@nginx.com                              req_rpc_data->stream, &notify,
54171555Smax.romanov@nginx.com                              &req_rpc_data->msg_info.tracking_cookie);
54181555Smax.romanov@nginx.com     if (nxt_fast_path(res == NXT_OK)) {
54191555Smax.romanov@nginx.com         if (notify != 0) {
54201555Smax.romanov@nginx.com             (void) nxt_port_socket_write(task, port,
54211555Smax.romanov@nginx.com                                          NXT_PORT_MSG_READ_QUEUE,
54221555Smax.romanov@nginx.com                                          -1, req_rpc_data->stream,
54231555Smax.romanov@nginx.com                                          reply_port->id, NULL);
54241555Smax.romanov@nginx.com 
54251555Smax.romanov@nginx.com         } else {
54261555Smax.romanov@nginx.com             nxt_debug(task, "queue is not empty");
54271555Smax.romanov@nginx.com         }
54281555Smax.romanov@nginx.com 
54291615Smax.romanov@nginx.com         buf->is_port_mmap_sent = 1;
54301615Smax.romanov@nginx.com         buf->mem.pos = buf->mem.free;
54311615Smax.romanov@nginx.com 
54321555Smax.romanov@nginx.com     } else {
54331547Smax.romanov@nginx.com         nxt_alert(task, "stream #%uD, app '%V': failed to send app message",
54341547Smax.romanov@nginx.com                   req_rpc_data->stream, &app->name);
54351547Smax.romanov@nginx.com 
54361547Smax.romanov@nginx.com         nxt_http_request_error(task, req_rpc_data->request,
54371547Smax.romanov@nginx.com                                NXT_HTTP_INTERNAL_SERVER_ERROR);
54381547Smax.romanov@nginx.com     }
543953Sigor@sysoev.ru }
544053Sigor@sysoev.ru 
544153Sigor@sysoev.ru 
5442743Smax.romanov@nginx.com struct nxt_fields_iter_s {
5443743Smax.romanov@nginx.com     nxt_list_part_t   *part;
5444743Smax.romanov@nginx.com     nxt_http_field_t  *field;
5445743Smax.romanov@nginx.com };
5446743Smax.romanov@nginx.com 
5447743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s  nxt_fields_iter_t;
5448743Smax.romanov@nginx.com 
5449743Smax.romanov@nginx.com 
5450743Smax.romanov@nginx.com static nxt_http_field_t *
5451743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
5452216Sigor@sysoev.ru {
5453743Smax.romanov@nginx.com     if (part == NULL) {
5454743Smax.romanov@nginx.com         return NULL;
5455216Sigor@sysoev.ru     }
5456216Sigor@sysoev.ru 
5457743Smax.romanov@nginx.com     while (part->nelts == 0) {
5458743Smax.romanov@nginx.com         part = part->next;
5459743Smax.romanov@nginx.com         if (part == NULL) {
5460743Smax.romanov@nginx.com             return NULL;
5461743Smax.romanov@nginx.com         }
5462216Sigor@sysoev.ru     }
5463216Sigor@sysoev.ru 
5464743Smax.romanov@nginx.com     i->part = part;
5465743Smax.romanov@nginx.com     i->field = nxt_list_data(i->part);
5466743Smax.romanov@nginx.com 
5467743Smax.romanov@nginx.com     return i->field;
5468743Smax.romanov@nginx.com }
5469743Smax.romanov@nginx.com 
5470743Smax.romanov@nginx.com 
5471743Smax.romanov@nginx.com static nxt_http_field_t *
5472743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
5473743Smax.romanov@nginx.com {
5474743Smax.romanov@nginx.com     return nxt_fields_part_first(nxt_list_part(fields), i);
5475743Smax.romanov@nginx.com }
5476743Smax.romanov@nginx.com 
5477743Smax.romanov@nginx.com 
5478743Smax.romanov@nginx.com static nxt_http_field_t *
5479743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i)
5480743Smax.romanov@nginx.com {
5481743Smax.romanov@nginx.com     nxt_http_field_t  *end = nxt_list_data(i->part);
5482743Smax.romanov@nginx.com 
5483743Smax.romanov@nginx.com     end += i->part->nelts;
5484743Smax.romanov@nginx.com     i->field++;
5485743Smax.romanov@nginx.com 
5486743Smax.romanov@nginx.com     if (i->field < end) {
5487743Smax.romanov@nginx.com         return i->field;
5488216Sigor@sysoev.ru     }
5489216Sigor@sysoev.ru 
5490743Smax.romanov@nginx.com     return nxt_fields_part_first(i->part->next, i);
5491216Sigor@sysoev.ru }
5492216Sigor@sysoev.ru 
5493216Sigor@sysoev.ru 
5494743Smax.romanov@nginx.com static nxt_buf_t *
54951007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
54961547Smax.romanov@nginx.com     nxt_app_t *app, const nxt_str_t *prefix)
5497216Sigor@sysoev.ru {
54981007Salexander.borisov@nginx.com     void                *target_pos, *query_pos;
54991007Salexander.borisov@nginx.com     u_char              *pos, *end, *p, c;
55001007Salexander.borisov@nginx.com     size_t              fields_count, req_size, size, free_size;
55011007Salexander.borisov@nginx.com     size_t              copy_size;
55021007Salexander.borisov@nginx.com     nxt_off_t           content_length;
55031007Salexander.borisov@nginx.com     nxt_buf_t           *b, *buf, *out, **tail;
55041007Salexander.borisov@nginx.com     nxt_http_field_t    *field, *dup;
55051007Salexander.borisov@nginx.com     nxt_unit_field_t    *dst_field;
55061007Salexander.borisov@nginx.com     nxt_fields_iter_t   iter, dup_iter;
55071007Salexander.borisov@nginx.com     nxt_unit_request_t  *req;
5508216Sigor@sysoev.ru 
5509743Smax.romanov@nginx.com     req_size = sizeof(nxt_unit_request_t)
55101007Salexander.borisov@nginx.com                + r->method->length + 1
55111007Salexander.borisov@nginx.com                + r->version.length + 1
55121007Salexander.borisov@nginx.com                + r->remote->length + 1
55131007Salexander.borisov@nginx.com                + r->local->length + 1
55141007Salexander.borisov@nginx.com                + r->server_name.length + 1
55151007Salexander.borisov@nginx.com                + r->target.length + 1
55161007Salexander.borisov@nginx.com                + (r->path->start != r->target.start ? r->path->length + 1 : 0);
55171007Salexander.borisov@nginx.com 
55181007Salexander.borisov@nginx.com     content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
5519743Smax.romanov@nginx.com     fields_count = 0;
5520743Smax.romanov@nginx.com 
55211007Salexander.borisov@nginx.com     nxt_list_each(field, r->fields) {
5522743Smax.romanov@nginx.com         fields_count++;
5523743Smax.romanov@nginx.com 
5524743Smax.romanov@nginx.com         req_size += field->name_length + prefix->length + 1
5525743Smax.romanov@nginx.com                     + field->value_length + 1;
5526743Smax.romanov@nginx.com     } nxt_list_loop;
5527743Smax.romanov@nginx.com 
5528743Smax.romanov@nginx.com     req_size += fields_count * sizeof(nxt_unit_field_t);
5529743Smax.romanov@nginx.com 
5530743Smax.romanov@nginx.com     if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
5531743Smax.romanov@nginx.com         nxt_alert(task, "headers to big to fit in shared memory (%d)",
5532743Smax.romanov@nginx.com                   (int) req_size);
5533743Smax.romanov@nginx.com 
5534743Smax.romanov@nginx.com         return NULL;
5535743Smax.romanov@nginx.com     }
5536743Smax.romanov@nginx.com 
55371547Smax.romanov@nginx.com     out = nxt_port_mmap_get_buf(task, &app->outgoing,
55381007Salexander.borisov@nginx.com               nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
5539743Smax.romanov@nginx.com     if (nxt_slow_path(out == NULL)) {
5540743Smax.romanov@nginx.com         return NULL;
5541743Smax.romanov@nginx.com     }
5542743Smax.romanov@nginx.com 
5543743Smax.romanov@nginx.com     req = (nxt_unit_request_t *) out->mem.free;
5544743Smax.romanov@nginx.com     out->mem.free += req_size;
5545743Smax.romanov@nginx.com 
55461473Svbart@nginx.com     req->app_target = r->app_target;
55471473Svbart@nginx.com 
55481007Salexander.borisov@nginx.com     req->content_length = content_length;
5549743Smax.romanov@nginx.com 
5550743Smax.romanov@nginx.com     p = (u_char *) (req->fields + fields_count);
5551743Smax.romanov@nginx.com 
5552743Smax.romanov@nginx.com     nxt_debug(task, "fields_count=%d", (int) fields_count);
5553743Smax.romanov@nginx.com 
55541007Salexander.borisov@nginx.com     req->method_length = r->method->length;
5555743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->method, p);
55561007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->method->start, r->method->length);
5557743Smax.romanov@nginx.com     *p++ = '\0';
5558743Smax.romanov@nginx.com 
55591007Salexander.borisov@nginx.com     req->version_length = r->version.length;
5560743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->version, p);
55611007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->version.start, r->version.length);
5562743Smax.romanov@nginx.com     *p++ = '\0';
5563743Smax.romanov@nginx.com 
55641007Salexander.borisov@nginx.com     req->remote_length = r->remote->address_length;
5565743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->remote, p);
55661007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
55671007Salexander.borisov@nginx.com                    r->remote->address_length);
5568743Smax.romanov@nginx.com     *p++ = '\0';
5569743Smax.romanov@nginx.com 
55701007Salexander.borisov@nginx.com     req->local_length = r->local->address_length;
5571743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->local, p);
55721007Salexander.borisov@nginx.com     p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
5573743Smax.romanov@nginx.com     *p++ = '\0';
5574743Smax.romanov@nginx.com 
55751011Smax.romanov@nginx.com     req->tls = (r->tls != NULL);
55761131Smax.romanov@nginx.com     req->websocket_handshake = r->websocket_handshake;
55771011Smax.romanov@nginx.com 
55781007Salexander.borisov@nginx.com     req->server_name_length = r->server_name.length;
5579967Svbart@nginx.com     nxt_unit_sptr_set(&req->server_name, p);
55801007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
5581967Svbart@nginx.com     *p++ = '\0';
5582967Svbart@nginx.com 
5583743Smax.romanov@nginx.com     target_pos = p;
55841007Salexander.borisov@nginx.com     req->target_length = (uint32_t) r->target.length;
5585743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->target, p);
55861007Salexander.borisov@nginx.com     p = nxt_cpymem(p, r->target.start, r->target.length);
5587743Smax.romanov@nginx.com     *p++ = '\0';
5588743Smax.romanov@nginx.com 
55891007Salexander.borisov@nginx.com     req->path_length = (uint32_t) r->path->length;
55901007Salexander.borisov@nginx.com     if (r->path->start == r->target.start) {
5591743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, target_pos);
5592277Sigor@sysoev.ru 
5593216Sigor@sysoev.ru     } else {
5594743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->path, p);
55951007Salexander.borisov@nginx.com         p = nxt_cpymem(p, r->path->start, r->path->length);
5596743Smax.romanov@nginx.com         *p++ = '\0';
5597305Smax.romanov@nginx.com     }
5598216Sigor@sysoev.ru 
55991990Sz.hong@f5.com     req->query_length = (uint32_t) r->args->length;
56001990Sz.hong@f5.com     if (r->args->start != NULL) {
5601743Smax.romanov@nginx.com         query_pos = nxt_pointer_to(target_pos,
56021007Salexander.borisov@nginx.com                                    r->args->start - r->target.start);
5603743Smax.romanov@nginx.com 
5604743Smax.romanov@nginx.com         nxt_unit_sptr_set(&req->query, query_pos);
5605277Sigor@sysoev.ru 
5606216Sigor@sysoev.ru     } else {
5607743Smax.romanov@nginx.com         req->query.offset = 0;
5608216Sigor@sysoev.ru     }
5609216Sigor@sysoev.ru 
5610743Smax.romanov@nginx.com     req->content_length_field = NXT_UNIT_NONE_FIELD;
5611743Smax.romanov@nginx.com     req->content_type_field   = NXT_UNIT_NONE_FIELD;
5612743Smax.romanov@nginx.com     req->cookie_field         = NXT_UNIT_NONE_FIELD;
56131733Svbart@nginx.com     req->authorization_field  = NXT_UNIT_NONE_FIELD;
5614743Smax.romanov@nginx.com 
5615743Smax.romanov@nginx.com     dst_field = req->fields;
5616743Smax.romanov@nginx.com 
56171007Salexander.borisov@nginx.com     for (field = nxt_fields_first(r->fields, &iter);
5618743Smax.romanov@nginx.com          field != NULL;
5619743Smax.romanov@nginx.com          field = nxt_fields_next(&iter))
5620743Smax.romanov@nginx.com     {
5621743Smax.romanov@nginx.com         if (field->skip) {
5622743Smax.romanov@nginx.com             continue;
5623743Smax.romanov@nginx.com         }
5624743Smax.romanov@nginx.com 
5625743Smax.romanov@nginx.com         dst_field->hash = field->hash;
5626743Smax.romanov@nginx.com         dst_field->skip = 0;
5627743Smax.romanov@nginx.com         dst_field->name_length = field->name_length + prefix->length;
5628743Smax.romanov@nginx.com         dst_field->value_length = field->value_length;
5629743Smax.romanov@nginx.com 
56301007Salexander.borisov@nginx.com         if (field == r->content_length) {
5631743Smax.romanov@nginx.com             req->content_length_field = dst_field - req->fields;
5632743Smax.romanov@nginx.com 
56331007Salexander.borisov@nginx.com         } else if (field == r->content_type) {
5634743Smax.romanov@nginx.com             req->content_type_field = dst_field - req->fields;
5635743Smax.romanov@nginx.com 
56361007Salexander.borisov@nginx.com         } else if (field == r->cookie) {
5637743Smax.romanov@nginx.com             req->cookie_field = dst_field - req->fields;
56381733Svbart@nginx.com 
56391733Svbart@nginx.com         } else if (field == r->authorization) {
56401733Svbart@nginx.com             req->authorization_field = dst_field - req->fields;
5641743Smax.romanov@nginx.com         }
5642743Smax.romanov@nginx.com 
5643743Smax.romanov@nginx.com         nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
5644743Smax.romanov@nginx.com                   (int) field->hash, (int) field->skip,
5645743Smax.romanov@nginx.com                   (int) field->name_length, field->name,
5646743Smax.romanov@nginx.com                   (int) field->value_length, field->value);
5647743Smax.romanov@nginx.com 
5648743Smax.romanov@nginx.com         if (prefix->length != 0) {
5649743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
5650743Smax.romanov@nginx.com             p = nxt_cpymem(p, prefix->start, prefix->length);
5651743Smax.romanov@nginx.com 
5652743Smax.romanov@nginx.com             end = field->name + field->name_length;
5653743Smax.romanov@nginx.com             for (pos = field->name; pos < end; pos++) {
5654743Smax.romanov@nginx.com                 c = *pos;
5655743Smax.romanov@nginx.com 
5656743Smax.romanov@nginx.com                 if (c >= 'a' && c <= 'z') {
5657743Smax.romanov@nginx.com                     *p++ = (c & ~0x20);
5658743Smax.romanov@nginx.com                     continue;
5659743Smax.romanov@nginx.com                 }
5660743Smax.romanov@nginx.com 
5661743Smax.romanov@nginx.com                 if (c == '-') {
5662743Smax.romanov@nginx.com                     *p++ = '_';
5663743Smax.romanov@nginx.com                     continue;
5664743Smax.romanov@nginx.com                 }
5665743Smax.romanov@nginx.com 
5666743Smax.romanov@nginx.com                 *p++ = c;
5667743Smax.romanov@nginx.com             }
5668743Smax.romanov@nginx.com 
5669743Smax.romanov@nginx.com         } else {
5670743Smax.romanov@nginx.com             nxt_unit_sptr_set(&dst_field->name, p);
5671743Smax.romanov@nginx.com             p = nxt_cpymem(p, field->name, field->name_length);
5672743Smax.romanov@nginx.com         }
5673743Smax.romanov@nginx.com 
5674743Smax.romanov@nginx.com         *p++ = '\0';
5675743Smax.romanov@nginx.com 
5676743Smax.romanov@nginx.com         nxt_unit_sptr_set(&dst_field->value, p);
5677743Smax.romanov@nginx.com         p = nxt_cpymem(p, field->value, field->value_length);
5678743Smax.romanov@nginx.com 
5679743Smax.romanov@nginx.com         if (prefix->length != 0) {
5680743Smax.romanov@nginx.com             dup_iter = iter;
5681743Smax.romanov@nginx.com 
5682743Smax.romanov@nginx.com             for (dup = nxt_fields_next(&dup_iter);
5683743Smax.romanov@nginx.com                  dup != NULL;
5684743Smax.romanov@nginx.com                  dup = nxt_fields_next(&dup_iter))
5685743Smax.romanov@nginx.com             {
5686743Smax.romanov@nginx.com                 if (dup->name_length != field->name_length
5687743Smax.romanov@nginx.com                     || dup->skip
5688743Smax.romanov@nginx.com                     || dup->hash != field->hash
5689743Smax.romanov@nginx.com                     || nxt_memcasecmp(dup->name, field->name, dup->name_length))
5690743Smax.romanov@nginx.com                 {
5691743Smax.romanov@nginx.com                     continue;
5692743Smax.romanov@nginx.com                 }
5693743Smax.romanov@nginx.com 
5694743Smax.romanov@nginx.com                 p = nxt_cpymem(p, ", ", 2);
5695743Smax.romanov@nginx.com                 p = nxt_cpymem(p, dup->value, dup->value_length);
5696743Smax.romanov@nginx.com 
5697743Smax.romanov@nginx.com                 dst_field->value_length += 2 + dup->value_length;
5698743Smax.romanov@nginx.com 
5699743Smax.romanov@nginx.com                 dup->skip = 1;
5700743Smax.romanov@nginx.com             }
5701743Smax.romanov@nginx.com         }
5702743Smax.romanov@nginx.com 
5703743Smax.romanov@nginx.com         *p++ = '\0';
5704743Smax.romanov@nginx.com 
5705743Smax.romanov@nginx.com         dst_field++;
5706743Smax.romanov@nginx.com     }
5707743Smax.romanov@nginx.com 
57081007Salexander.borisov@nginx.com     req->fields_count = (uint32_t) (dst_field - req->fields);
5709743Smax.romanov@nginx.com 
5710743Smax.romanov@nginx.com     nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5711743Smax.romanov@nginx.com 
5712743Smax.romanov@nginx.com     buf = out;
5713743Smax.romanov@nginx.com     tail = &buf->next;
5714216Sigor@sysoev.ru 
57151007Salexander.borisov@nginx.com     for (b = r->body; b != NULL; b = b->next) {
5716743Smax.romanov@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
5717743Smax.romanov@nginx.com         pos = b->mem.pos;
5718743Smax.romanov@nginx.com 
5719743Smax.romanov@nginx.com         while (size > 0) {
5720743Smax.romanov@nginx.com             if (buf == NULL) {
5721743Smax.romanov@nginx.com                 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5722743Smax.romanov@nginx.com 
57231547Smax.romanov@nginx.com                 buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size);
5724743Smax.romanov@nginx.com                 if (nxt_slow_path(buf == NULL)) {
5725743Smax.romanov@nginx.com                     while (out != NULL) {
5726743Smax.romanov@nginx.com                         buf = out->next;
57271269Sigor@sysoev.ru                         out->next = NULL;
5728743Smax.romanov@nginx.com                         out->completion_handler(task, out, out->parent);
5729743Smax.romanov@nginx.com                         out = buf;
5730743Smax.romanov@nginx.com                     }
5731743Smax.romanov@nginx.com                     return NULL;
5732743Smax.romanov@nginx.com                 }
5733743Smax.romanov@nginx.com 
5734743Smax.romanov@nginx.com                 *tail = buf;
5735743Smax.romanov@nginx.com                 tail = &buf->next;
5736743Smax.romanov@nginx.com 
5737743Smax.romanov@nginx.com             } else {
5738743Smax.romanov@nginx.com                 free_size = nxt_buf_mem_free_size(&buf->mem);
5739743Smax.romanov@nginx.com                 if (free_size < size
5740743Smax.romanov@nginx.com                     && nxt_port_mmap_increase_buf(task, buf, size, 1)
5741743Smax.romanov@nginx.com                        == NXT_OK)
5742743Smax.romanov@nginx.com                 {
5743743Smax.romanov@nginx.com                     free_size = nxt_buf_mem_free_size(&buf->mem);
5744743Smax.romanov@nginx.com                 }
5745743Smax.romanov@nginx.com             }
5746743Smax.romanov@nginx.com 
5747743Smax.romanov@nginx.com             if (free_size > 0) {
5748743Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
5749743Smax.romanov@nginx.com 
5750743Smax.romanov@nginx.com                 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5751743Smax.romanov@nginx.com 
5752743Smax.romanov@nginx.com                 size -= copy_size;
5753743Smax.romanov@nginx.com                 pos += copy_size;
5754743Smax.romanov@nginx.com 
5755743Smax.romanov@nginx.com                 if (size == 0) {
5756743Smax.romanov@nginx.com                     break;
5757743Smax.romanov@nginx.com                 }
5758743Smax.romanov@nginx.com             }
5759743Smax.romanov@nginx.com 
5760743Smax.romanov@nginx.com             buf = NULL;
5761743Smax.romanov@nginx.com         }
5762216Sigor@sysoev.ru     }
5763216Sigor@sysoev.ru 
5764743Smax.romanov@nginx.com     return out;
5765584Salexander.borisov@nginx.com }
5766584Salexander.borisov@nginx.com 
5767584Salexander.borisov@nginx.com 
576853Sigor@sysoev.ru static void
5769318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5770318Smax.romanov@nginx.com {
5771615Smax.romanov@nginx.com     nxt_timer_t              *timer;
57721007Salexander.borisov@nginx.com     nxt_http_request_t       *r;
57731123Smax.romanov@nginx.com     nxt_request_rpc_data_t   *req_rpc_data;
5774318Smax.romanov@nginx.com 
5775318Smax.romanov@nginx.com     timer = obj;
5776318Smax.romanov@nginx.com 
5777318Smax.romanov@nginx.com     nxt_debug(task, "router app timeout");
5778318Smax.romanov@nginx.com 
57791007Salexander.borisov@nginx.com     r = nxt_timer_data(timer, nxt_http_request_t, timer);
57801123Smax.romanov@nginx.com     req_rpc_data = r->timer_data;
5781615Smax.romanov@nginx.com 
57821007Salexander.borisov@nginx.com     nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5783615Smax.romanov@nginx.com 
57841123Smax.romanov@nginx.com     nxt_request_rpc_data_unlink(task, req_rpc_data);
5785318Smax.romanov@nginx.com }
57861007Salexander.borisov@nginx.com 
57871007Salexander.borisov@nginx.com 
57881547Smax.romanov@nginx.com static void
57891547Smax.romanov@nginx.com nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r)
57901007Salexander.borisov@nginx.com {
57911007Salexander.borisov@nginx.com     r->timer.handler = nxt_router_http_request_release;
57921007Salexander.borisov@nginx.com     nxt_timer_add(task->thread->engine, &r->timer, 0);
57931007Salexander.borisov@nginx.com }
57941007Salexander.borisov@nginx.com 
57951007Salexander.borisov@nginx.com 
57961007Salexander.borisov@nginx.com static void
57971007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
57981007Salexander.borisov@nginx.com {
57991007Salexander.borisov@nginx.com     nxt_http_request_t  *r;
58001007Salexander.borisov@nginx.com 
58011547Smax.romanov@nginx.com     nxt_debug(task, "http request pool release");
58021007Salexander.borisov@nginx.com 
58031007Salexander.borisov@nginx.com     r = nxt_timer_data(obj, nxt_http_request_t, timer);
58041007Salexander.borisov@nginx.com 
58051007Salexander.borisov@nginx.com     nxt_mp_release(r->mem_pool);
58061007Salexander.borisov@nginx.com }
58071321Smax.romanov@nginx.com 
58081321Smax.romanov@nginx.com 
58091321Smax.romanov@nginx.com static void
58101321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
58111321Smax.romanov@nginx.com {
58121321Smax.romanov@nginx.com     size_t                   mi;
58131321Smax.romanov@nginx.com     uint32_t                 i;
58141321Smax.romanov@nginx.com     nxt_bool_t               ack;
58151321Smax.romanov@nginx.com     nxt_process_t            *process;
58161321Smax.romanov@nginx.com     nxt_free_map_t           *m;
58171754Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
58181321Smax.romanov@nginx.com 
58191321Smax.romanov@nginx.com     nxt_debug(task, "oosm in %PI", msg->port_msg.pid);
58201321Smax.romanov@nginx.com 
58211321Smax.romanov@nginx.com     process = nxt_runtime_process_find(task->thread->runtime,
58221321Smax.romanov@nginx.com                                        msg->port_msg.pid);
58231321Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
58241321Smax.romanov@nginx.com         return;
58251321Smax.romanov@nginx.com     }
58261321Smax.romanov@nginx.com 
58271321Smax.romanov@nginx.com     ack = 0;
58281321Smax.romanov@nginx.com 
58291321Smax.romanov@nginx.com     /*
58301321Smax.romanov@nginx.com      * To mitigate possible racing condition (when OOSM message received
58311321Smax.romanov@nginx.com      * after some of the memory was already freed), need to try to find
58321321Smax.romanov@nginx.com      * first free segment in shared memory and send ACK if found.
58331321Smax.romanov@nginx.com      */
58341321Smax.romanov@nginx.com 
58351321Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
58361321Smax.romanov@nginx.com 
58371321Smax.romanov@nginx.com     for (i = 0; i < process->incoming.size; i++) {
58381754Smax.romanov@nginx.com         mmap_handler = process->incoming.elts[i].mmap_handler;
58391754Smax.romanov@nginx.com 
58401754Smax.romanov@nginx.com         if (nxt_slow_path(mmap_handler == NULL)) {
58411754Smax.romanov@nginx.com             continue;
58421754Smax.romanov@nginx.com         }
58431754Smax.romanov@nginx.com 
58441754Smax.romanov@nginx.com         m = mmap_handler->hdr->free_map;
58451321Smax.romanov@nginx.com 
58461321Smax.romanov@nginx.com         for (mi = 0; mi < MAX_FREE_IDX; mi++) {
58471321Smax.romanov@nginx.com             if (m[mi] != 0) {
58481321Smax.romanov@nginx.com                 ack = 1;
58491321Smax.romanov@nginx.com 
58501321Smax.romanov@nginx.com                 nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA",
58511321Smax.romanov@nginx.com                           i, mi, m[mi]);
58521321Smax.romanov@nginx.com 
58531321Smax.romanov@nginx.com                 break;
58541321Smax.romanov@nginx.com             }
58551321Smax.romanov@nginx.com         }
58561321Smax.romanov@nginx.com     }
58571321Smax.romanov@nginx.com 
58581321Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
58591321Smax.romanov@nginx.com 
58601321Smax.romanov@nginx.com     if (ack) {
58611662Smax.romanov@nginx.com         nxt_process_broadcast_shm_ack(task, process);
58621321Smax.romanov@nginx.com     }
58631321Smax.romanov@nginx.com }
58641545Smax.romanov@nginx.com 
58651545Smax.romanov@nginx.com 
58661545Smax.romanov@nginx.com static void
58671546Smax.romanov@nginx.com nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
58681546Smax.romanov@nginx.com {
58691546Smax.romanov@nginx.com     nxt_fd_t                 fd;
58701546Smax.romanov@nginx.com     nxt_port_t               *port;
58711546Smax.romanov@nginx.com     nxt_runtime_t            *rt;
58721546Smax.romanov@nginx.com     nxt_port_mmaps_t         *mmaps;
58731546Smax.romanov@nginx.com     nxt_port_msg_get_mmap_t  *get_mmap_msg;
58741546Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
58751546Smax.romanov@nginx.com 
58761546Smax.romanov@nginx.com     rt = task->thread->runtime;
58771546Smax.romanov@nginx.com 
58781546Smax.romanov@nginx.com     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
58791546Smax.romanov@nginx.com                                  msg->port_msg.reply_port);
58801546Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
58811546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found",
58821546Smax.romanov@nginx.com                   msg->port_msg.pid, msg->port_msg.reply_port);
58831546Smax.romanov@nginx.com 
58841546Smax.romanov@nginx.com         return;
58851546Smax.romanov@nginx.com     }
58861546Smax.romanov@nginx.com 
58871546Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_used_size(msg->buf)
58881546Smax.romanov@nginx.com                       < (int) sizeof(nxt_port_msg_get_mmap_t)))
58891546Smax.romanov@nginx.com     {
58901546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: message buffer too small (%d)",
58911546Smax.romanov@nginx.com                   (int) nxt_buf_used_size(msg->buf));
58921546Smax.romanov@nginx.com 
58931546Smax.romanov@nginx.com         return;
58941546Smax.romanov@nginx.com     }
58951546Smax.romanov@nginx.com 
58961546Smax.romanov@nginx.com     get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos;
58971546Smax.romanov@nginx.com 
58981546Smax.romanov@nginx.com     nxt_assert(port->type == NXT_PROCESS_APP);
58991546Smax.romanov@nginx.com 
59001547Smax.romanov@nginx.com     if (nxt_slow_path(port->app == NULL)) {
59011547Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d",
59021547Smax.romanov@nginx.com                   port->pid, port->id);
59031547Smax.romanov@nginx.com 
59041547Smax.romanov@nginx.com         // FIXME
59051547Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
59061547Smax.romanov@nginx.com                               -1, msg->port_msg.stream, 0, NULL);
59071547Smax.romanov@nginx.com 
59081547Smax.romanov@nginx.com         return;
59091547Smax.romanov@nginx.com     }
59101547Smax.romanov@nginx.com 
59111547Smax.romanov@nginx.com     mmaps = &port->app->outgoing;
59121546Smax.romanov@nginx.com     nxt_thread_mutex_lock(&mmaps->mutex);
59131546Smax.romanov@nginx.com 
59141546Smax.romanov@nginx.com     if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) {
59151546Smax.romanov@nginx.com         nxt_thread_mutex_unlock(&mmaps->mutex);
59161546Smax.romanov@nginx.com 
59171546Smax.romanov@nginx.com         nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)",
59181546Smax.romanov@nginx.com                   (int) get_mmap_msg->id);
59191546Smax.romanov@nginx.com 
59201547Smax.romanov@nginx.com         // FIXME
59211547Smax.romanov@nginx.com         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
59221547Smax.romanov@nginx.com                               -1, msg->port_msg.stream, 0, NULL);
59231546Smax.romanov@nginx.com         return;
59241546Smax.romanov@nginx.com     }
59251546Smax.romanov@nginx.com 
59261546Smax.romanov@nginx.com     mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler;
59271546Smax.romanov@nginx.com 
59281546Smax.romanov@nginx.com     fd = mmap_handler->fd;
59291546Smax.romanov@nginx.com 
59301546Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&mmaps->mutex);
59311546Smax.romanov@nginx.com 
59321546Smax.romanov@nginx.com     nxt_debug(task, "get mmap %PI:%d found",
59331546Smax.romanov@nginx.com               msg->port_msg.pid, (int) get_mmap_msg->id);
59341546Smax.romanov@nginx.com 
59351546Smax.romanov@nginx.com     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL);
59361546Smax.romanov@nginx.com }
59371546Smax.romanov@nginx.com 
59381546Smax.romanov@nginx.com 
59391546Smax.romanov@nginx.com static void
59401545Smax.romanov@nginx.com nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
59411545Smax.romanov@nginx.com {
59421545Smax.romanov@nginx.com     nxt_port_t               *port, *reply_port;
59431545Smax.romanov@nginx.com     nxt_runtime_t            *rt;
59441545Smax.romanov@nginx.com     nxt_port_msg_get_port_t  *get_port_msg;
59451545Smax.romanov@nginx.com 
59461545Smax.romanov@nginx.com     rt = task->thread->runtime;
59471545Smax.romanov@nginx.com 
59481545Smax.romanov@nginx.com     reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid,
59491545Smax.romanov@nginx.com                                        msg->port_msg.reply_port);
59501545Smax.romanov@nginx.com     if (nxt_slow_path(reply_port == NULL)) {
59511545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: reply_port %PI:%d not found",
59521545Smax.romanov@nginx.com                   msg->port_msg.pid, msg->port_msg.reply_port);
59531545Smax.romanov@nginx.com 
59541545Smax.romanov@nginx.com         return;
59551545Smax.romanov@nginx.com     }
59561545Smax.romanov@nginx.com 
59571545Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_used_size(msg->buf)
59581545Smax.romanov@nginx.com                       < (int) sizeof(nxt_port_msg_get_port_t)))
59591545Smax.romanov@nginx.com     {
59601545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: message buffer too small (%d)",
59611545Smax.romanov@nginx.com                   (int) nxt_buf_used_size(msg->buf));
59621545Smax.romanov@nginx.com 
59631545Smax.romanov@nginx.com         return;
59641545Smax.romanov@nginx.com     }
59651545Smax.romanov@nginx.com 
59661545Smax.romanov@nginx.com     get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos;
59671545Smax.romanov@nginx.com 
59681545Smax.romanov@nginx.com     port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id);
59691545Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
59701545Smax.romanov@nginx.com         nxt_alert(task, "get_port_handler: port %PI:%d not found",
59711545Smax.romanov@nginx.com                   get_port_msg->pid, get_port_msg->id);
59721545Smax.romanov@nginx.com 
59731545Smax.romanov@nginx.com         return;
59741545Smax.romanov@nginx.com     }
59751545Smax.romanov@nginx.com 
59761545Smax.romanov@nginx.com     nxt_debug(task, "get port %PI:%d found", get_port_msg->pid,
59771545Smax.romanov@nginx.com               get_port_msg->id);
59781545Smax.romanov@nginx.com 
59791545Smax.romanov@nginx.com     (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream);
59801545Smax.romanov@nginx.com }
5981