nxt_router.c (1925:b8a2ac618950) nxt_router.c (1926:6e85d6c0b8bb)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Valentin V. Bartenev
5 * Copyright (C) NGINX, Inc.
6 */
7
8#include <nxt_router.h>
9#include <nxt_conf.h>
10#if (NXT_TLS)
11#include <nxt_cert.h>
12#endif
13#include <nxt_http.h>
14#include <nxt_port_memory_int.h>
15#include <nxt_unit_request.h>
16#include <nxt_unit_response.h>
17#include <nxt_router_request.h>
18#include <nxt_app_queue.h>
19#include <nxt_port_queue.h>
20
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Valentin V. Bartenev
5 * Copyright (C) NGINX, Inc.
6 */
7
8#include <nxt_router.h>
9#include <nxt_conf.h>
10#if (NXT_TLS)
11#include <nxt_cert.h>
12#endif
13#include <nxt_http.h>
14#include <nxt_port_memory_int.h>
15#include <nxt_unit_request.h>
16#include <nxt_unit_response.h>
17#include <nxt_router_request.h>
18#include <nxt_app_queue.h>
19#include <nxt_port_queue.h>
20
21#define NXT_SHARED_PORT_ID 0xFFFFu
22
21typedef struct {
22 nxt_str_t type;
23 uint32_t processes;
24 uint32_t max_processes;
25 uint32_t spare_processes;
26 nxt_msec_t timeout;
27 nxt_msec_t idle_timeout;
28 uint32_t requests;
29 nxt_conf_value_t *limits_value;
30 nxt_conf_value_t *processes_value;
31 nxt_conf_value_t *targets_value;
32} nxt_router_app_conf_t;
33
34
35typedef struct {
36 nxt_str_t pass;
37 nxt_str_t application;
38} nxt_router_listener_conf_t;
39
40
41#if (NXT_TLS)
42
43typedef struct {
44 nxt_str_t name;
45 nxt_socket_conf_t *socket_conf;
46 nxt_router_temp_conf_t *temp_conf;
47 nxt_tls_init_t *tls_init;
48 nxt_bool_t last;
49
50 nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */
51} nxt_router_tlssock_t;
52
53#endif
54
55
56typedef struct {
57 nxt_str_t *name;
58 nxt_socket_conf_t *socket_conf;
59 nxt_router_temp_conf_t *temp_conf;
60 nxt_bool_t last;
61} nxt_socket_rpc_t;
62
63
64typedef struct {
65 nxt_app_t *app;
66 nxt_router_temp_conf_t *temp_conf;
67} nxt_app_rpc_t;
68
69
23typedef struct {
24 nxt_str_t type;
25 uint32_t processes;
26 uint32_t max_processes;
27 uint32_t spare_processes;
28 nxt_msec_t timeout;
29 nxt_msec_t idle_timeout;
30 uint32_t requests;
31 nxt_conf_value_t *limits_value;
32 nxt_conf_value_t *processes_value;
33 nxt_conf_value_t *targets_value;
34} nxt_router_app_conf_t;
35
36
37typedef struct {
38 nxt_str_t pass;
39 nxt_str_t application;
40} nxt_router_listener_conf_t;
41
42
43#if (NXT_TLS)
44
45typedef struct {
46 nxt_str_t name;
47 nxt_socket_conf_t *socket_conf;
48 nxt_router_temp_conf_t *temp_conf;
49 nxt_tls_init_t *tls_init;
50 nxt_bool_t last;
51
52 nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */
53} nxt_router_tlssock_t;
54
55#endif
56
57
58typedef struct {
59 nxt_str_t *name;
60 nxt_socket_conf_t *socket_conf;
61 nxt_router_temp_conf_t *temp_conf;
62 nxt_bool_t last;
63} nxt_socket_rpc_t;
64
65
66typedef struct {
67 nxt_app_t *app;
68 nxt_router_temp_conf_t *temp_conf;
69} nxt_app_rpc_t;
70
71
72typedef struct {
73 nxt_app_joint_t *app_joint;
74 uint32_t generation;
75} nxt_app_joint_rpc_t;
76
77
70static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process,
71 nxt_mp_t *mp);
72static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data);
73static void nxt_router_greet_controller(nxt_task_t *task,
74 nxt_port_t *controller_port);
75
76static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
77
78static void nxt_router_new_port_handler(nxt_task_t *task,
79 nxt_port_recv_msg_t *msg);
80static void nxt_router_conf_data_handler(nxt_task_t *task,
81 nxt_port_recv_msg_t *msg);
78static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process,
79 nxt_mp_t *mp);
80static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data);
81static void nxt_router_greet_controller(nxt_task_t *task,
82 nxt_port_t *controller_port);
83
84static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app);
85
86static void nxt_router_new_port_handler(nxt_task_t *task,
87 nxt_port_recv_msg_t *msg);
88static void nxt_router_conf_data_handler(nxt_task_t *task,
89 nxt_port_recv_msg_t *msg);
90static void nxt_router_app_restart_handler(nxt_task_t *task,
91 nxt_port_recv_msg_t *msg);
82static void nxt_router_remove_pid_handler(nxt_task_t *task,
83 nxt_port_recv_msg_t *msg);
84static void nxt_router_access_log_reopen_handler(nxt_task_t *task,
85 nxt_port_recv_msg_t *msg);
86
87static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
88static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
89static void nxt_router_conf_ready(nxt_task_t *task,
90 nxt_router_temp_conf_t *tmcf);
91static void nxt_router_conf_error(nxt_task_t *task,
92 nxt_router_temp_conf_t *tmcf);
93static void nxt_router_conf_send(nxt_task_t *task,
94 nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
95
96static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
97 nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
98static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
99 nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
100
101static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
102static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
103static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf,
104 nxt_app_t *app);
105static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf,
106 nxt_str_t *name);
107static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf,
108 int i);
109
110static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task,
111 nxt_port_t *port);
112static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task,
113 nxt_port_t *port);
114static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task,
115 nxt_port_t *port, nxt_fd_t fd);
116static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
117 nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
118static void nxt_router_listen_socket_ready(nxt_task_t *task,
119 nxt_port_recv_msg_t *msg, void *data);
120static void nxt_router_listen_socket_error(nxt_task_t *task,
121 nxt_port_recv_msg_t *msg, void *data);
122#if (NXT_TLS)
123static void nxt_router_tls_rpc_handler(nxt_task_t *task,
124 nxt_port_recv_msg_t *msg, void *data);
125static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
126 nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init,
127 nxt_bool_t last);
128#endif
129static void nxt_router_app_rpc_create(nxt_task_t *task,
130 nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
131static void nxt_router_app_prefork_ready(nxt_task_t *task,
132 nxt_port_recv_msg_t *msg, void *data);
133static void nxt_router_app_prefork_error(nxt_task_t *task,
134 nxt_port_recv_msg_t *msg, void *data);
135static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
136 nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
137static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
138 nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
139
140static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
141 nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
142 const nxt_event_interface_t *interface);
143static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
144 nxt_router_engine_conf_t *recf);
145static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
146 nxt_router_engine_conf_t *recf);
147static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
148 nxt_router_engine_conf_t *recf);
149static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
150 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
151 nxt_work_handler_t handler);
152static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
153 nxt_router_engine_conf_t *recf);
154static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
155 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
156
157static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
158 nxt_router_temp_conf_t *tmcf);
159static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
160 nxt_event_engine_t *engine);
161static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
162 nxt_router_temp_conf_t *tmcf);
163
164static void nxt_router_engines_post(nxt_router_t *router,
165 nxt_router_temp_conf_t *tmcf);
166static void nxt_router_engine_post(nxt_event_engine_t *engine,
167 nxt_work_t *jobs);
168
169static void nxt_router_thread_start(void *data);
170static void nxt_router_rt_add_port(nxt_task_t *task, void *obj,
171 void *data);
172static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
173 void *data);
174static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
175 void *data);
176static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
177 void *data);
178static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
179 void *data);
180static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
181 void *data);
182static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
183 void *data);
184static void nxt_router_req_headers_ack_handler(nxt_task_t *task,
185 nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data);
186static void nxt_router_listen_socket_release(nxt_task_t *task,
187 nxt_socket_conf_t *skcf);
188
189static void nxt_router_access_log_writer(nxt_task_t *task,
190 nxt_http_request_t *r, nxt_router_access_log_t *access_log);
191static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
192 struct tm *tm, size_t size, const char *format);
193static void nxt_router_access_log_open(nxt_task_t *task,
194 nxt_router_temp_conf_t *tmcf);
195static void nxt_router_access_log_ready(nxt_task_t *task,
196 nxt_port_recv_msg_t *msg, void *data);
197static void nxt_router_access_log_error(nxt_task_t *task,
198 nxt_port_recv_msg_t *msg, void *data);
199static void nxt_router_access_log_release(nxt_task_t *task,
200 nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
201static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
202 void *data);
203static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
204 nxt_port_recv_msg_t *msg, void *data);
205static void nxt_router_access_log_reopen_error(nxt_task_t *task,
206 nxt_port_recv_msg_t *msg, void *data);
207
208static void nxt_router_app_port_ready(nxt_task_t *task,
209 nxt_port_recv_msg_t *msg, void *data);
210static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task,
211 nxt_port_t *app_port);
212static void nxt_router_app_port_error(nxt_task_t *task,
213 nxt_port_recv_msg_t *msg, void *data);
214
215static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i);
216static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
217
218static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
219 nxt_apr_action_t action);
220static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
221 nxt_request_rpc_data_t *req_rpc_data);
222static void nxt_router_http_request_error(nxt_task_t *task, void *obj,
223 void *data);
224static void nxt_router_http_request_done(nxt_task_t *task, void *obj,
225 void *data);
226
227static void nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj,
228 void *data);
229static void nxt_router_app_prepare_request(nxt_task_t *task,
230 nxt_request_rpc_data_t *req_rpc_data);
231static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
232 nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix);
233
234static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
235static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
236 void *data);
237static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
238 void *data);
239static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
240 void *data);
241static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
242
243static const nxt_http_request_state_t nxt_http_request_send_state;
244static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
245
246static void nxt_router_app_joint_use(nxt_task_t *task,
247 nxt_app_joint_t *app_joint, int i);
248
249static void nxt_router_http_request_release_post(nxt_task_t *task,
250 nxt_http_request_t *r);
251static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
252 void *data);
253static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
254static void nxt_router_get_port_handler(nxt_task_t *task,
255 nxt_port_recv_msg_t *msg);
256static void nxt_router_get_mmap_handler(nxt_task_t *task,
257 nxt_port_recv_msg_t *msg);
258
259extern const nxt_http_request_state_t nxt_http_websocket;
260
261static nxt_router_t *nxt_router;
262
263static const nxt_str_t http_prefix = nxt_string("HTTP_");
264static const nxt_str_t empty_prefix = nxt_string("");
265
266static const nxt_str_t *nxt_app_msg_prefix[] = {
267 &empty_prefix,
268 &empty_prefix,
269 &http_prefix,
270 &http_prefix,
271 &http_prefix,
272 &empty_prefix,
273};
274
275
276static const nxt_port_handlers_t nxt_router_process_port_handlers = {
277 .quit = nxt_signal_quit_handler,
278 .new_port = nxt_router_new_port_handler,
279 .get_port = nxt_router_get_port_handler,
280 .change_file = nxt_port_change_log_file_handler,
281 .mmap = nxt_port_mmap_handler,
282 .get_mmap = nxt_router_get_mmap_handler,
283 .data = nxt_router_conf_data_handler,
92static void nxt_router_remove_pid_handler(nxt_task_t *task,
93 nxt_port_recv_msg_t *msg);
94static void nxt_router_access_log_reopen_handler(nxt_task_t *task,
95 nxt_port_recv_msg_t *msg);
96
97static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task);
98static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data);
99static void nxt_router_conf_ready(nxt_task_t *task,
100 nxt_router_temp_conf_t *tmcf);
101static void nxt_router_conf_error(nxt_task_t *task,
102 nxt_router_temp_conf_t *tmcf);
103static void nxt_router_conf_send(nxt_task_t *task,
104 nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type);
105
106static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
107 nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
108static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
109 nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
110
111static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
112static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
113static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf,
114 nxt_app_t *app);
115static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf,
116 nxt_str_t *name);
117static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf,
118 int i);
119
120static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task,
121 nxt_port_t *port);
122static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task,
123 nxt_port_t *port);
124static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task,
125 nxt_port_t *port, nxt_fd_t fd);
126static void nxt_router_listen_socket_rpc_create(nxt_task_t *task,
127 nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf);
128static void nxt_router_listen_socket_ready(nxt_task_t *task,
129 nxt_port_recv_msg_t *msg, void *data);
130static void nxt_router_listen_socket_error(nxt_task_t *task,
131 nxt_port_recv_msg_t *msg, void *data);
132#if (NXT_TLS)
133static void nxt_router_tls_rpc_handler(nxt_task_t *task,
134 nxt_port_recv_msg_t *msg, void *data);
135static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
136 nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init,
137 nxt_bool_t last);
138#endif
139static void nxt_router_app_rpc_create(nxt_task_t *task,
140 nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
141static void nxt_router_app_prefork_ready(nxt_task_t *task,
142 nxt_port_recv_msg_t *msg, void *data);
143static void nxt_router_app_prefork_error(nxt_task_t *task,
144 nxt_port_recv_msg_t *msg, void *data);
145static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task,
146 nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
147static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
148 nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa);
149
150static nxt_int_t nxt_router_engines_create(nxt_task_t *task,
151 nxt_router_t *router, nxt_router_temp_conf_t *tmcf,
152 const nxt_event_interface_t *interface);
153static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
154 nxt_router_engine_conf_t *recf);
155static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
156 nxt_router_engine_conf_t *recf);
157static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
158 nxt_router_engine_conf_t *recf);
159static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
160 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
161 nxt_work_handler_t handler);
162static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
163 nxt_router_engine_conf_t *recf);
164static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
165 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets);
166
167static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
168 nxt_router_temp_conf_t *tmcf);
169static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
170 nxt_event_engine_t *engine);
171static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
172 nxt_router_temp_conf_t *tmcf);
173
174static void nxt_router_engines_post(nxt_router_t *router,
175 nxt_router_temp_conf_t *tmcf);
176static void nxt_router_engine_post(nxt_event_engine_t *engine,
177 nxt_work_t *jobs);
178
179static void nxt_router_thread_start(void *data);
180static void nxt_router_rt_add_port(nxt_task_t *task, void *obj,
181 void *data);
182static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj,
183 void *data);
184static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj,
185 void *data);
186static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj,
187 void *data);
188static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj,
189 void *data);
190static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj,
191 void *data);
192static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj,
193 void *data);
194static void nxt_router_req_headers_ack_handler(nxt_task_t *task,
195 nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data);
196static void nxt_router_listen_socket_release(nxt_task_t *task,
197 nxt_socket_conf_t *skcf);
198
199static void nxt_router_access_log_writer(nxt_task_t *task,
200 nxt_http_request_t *r, nxt_router_access_log_t *access_log);
201static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now,
202 struct tm *tm, size_t size, const char *format);
203static void nxt_router_access_log_open(nxt_task_t *task,
204 nxt_router_temp_conf_t *tmcf);
205static void nxt_router_access_log_ready(nxt_task_t *task,
206 nxt_port_recv_msg_t *msg, void *data);
207static void nxt_router_access_log_error(nxt_task_t *task,
208 nxt_port_recv_msg_t *msg, void *data);
209static void nxt_router_access_log_release(nxt_task_t *task,
210 nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log);
211static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
212 void *data);
213static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
214 nxt_port_recv_msg_t *msg, void *data);
215static void nxt_router_access_log_reopen_error(nxt_task_t *task,
216 nxt_port_recv_msg_t *msg, void *data);
217
218static void nxt_router_app_port_ready(nxt_task_t *task,
219 nxt_port_recv_msg_t *msg, void *data);
220static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task,
221 nxt_port_t *app_port);
222static void nxt_router_app_port_error(nxt_task_t *task,
223 nxt_port_recv_msg_t *msg, void *data);
224
225static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i);
226static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
227
228static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
229 nxt_apr_action_t action);
230static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
231 nxt_request_rpc_data_t *req_rpc_data);
232static void nxt_router_http_request_error(nxt_task_t *task, void *obj,
233 void *data);
234static void nxt_router_http_request_done(nxt_task_t *task, void *obj,
235 void *data);
236
237static void nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj,
238 void *data);
239static void nxt_router_app_prepare_request(nxt_task_t *task,
240 nxt_request_rpc_data_t *req_rpc_data);
241static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
242 nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix);
243
244static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
245static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
246 void *data);
247static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj,
248 void *data);
249static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj,
250 void *data);
251static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data);
252
253static const nxt_http_request_state_t nxt_http_request_send_state;
254static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
255
256static void nxt_router_app_joint_use(nxt_task_t *task,
257 nxt_app_joint_t *app_joint, int i);
258
259static void nxt_router_http_request_release_post(nxt_task_t *task,
260 nxt_http_request_t *r);
261static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
262 void *data);
263static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
264static void nxt_router_get_port_handler(nxt_task_t *task,
265 nxt_port_recv_msg_t *msg);
266static void nxt_router_get_mmap_handler(nxt_task_t *task,
267 nxt_port_recv_msg_t *msg);
268
269extern const nxt_http_request_state_t nxt_http_websocket;
270
271static nxt_router_t *nxt_router;
272
273static const nxt_str_t http_prefix = nxt_string("HTTP_");
274static const nxt_str_t empty_prefix = nxt_string("");
275
276static const nxt_str_t *nxt_app_msg_prefix[] = {
277 &empty_prefix,
278 &empty_prefix,
279 &http_prefix,
280 &http_prefix,
281 &http_prefix,
282 &empty_prefix,
283};
284
285
286static const nxt_port_handlers_t nxt_router_process_port_handlers = {
287 .quit = nxt_signal_quit_handler,
288 .new_port = nxt_router_new_port_handler,
289 .get_port = nxt_router_get_port_handler,
290 .change_file = nxt_port_change_log_file_handler,
291 .mmap = nxt_port_mmap_handler,
292 .get_mmap = nxt_router_get_mmap_handler,
293 .data = nxt_router_conf_data_handler,
294 .app_restart = nxt_router_app_restart_handler,
284 .remove_pid = nxt_router_remove_pid_handler,
285 .access_log = nxt_router_access_log_reopen_handler,
286 .rpc_ready = nxt_port_rpc_handler,
287 .rpc_error = nxt_port_rpc_handler,
288 .oosm = nxt_router_oosm_handler,
289};
290
291
292const nxt_process_init_t nxt_router_process = {
293 .name = "router",
294 .type = NXT_PROCESS_ROUTER,
295 .prefork = nxt_router_prefork,
296 .restart = 1,
297 .setup = nxt_process_core_setup,
298 .start = nxt_router_start,
299 .port_handlers = &nxt_router_process_port_handlers,
300 .signals = nxt_process_signals,
301};
302
303
304/* Queues of nxt_socket_conf_t */
305nxt_queue_t creating_sockets;
306nxt_queue_t pending_sockets;
307nxt_queue_t updating_sockets;
308nxt_queue_t keeping_sockets;
309nxt_queue_t deleting_sockets;
310
311
312static nxt_int_t
313nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
314{
315 nxt_runtime_stop_app_processes(task, task->thread->runtime);
316
317 return NXT_OK;
318}
319
320
321static nxt_int_t
322nxt_router_start(nxt_task_t *task, nxt_process_data_t *data)
323{
324 nxt_int_t ret;
325 nxt_port_t *controller_port;
326 nxt_router_t *router;
327 nxt_runtime_t *rt;
328
329 rt = task->thread->runtime;
330
331 nxt_log(task, NXT_LOG_INFO, "router started");
332
333#if (NXT_TLS)
334 rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
335 if (nxt_slow_path(rt->tls == NULL)) {
336 return NXT_ERROR;
337 }
338
339 ret = rt->tls->library_init(task);
340 if (nxt_slow_path(ret != NXT_OK)) {
341 return ret;
342 }
343#endif
344
345 ret = nxt_http_init(task);
346 if (nxt_slow_path(ret != NXT_OK)) {
347 return ret;
348 }
349
350 router = nxt_zalloc(sizeof(nxt_router_t));
351 if (nxt_slow_path(router == NULL)) {
352 return NXT_ERROR;
353 }
354
355 nxt_queue_init(&router->engines);
356 nxt_queue_init(&router->sockets);
357 nxt_queue_init(&router->apps);
358
359 nxt_router = router;
360
361 controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
362 if (controller_port != NULL) {
363 nxt_router_greet_controller(task, controller_port);
364 }
365
366 return NXT_OK;
367}
368
369
370static void
371nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
372{
373 nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
374 -1, 0, 0, NULL);
375}
376
377
378static void
379nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
380 void *data)
381{
295 .remove_pid = nxt_router_remove_pid_handler,
296 .access_log = nxt_router_access_log_reopen_handler,
297 .rpc_ready = nxt_port_rpc_handler,
298 .rpc_error = nxt_port_rpc_handler,
299 .oosm = nxt_router_oosm_handler,
300};
301
302
303const nxt_process_init_t nxt_router_process = {
304 .name = "router",
305 .type = NXT_PROCESS_ROUTER,
306 .prefork = nxt_router_prefork,
307 .restart = 1,
308 .setup = nxt_process_core_setup,
309 .start = nxt_router_start,
310 .port_handlers = &nxt_router_process_port_handlers,
311 .signals = nxt_process_signals,
312};
313
314
315/* Queues of nxt_socket_conf_t */
316nxt_queue_t creating_sockets;
317nxt_queue_t pending_sockets;
318nxt_queue_t updating_sockets;
319nxt_queue_t keeping_sockets;
320nxt_queue_t deleting_sockets;
321
322
323static nxt_int_t
324nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
325{
326 nxt_runtime_stop_app_processes(task, task->thread->runtime);
327
328 return NXT_OK;
329}
330
331
332static nxt_int_t
333nxt_router_start(nxt_task_t *task, nxt_process_data_t *data)
334{
335 nxt_int_t ret;
336 nxt_port_t *controller_port;
337 nxt_router_t *router;
338 nxt_runtime_t *rt;
339
340 rt = task->thread->runtime;
341
342 nxt_log(task, NXT_LOG_INFO, "router started");
343
344#if (NXT_TLS)
345 rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL");
346 if (nxt_slow_path(rt->tls == NULL)) {
347 return NXT_ERROR;
348 }
349
350 ret = rt->tls->library_init(task);
351 if (nxt_slow_path(ret != NXT_OK)) {
352 return ret;
353 }
354#endif
355
356 ret = nxt_http_init(task);
357 if (nxt_slow_path(ret != NXT_OK)) {
358 return ret;
359 }
360
361 router = nxt_zalloc(sizeof(nxt_router_t));
362 if (nxt_slow_path(router == NULL)) {
363 return NXT_ERROR;
364 }
365
366 nxt_queue_init(&router->engines);
367 nxt_queue_init(&router->sockets);
368 nxt_queue_init(&router->apps);
369
370 nxt_router = router;
371
372 controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
373 if (controller_port != NULL) {
374 nxt_router_greet_controller(task, controller_port);
375 }
376
377 return NXT_OK;
378}
379
380
381static void
382nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port)
383{
384 nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY,
385 -1, 0, 0, NULL);
386}
387
388
389static void
390nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
391 void *data)
392{
382 size_t size;
383 uint32_t stream;
384 nxt_mp_t *mp;
385 nxt_int_t ret;
386 nxt_app_t *app;
387 nxt_buf_t *b;
388 nxt_port_t *main_port;
389 nxt_runtime_t *rt;
393 size_t size;
394 uint32_t stream;
395 nxt_mp_t *mp;
396 nxt_int_t ret;
397 nxt_app_t *app;
398 nxt_buf_t *b;
399 nxt_port_t *main_port;
400 nxt_runtime_t *rt;
401 nxt_app_joint_rpc_t *app_joint_rpc;
390
391 app = data;
392
393 rt = task->thread->runtime;
394 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
395
396 nxt_debug(task, "app '%V' %p start process", &app->name, app);
397
398 size = app->name.length + 1 + app->conf.length;
399
400 b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
401
402 if (nxt_slow_path(b == NULL)) {
403 goto failed;
404 }
405
406 nxt_buf_cpystr(b, &app->name);
407 *b->mem.free++ = '\0';
408 nxt_buf_cpystr(b, &app->conf);
409
402
403 app = data;
404
405 rt = task->thread->runtime;
406 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
407
408 nxt_debug(task, "app '%V' %p start process", &app->name, app);
409
410 size = app->name.length + 1 + app->conf.length;
411
412 b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size);
413
414 if (nxt_slow_path(b == NULL)) {
415 goto failed;
416 }
417
418 nxt_buf_cpystr(b, &app->name);
419 *b->mem.free++ = '\0';
420 nxt_buf_cpystr(b, &app->conf);
421
410 nxt_router_app_joint_use(task, app->joint, 1);
411
412 stream = nxt_port_rpc_register_handler(task, port,
413 nxt_router_app_port_ready,
414 nxt_router_app_port_error,
415 -1, app->joint);
416
417 if (nxt_slow_path(stream == 0)) {
418 nxt_router_app_joint_use(task, app->joint, -1);
419
422 app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port,
423 nxt_router_app_port_ready,
424 nxt_router_app_port_error,
425 sizeof(nxt_app_joint_rpc_t));
426 if (nxt_slow_path(app_joint_rpc == NULL)) {
420 goto failed;
421 }
422
427 goto failed;
428 }
429
430 stream = nxt_port_rpc_ex_stream(app_joint_rpc);
431
423 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
424 -1, stream, port->id, b);
432 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
433 -1, stream, port->id, b);
425
426 if (nxt_slow_path(ret != NXT_OK)) {
427 nxt_port_rpc_cancel(task, port, stream);
428
434 if (nxt_slow_path(ret != NXT_OK)) {
435 nxt_port_rpc_cancel(task, port, stream);
436
429 nxt_router_app_joint_use(task, app->joint, -1);
430
431 goto failed;
432 }
433
437 goto failed;
438 }
439
440 app_joint_rpc->app_joint = app->joint;
441 app_joint_rpc->generation = app->generation;
442
443 nxt_router_app_joint_use(task, app->joint, 1);
444
434 nxt_router_app_use(task, app, -1);
435
436 return;
437
438failed:
439
440 if (b != NULL) {
441 mp = b->data;
442 nxt_mp_free(mp, b);
443 nxt_mp_release(mp);
444 }
445
446 nxt_thread_mutex_lock(&app->mutex);
447
448 app->pending_processes--;
449
450 nxt_thread_mutex_unlock(&app->mutex);
451
452 nxt_router_app_use(task, app, -1);
453}
454
455
456static void
457nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
458{
459 app_joint->use_count += i;
460
461 if (app_joint->use_count == 0) {
462 nxt_assert(app_joint->app == NULL);
463
464 nxt_free(app_joint);
465 }
466}
467
468
469static nxt_int_t
470nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
471{
472 nxt_int_t res;
473 nxt_port_t *router_port;
474 nxt_runtime_t *rt;
475
476 nxt_debug(task, "app '%V' start process", &app->name);
477
478 rt = task->thread->runtime;
479 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
480
481 nxt_router_app_use(task, app, 1);
482
483 res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
484 app);
485
486 if (res == NXT_OK) {
487 return res;
488 }
489
490 nxt_thread_mutex_lock(&app->mutex);
491
492 app->pending_processes--;
493
494 nxt_thread_mutex_unlock(&app->mutex);
495
496 nxt_router_app_use(task, app, -1);
497
498 return NXT_ERROR;
499}
500
501
502nxt_inline nxt_bool_t
503nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
504{
505 nxt_buf_t *b, *next;
506 nxt_bool_t cancelled;
445 nxt_router_app_use(task, app, -1);
446
447 return;
448
449failed:
450
451 if (b != NULL) {
452 mp = b->data;
453 nxt_mp_free(mp, b);
454 nxt_mp_release(mp);
455 }
456
457 nxt_thread_mutex_lock(&app->mutex);
458
459 app->pending_processes--;
460
461 nxt_thread_mutex_unlock(&app->mutex);
462
463 nxt_router_app_use(task, app, -1);
464}
465
466
467static void
468nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i)
469{
470 app_joint->use_count += i;
471
472 if (app_joint->use_count == 0) {
473 nxt_assert(app_joint->app == NULL);
474
475 nxt_free(app_joint);
476 }
477}
478
479
480static nxt_int_t
481nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app)
482{
483 nxt_int_t res;
484 nxt_port_t *router_port;
485 nxt_runtime_t *rt;
486
487 nxt_debug(task, "app '%V' start process", &app->name);
488
489 rt = task->thread->runtime;
490 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
491
492 nxt_router_app_use(task, app, 1);
493
494 res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler,
495 app);
496
497 if (res == NXT_OK) {
498 return res;
499 }
500
501 nxt_thread_mutex_lock(&app->mutex);
502
503 app->pending_processes--;
504
505 nxt_thread_mutex_unlock(&app->mutex);
506
507 nxt_router_app_use(task, app, -1);
508
509 return NXT_ERROR;
510}
511
512
513nxt_inline nxt_bool_t
514nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
515{
516 nxt_buf_t *b, *next;
517 nxt_bool_t cancelled;
518 nxt_port_t *app_port;
507 nxt_msg_info_t *msg_info;
508
509 msg_info = &req_rpc_data->msg_info;
510
511 if (msg_info->buf == NULL) {
512 return 0;
513 }
514
519 nxt_msg_info_t *msg_info;
520
521 msg_info = &req_rpc_data->msg_info;
522
523 if (msg_info->buf == NULL) {
524 return 0;
525 }
526
515 cancelled = nxt_app_queue_cancel(req_rpc_data->app->shared_port->queue,
516 msg_info->tracking_cookie,
517 req_rpc_data->stream);
527 app_port = req_rpc_data->app_port;
518
528
519 if (cancelled) {
520 nxt_debug(task, "stream #%uD: cancelled by router",
521 req_rpc_data->stream);
529 if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) {
530 cancelled = nxt_app_queue_cancel(app_port->queue,
531 msg_info->tracking_cookie,
532 req_rpc_data->stream);
533
534 if (cancelled) {
535 nxt_debug(task, "stream #%uD: cancelled by router",
536 req_rpc_data->stream);
537 }
538
539 } else {
540 cancelled = 0;
522 }
523
524 for (b = msg_info->buf; b != NULL; b = next) {
525 next = b->next;
526 b->next = NULL;
527
528 if (b->is_port_mmap_sent) {
529 b->is_port_mmap_sent = cancelled == 0;
530 }
531
532 b->completion_handler(task, b, b->parent);
533 }
534
535 msg_info->buf = NULL;
536
537 return cancelled;
538}
539
540
541nxt_inline nxt_bool_t
542nxt_queue_chk_remove(nxt_queue_link_t *lnk)
543{
544 if (lnk->next != NULL) {
545 nxt_queue_remove(lnk);
546
547 lnk->next = NULL;
548
549 return 1;
550 }
551
552 return 0;
553}
554
555
556nxt_inline void
557nxt_request_rpc_data_unlink(nxt_task_t *task,
558 nxt_request_rpc_data_t *req_rpc_data)
559{
560 nxt_app_t *app;
561 nxt_bool_t unlinked;
562 nxt_http_request_t *r;
563
564 nxt_router_msg_cancel(task, req_rpc_data);
565
566 if (req_rpc_data->app_port != NULL) {
567 nxt_router_app_port_release(task, req_rpc_data->app_port,
568 req_rpc_data->apr_action);
569
570 req_rpc_data->app_port = NULL;
571 }
572
573 app = req_rpc_data->app;
574 r = req_rpc_data->request;
575
576 if (r != NULL) {
577 r->timer_data = NULL;
578
579 nxt_router_http_request_release_post(task, r);
580
581 r->req_rpc_data = NULL;
582 req_rpc_data->request = NULL;
583
584 if (app != NULL) {
585 unlinked = 0;
586
587 nxt_thread_mutex_lock(&app->mutex);
588
589 if (r->app_link.next != NULL) {
590 nxt_queue_remove(&r->app_link);
591 r->app_link.next = NULL;
592
593 unlinked = 1;
594 }
595
596 nxt_thread_mutex_unlock(&app->mutex);
597
598 if (unlinked) {
599 nxt_mp_release(r->mem_pool);
600 }
601 }
602 }
603
604 if (app != NULL) {
605 nxt_router_app_use(task, app, -1);
606
607 req_rpc_data->app = NULL;
608 }
609
610 if (req_rpc_data->msg_info.body_fd != -1) {
611 nxt_fd_close(req_rpc_data->msg_info.body_fd);
612
613 req_rpc_data->msg_info.body_fd = -1;
614 }
615
616 if (req_rpc_data->rpc_cancel) {
617 req_rpc_data->rpc_cancel = 0;
618
619 nxt_port_rpc_cancel(task, task->thread->engine->port,
620 req_rpc_data->stream);
621 }
622}
623
624
625static void
626nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
627{
628 nxt_int_t res;
629 nxt_app_t *app;
630 nxt_port_t *port, *main_app_port;
631 nxt_runtime_t *rt;
632
633 nxt_port_new_port_handler(task, msg);
634
635 port = msg->u.new_port;
636
637 if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) {
638 nxt_router_greet_controller(task, msg->u.new_port);
639 }
640
641 if (port == NULL || port->type != NXT_PROCESS_APP) {
642
643 if (msg->port_msg.stream == 0) {
644 return;
645 }
646
647 msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
648
649 } else {
650 if (msg->fd[1] != -1) {
651 res = nxt_router_port_queue_map(task, port, msg->fd[1]);
652 if (nxt_slow_path(res != NXT_OK)) {
653 return;
654 }
655
656 nxt_fd_close(msg->fd[1]);
657 msg->fd[1] = -1;
658 }
659 }
660
661 if (msg->port_msg.stream != 0) {
662 nxt_port_rpc_handler(task, msg);
663 return;
664 }
665
666 /*
667 * Port with "id == 0" is application 'main' port and it always
668 * should come with non-zero stream.
669 */
670 nxt_assert(port->id != 0);
671
672 /* Find 'main' app port and get app reference. */
673 rt = task->thread->runtime;
674
675 /*
676 * It is safe to access 'runtime->ports' hash because 'NEW_PORT'
677 * sent to main port (with id == 0) and processed in main thread.
678 */
679 main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0);
680 nxt_assert(main_app_port != NULL);
681
682 app = main_app_port->app;
683
684 if (nxt_fast_path(app != NULL)) {
685 nxt_thread_mutex_lock(&app->mutex);
686
687 /* TODO here should be find-and-add code because there can be
688 port waiters in port_hash */
689 nxt_port_hash_add(&app->port_hash, port);
690 app->port_hash_count++;
691
692 nxt_thread_mutex_unlock(&app->mutex);
693
694 port->app = app;
695 }
696
697 port->main_app_port = main_app_port;
698
699 nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL);
700}
701
702
703static void
704nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
705{
706 void *p;
707 size_t size;
708 nxt_int_t ret;
709 nxt_port_t *port;
710 nxt_router_temp_conf_t *tmcf;
711
712 port = nxt_runtime_port_find(task->thread->runtime,
713 msg->port_msg.pid,
714 msg->port_msg.reply_port);
715 if (nxt_slow_path(port == NULL)) {
716 nxt_alert(task, "conf_data_handler: reply port not found");
717 return;
718 }
719
720 p = MAP_FAILED;
721
722 /*
723 * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be
724 * initialized in 'cleanup' section.
725 */
726 size = 0;
727
728 tmcf = nxt_router_temp_conf(task);
729 if (nxt_slow_path(tmcf == NULL)) {
730 goto fail;
731 }
732
733 if (nxt_slow_path(msg->fd[0] == -1)) {
734 nxt_alert(task, "conf_data_handler: invalid shm fd");
735 goto fail;
736 }
737
738 if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
739 nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)",
740 (int) nxt_buf_mem_used_size(&msg->buf->mem));
741 goto fail;
742 }
743
744 nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
745
746 p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
747
748 nxt_fd_close(msg->fd[0]);
749 msg->fd[0] = -1;
750
751 if (nxt_slow_path(p == MAP_FAILED)) {
752 goto fail;
753 }
754
755 nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p);
756
757 tmcf->router_conf->router = nxt_router;
758 tmcf->stream = msg->port_msg.stream;
759 tmcf->port = port;
760
761 nxt_port_use(task, tmcf->port, 1);
762
763 ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size));
764
765 if (nxt_fast_path(ret == NXT_OK)) {
766 nxt_router_conf_apply(task, tmcf, NULL);
767
768 } else {
769 nxt_router_conf_error(task, tmcf);
770 }
771
772 goto cleanup;
773
774fail:
775
776 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
777 msg->port_msg.stream, 0, NULL);
778
779 if (tmcf != NULL) {
780 nxt_mp_release(tmcf->mem_pool);
781 }
782
783cleanup:
784
785 if (p != MAP_FAILED) {
786 nxt_mem_munmap(p, size);
787 }
788
789 if (msg->fd[0] != -1) {
790 nxt_fd_close(msg->fd[0]);
791 msg->fd[0] = -1;
792 }
793}
794
795
796static void
541 }
542
543 for (b = msg_info->buf; b != NULL; b = next) {
544 next = b->next;
545 b->next = NULL;
546
547 if (b->is_port_mmap_sent) {
548 b->is_port_mmap_sent = cancelled == 0;
549 }
550
551 b->completion_handler(task, b, b->parent);
552 }
553
554 msg_info->buf = NULL;
555
556 return cancelled;
557}
558
559
560nxt_inline nxt_bool_t
561nxt_queue_chk_remove(nxt_queue_link_t *lnk)
562{
563 if (lnk->next != NULL) {
564 nxt_queue_remove(lnk);
565
566 lnk->next = NULL;
567
568 return 1;
569 }
570
571 return 0;
572}
573
574
575nxt_inline void
576nxt_request_rpc_data_unlink(nxt_task_t *task,
577 nxt_request_rpc_data_t *req_rpc_data)
578{
579 nxt_app_t *app;
580 nxt_bool_t unlinked;
581 nxt_http_request_t *r;
582
583 nxt_router_msg_cancel(task, req_rpc_data);
584
585 if (req_rpc_data->app_port != NULL) {
586 nxt_router_app_port_release(task, req_rpc_data->app_port,
587 req_rpc_data->apr_action);
588
589 req_rpc_data->app_port = NULL;
590 }
591
592 app = req_rpc_data->app;
593 r = req_rpc_data->request;
594
595 if (r != NULL) {
596 r->timer_data = NULL;
597
598 nxt_router_http_request_release_post(task, r);
599
600 r->req_rpc_data = NULL;
601 req_rpc_data->request = NULL;
602
603 if (app != NULL) {
604 unlinked = 0;
605
606 nxt_thread_mutex_lock(&app->mutex);
607
608 if (r->app_link.next != NULL) {
609 nxt_queue_remove(&r->app_link);
610 r->app_link.next = NULL;
611
612 unlinked = 1;
613 }
614
615 nxt_thread_mutex_unlock(&app->mutex);
616
617 if (unlinked) {
618 nxt_mp_release(r->mem_pool);
619 }
620 }
621 }
622
623 if (app != NULL) {
624 nxt_router_app_use(task, app, -1);
625
626 req_rpc_data->app = NULL;
627 }
628
629 if (req_rpc_data->msg_info.body_fd != -1) {
630 nxt_fd_close(req_rpc_data->msg_info.body_fd);
631
632 req_rpc_data->msg_info.body_fd = -1;
633 }
634
635 if (req_rpc_data->rpc_cancel) {
636 req_rpc_data->rpc_cancel = 0;
637
638 nxt_port_rpc_cancel(task, task->thread->engine->port,
639 req_rpc_data->stream);
640 }
641}
642
643
644static void
645nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
646{
647 nxt_int_t res;
648 nxt_app_t *app;
649 nxt_port_t *port, *main_app_port;
650 nxt_runtime_t *rt;
651
652 nxt_port_new_port_handler(task, msg);
653
654 port = msg->u.new_port;
655
656 if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) {
657 nxt_router_greet_controller(task, msg->u.new_port);
658 }
659
660 if (port == NULL || port->type != NXT_PROCESS_APP) {
661
662 if (msg->port_msg.stream == 0) {
663 return;
664 }
665
666 msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
667
668 } else {
669 if (msg->fd[1] != -1) {
670 res = nxt_router_port_queue_map(task, port, msg->fd[1]);
671 if (nxt_slow_path(res != NXT_OK)) {
672 return;
673 }
674
675 nxt_fd_close(msg->fd[1]);
676 msg->fd[1] = -1;
677 }
678 }
679
680 if (msg->port_msg.stream != 0) {
681 nxt_port_rpc_handler(task, msg);
682 return;
683 }
684
685 /*
686 * Port with "id == 0" is application 'main' port and it always
687 * should come with non-zero stream.
688 */
689 nxt_assert(port->id != 0);
690
691 /* Find 'main' app port and get app reference. */
692 rt = task->thread->runtime;
693
694 /*
695 * It is safe to access 'runtime->ports' hash because 'NEW_PORT'
696 * sent to main port (with id == 0) and processed in main thread.
697 */
698 main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0);
699 nxt_assert(main_app_port != NULL);
700
701 app = main_app_port->app;
702
703 if (nxt_fast_path(app != NULL)) {
704 nxt_thread_mutex_lock(&app->mutex);
705
706 /* TODO here should be find-and-add code because there can be
707 port waiters in port_hash */
708 nxt_port_hash_add(&app->port_hash, port);
709 app->port_hash_count++;
710
711 nxt_thread_mutex_unlock(&app->mutex);
712
713 port->app = app;
714 }
715
716 port->main_app_port = main_app_port;
717
718 nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL);
719}
720
721
722static void
723nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
724{
725 void *p;
726 size_t size;
727 nxt_int_t ret;
728 nxt_port_t *port;
729 nxt_router_temp_conf_t *tmcf;
730
731 port = nxt_runtime_port_find(task->thread->runtime,
732 msg->port_msg.pid,
733 msg->port_msg.reply_port);
734 if (nxt_slow_path(port == NULL)) {
735 nxt_alert(task, "conf_data_handler: reply port not found");
736 return;
737 }
738
739 p = MAP_FAILED;
740
741 /*
742 * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be
743 * initialized in 'cleanup' section.
744 */
745 size = 0;
746
747 tmcf = nxt_router_temp_conf(task);
748 if (nxt_slow_path(tmcf == NULL)) {
749 goto fail;
750 }
751
752 if (nxt_slow_path(msg->fd[0] == -1)) {
753 nxt_alert(task, "conf_data_handler: invalid shm fd");
754 goto fail;
755 }
756
757 if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
758 nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)",
759 (int) nxt_buf_mem_used_size(&msg->buf->mem));
760 goto fail;
761 }
762
763 nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
764
765 p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
766
767 nxt_fd_close(msg->fd[0]);
768 msg->fd[0] = -1;
769
770 if (nxt_slow_path(p == MAP_FAILED)) {
771 goto fail;
772 }
773
774 nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p);
775
776 tmcf->router_conf->router = nxt_router;
777 tmcf->stream = msg->port_msg.stream;
778 tmcf->port = port;
779
780 nxt_port_use(task, tmcf->port, 1);
781
782 ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size));
783
784 if (nxt_fast_path(ret == NXT_OK)) {
785 nxt_router_conf_apply(task, tmcf, NULL);
786
787 } else {
788 nxt_router_conf_error(task, tmcf);
789 }
790
791 goto cleanup;
792
793fail:
794
795 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
796 msg->port_msg.stream, 0, NULL);
797
798 if (tmcf != NULL) {
799 nxt_mp_release(tmcf->mem_pool);
800 }
801
802cleanup:
803
804 if (p != MAP_FAILED) {
805 nxt_mem_munmap(p, size);
806 }
807
808 if (msg->fd[0] != -1) {
809 nxt_fd_close(msg->fd[0]);
810 msg->fd[0] = -1;
811 }
812}
813
814
815static void
816nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
817{
818 nxt_app_t *app;
819 nxt_int_t ret;
820 nxt_str_t app_name;
821 nxt_port_t *port, *reply_port, *shared_port, *old_shared_port;
822 nxt_port_msg_type_t reply;
823
824 reply_port = nxt_runtime_port_find(task->thread->runtime,
825 msg->port_msg.pid,
826 msg->port_msg.reply_port);
827 if (nxt_slow_path(reply_port == NULL)) {
828 nxt_alert(task, "app_restart_handler: reply port not found");
829 return;
830 }
831
832 app_name.length = nxt_buf_mem_used_size(&msg->buf->mem);
833 app_name.start = msg->buf->mem.pos;
834
835 nxt_debug(task, "app_restart_handler: %V", &app_name);
836
837 app = nxt_router_app_find(&nxt_router->apps, &app_name);
838
839 if (nxt_fast_path(app != NULL)) {
840 shared_port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
841 NXT_PROCESS_APP);
842 if (nxt_slow_path(shared_port == NULL)) {
843 goto fail;
844 }
845
846 ret = nxt_port_socket_init(task, shared_port, 0);
847 if (nxt_slow_path(ret != NXT_OK)) {
848 nxt_port_use(task, shared_port, -1);
849 goto fail;
850 }
851
852 ret = nxt_router_app_queue_init(task, shared_port);
853 if (nxt_slow_path(ret != NXT_OK)) {
854 nxt_port_write_close(shared_port);
855 nxt_port_read_close(shared_port);
856 nxt_port_use(task, shared_port, -1);
857 goto fail;
858 }
859
860 nxt_port_write_enable(task, shared_port);
861
862 nxt_thread_mutex_lock(&app->mutex);
863
864 nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
865
866 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1,
867 0, 0, NULL);
868
869 } nxt_queue_loop;
870
871 app->generation++;
872
873 shared_port->app = app;
874
875 old_shared_port = app->shared_port;
876 old_shared_port->app = NULL;
877
878 app->shared_port = shared_port;
879
880 nxt_thread_mutex_unlock(&app->mutex);
881
882 nxt_port_close(task, old_shared_port);
883 nxt_port_use(task, old_shared_port, -1);
884
885 reply = NXT_PORT_MSG_RPC_READY_LAST;
886
887 } else {
888
889fail:
890
891 reply = NXT_PORT_MSG_RPC_ERROR;
892 }
893
894 nxt_port_socket_write(task, reply_port, reply, -1, msg->port_msg.stream,
895 0, NULL);
896}
897
898
899static void
797nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
798 void *data)
799{
800 union {
801 nxt_pid_t removed_pid;
802 void *data;
803 } u;
804
805 u.data = data;
806
807 nxt_port_rpc_remove_peer(task, port, u.removed_pid);
808}
809
810
811static void
812nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
813{
814 nxt_event_engine_t *engine;
815
816 nxt_port_remove_pid_handler(task, msg);
817
818 nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
819 {
820 if (nxt_fast_path(engine->port != NULL)) {
821 nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
822 msg->u.data);
823 }
824 }
825 nxt_queue_loop;
826
827 if (msg->port_msg.stream == 0) {
828 return;
829 }
830
831 msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
832
833 nxt_port_rpc_handler(task, msg);
834}
835
836
837static nxt_router_temp_conf_t *
838nxt_router_temp_conf(nxt_task_t *task)
839{
840 nxt_mp_t *mp, *tmp;
841 nxt_router_conf_t *rtcf;
842 nxt_router_temp_conf_t *tmcf;
843
844 mp = nxt_mp_create(1024, 128, 256, 32);
845 if (nxt_slow_path(mp == NULL)) {
846 return NULL;
847 }
848
849 rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
850 if (nxt_slow_path(rtcf == NULL)) {
851 goto fail;
852 }
853
854 rtcf->mem_pool = mp;
855
856 tmp = nxt_mp_create(1024, 128, 256, 32);
857 if (nxt_slow_path(tmp == NULL)) {
858 goto fail;
859 }
860
861 tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
862 if (nxt_slow_path(tmcf == NULL)) {
863 goto temp_fail;
864 }
865
866 tmcf->mem_pool = tmp;
867 tmcf->router_conf = rtcf;
868 tmcf->count = 1;
869 tmcf->engine = task->thread->engine;
870
871 tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
872 sizeof(nxt_router_engine_conf_t));
873 if (nxt_slow_path(tmcf->engines == NULL)) {
874 goto temp_fail;
875 }
876
877 nxt_queue_init(&creating_sockets);
878 nxt_queue_init(&pending_sockets);
879 nxt_queue_init(&updating_sockets);
880 nxt_queue_init(&keeping_sockets);
881 nxt_queue_init(&deleting_sockets);
882
883#if (NXT_TLS)
884 nxt_queue_init(&tmcf->tls);
885#endif
886
887 nxt_queue_init(&tmcf->apps);
888 nxt_queue_init(&tmcf->previous);
889
890 return tmcf;
891
892temp_fail:
893
894 nxt_mp_destroy(tmp);
895
896fail:
897
898 nxt_mp_destroy(mp);
899
900 return NULL;
901}
902
903
904nxt_inline nxt_bool_t
905nxt_router_app_can_start(nxt_app_t *app)
906{
907 return app->processes + app->pending_processes < app->max_processes
908 && app->pending_processes < app->max_pending_processes;
909}
910
911
912nxt_inline nxt_bool_t
913nxt_router_app_need_start(nxt_app_t *app)
914{
915 return (app->active_requests
916 > app->port_hash_count + app->pending_processes)
917 || (app->spare_processes
918 > app->idle_processes + app->pending_processes);
919}
920
921
922static void
923nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
924{
925 nxt_int_t ret;
926 nxt_app_t *app;
927 nxt_router_t *router;
928 nxt_runtime_t *rt;
929 nxt_queue_link_t *qlk;
930 nxt_socket_conf_t *skcf;
931 nxt_router_conf_t *rtcf;
932 nxt_router_temp_conf_t *tmcf;
933 const nxt_event_interface_t *interface;
934#if (NXT_TLS)
935 nxt_router_tlssock_t *tls;
936#endif
937
938 tmcf = obj;
939
940 qlk = nxt_queue_first(&pending_sockets);
941
942 if (qlk != nxt_queue_tail(&pending_sockets)) {
943 nxt_queue_remove(qlk);
944 nxt_queue_insert_tail(&creating_sockets, qlk);
945
946 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
947
948 nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
949
950 return;
951 }
952
953#if (NXT_TLS)
954 qlk = nxt_queue_last(&tmcf->tls);
955
956 if (qlk != nxt_queue_head(&tmcf->tls)) {
957 nxt_queue_remove(qlk);
958
959 tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
960
961 nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
962 nxt_router_tls_rpc_handler, tls);
963 return;
964 }
965#endif
966
967 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
968
969 if (nxt_router_app_need_start(app)) {
970 nxt_router_app_rpc_create(task, tmcf, app);
971 return;
972 }
973
974 } nxt_queue_loop;
975
976 rtcf = tmcf->router_conf;
977
978 if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
979 nxt_router_access_log_open(task, tmcf);
980 return;
981 }
982
983 rt = task->thread->runtime;
984
985 interface = nxt_service_get(rt->services, "engine", NULL);
986
987 router = rtcf->router;
988
989 ret = nxt_router_engines_create(task, router, tmcf, interface);
990 if (nxt_slow_path(ret != NXT_OK)) {
991 goto fail;
992 }
993
994 ret = nxt_router_threads_create(task, rt, tmcf);
995 if (nxt_slow_path(ret != NXT_OK)) {
996 goto fail;
997 }
998
999 nxt_router_apps_sort(task, router, tmcf);
1000
1001 nxt_router_apps_hash_use(task, rtcf, 1);
1002
1003 nxt_router_engines_post(router, tmcf);
1004
1005 nxt_queue_add(&router->sockets, &updating_sockets);
1006 nxt_queue_add(&router->sockets, &creating_sockets);
1007
1008 router->access_log = rtcf->access_log;
1009
1010 nxt_router_conf_ready(task, tmcf);
1011
1012 return;
1013
1014fail:
1015
1016 nxt_router_conf_error(task, tmcf);
1017
1018 return;
1019}
1020
1021
1022static void
1023nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1024{
1025 nxt_joint_job_t *job;
1026
1027 job = obj;
1028
1029 nxt_router_conf_ready(task, job->tmcf);
1030}
1031
1032
1033static void
1034nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1035{
1036 uint32_t count;
1037 nxt_router_conf_t *rtcf;
1038 nxt_thread_spinlock_t *lock;
1039
1040 nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count);
1041
1042 if (--tmcf->count > 0) {
1043 return;
1044 }
1045
1046 nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1047
1048 rtcf = tmcf->router_conf;
1049
1050 lock = &rtcf->router->lock;
1051
1052 nxt_thread_spin_lock(lock);
1053
1054 count = rtcf->count;
1055
1056 nxt_thread_spin_unlock(lock);
1057
1058 nxt_debug(task, "rtcf %p: %D", rtcf, count);
1059
1060 if (count == 0) {
1061 nxt_router_apps_hash_use(task, rtcf, -1);
1062
1063 nxt_router_access_log_release(task, lock, rtcf->access_log);
1064
1065 nxt_mp_destroy(rtcf->mem_pool);
1066 }
1067
1068 nxt_mp_release(tmcf->mem_pool);
1069}
1070
1071
1072static void
1073nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1074{
1075 nxt_app_t *app;
1076 nxt_queue_t new_socket_confs;
1077 nxt_socket_t s;
1078 nxt_router_t *router;
1079 nxt_queue_link_t *qlk;
1080 nxt_socket_conf_t *skcf;
1081 nxt_router_conf_t *rtcf;
1082
1083 nxt_alert(task, "failed to apply new conf");
1084
1085 for (qlk = nxt_queue_first(&creating_sockets);
1086 qlk != nxt_queue_tail(&creating_sockets);
1087 qlk = nxt_queue_next(qlk))
1088 {
1089 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1090 s = skcf->listen->socket;
1091
1092 if (s != -1) {
1093 nxt_socket_close(task, s);
1094 }
1095
1096 nxt_free(skcf->listen);
1097 }
1098
1099 nxt_queue_init(&new_socket_confs);
1100 nxt_queue_add(&new_socket_confs, &updating_sockets);
1101 nxt_queue_add(&new_socket_confs, &pending_sockets);
1102 nxt_queue_add(&new_socket_confs, &creating_sockets);
1103
1104 rtcf = tmcf->router_conf;
1105
1106 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1107
1108 nxt_router_app_unlink(task, app);
1109
1110 } nxt_queue_loop;
1111
1112 router = rtcf->router;
1113
1114 nxt_queue_add(&router->sockets, &keeping_sockets);
1115 nxt_queue_add(&router->sockets, &deleting_sockets);
1116
1117 nxt_queue_add(&router->apps, &tmcf->previous);
1118
1119 // TODO: new engines and threads
1120
1121 nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1122
1123 nxt_mp_destroy(rtcf->mem_pool);
1124
1125 nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1126
1127 nxt_mp_release(tmcf->mem_pool);
1128}
1129
1130
1131static void
1132nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1133 nxt_port_msg_type_t type)
1134{
1135 nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1136
1137 nxt_port_use(task, tmcf->port, -1);
1138
1139 tmcf->port = NULL;
1140}
1141
1142
1143static nxt_conf_map_t nxt_router_conf[] = {
1144 {
1145 nxt_string("listeners_threads"),
1146 NXT_CONF_MAP_INT32,
1147 offsetof(nxt_router_conf_t, threads),
1148 },
1149};
1150
1151
1152static nxt_conf_map_t nxt_router_app_conf[] = {
1153 {
1154 nxt_string("type"),
1155 NXT_CONF_MAP_STR,
1156 offsetof(nxt_router_app_conf_t, type),
1157 },
1158
1159 {
1160 nxt_string("limits"),
1161 NXT_CONF_MAP_PTR,
1162 offsetof(nxt_router_app_conf_t, limits_value),
1163 },
1164
1165 {
1166 nxt_string("processes"),
1167 NXT_CONF_MAP_INT32,
1168 offsetof(nxt_router_app_conf_t, processes),
1169 },
1170
1171 {
1172 nxt_string("processes"),
1173 NXT_CONF_MAP_PTR,
1174 offsetof(nxt_router_app_conf_t, processes_value),
1175 },
1176
1177 {
1178 nxt_string("targets"),
1179 NXT_CONF_MAP_PTR,
1180 offsetof(nxt_router_app_conf_t, targets_value),
1181 },
1182};
1183
1184
1185static nxt_conf_map_t nxt_router_app_limits_conf[] = {
1186 {
1187 nxt_string("timeout"),
1188 NXT_CONF_MAP_MSEC,
1189 offsetof(nxt_router_app_conf_t, timeout),
1190 },
1191
1192 {
1193 nxt_string("requests"),
1194 NXT_CONF_MAP_INT32,
1195 offsetof(nxt_router_app_conf_t, requests),
1196 },
1197};
1198
1199
1200static nxt_conf_map_t nxt_router_app_processes_conf[] = {
1201 {
1202 nxt_string("spare"),
1203 NXT_CONF_MAP_INT32,
1204 offsetof(nxt_router_app_conf_t, spare_processes),
1205 },
1206
1207 {
1208 nxt_string("max"),
1209 NXT_CONF_MAP_INT32,
1210 offsetof(nxt_router_app_conf_t, max_processes),
1211 },
1212
1213 {
1214 nxt_string("idle_timeout"),
1215 NXT_CONF_MAP_MSEC,
1216 offsetof(nxt_router_app_conf_t, idle_timeout),
1217 },
1218};
1219
1220
1221static nxt_conf_map_t nxt_router_listener_conf[] = {
1222 {
1223 nxt_string("pass"),
1224 NXT_CONF_MAP_STR_COPY,
1225 offsetof(nxt_router_listener_conf_t, pass),
1226 },
1227
1228 {
1229 nxt_string("application"),
1230 NXT_CONF_MAP_STR_COPY,
1231 offsetof(nxt_router_listener_conf_t, application),
1232 },
1233};
1234
1235
1236static nxt_conf_map_t nxt_router_http_conf[] = {
1237 {
1238 nxt_string("header_buffer_size"),
1239 NXT_CONF_MAP_SIZE,
1240 offsetof(nxt_socket_conf_t, header_buffer_size),
1241 },
1242
1243 {
1244 nxt_string("large_header_buffer_size"),
1245 NXT_CONF_MAP_SIZE,
1246 offsetof(nxt_socket_conf_t, large_header_buffer_size),
1247 },
1248
1249 {
1250 nxt_string("large_header_buffers"),
1251 NXT_CONF_MAP_SIZE,
1252 offsetof(nxt_socket_conf_t, large_header_buffers),
1253 },
1254
1255 {
1256 nxt_string("body_buffer_size"),
1257 NXT_CONF_MAP_SIZE,
1258 offsetof(nxt_socket_conf_t, body_buffer_size),
1259 },
1260
1261 {
1262 nxt_string("max_body_size"),
1263 NXT_CONF_MAP_SIZE,
1264 offsetof(nxt_socket_conf_t, max_body_size),
1265 },
1266
1267 {
1268 nxt_string("idle_timeout"),
1269 NXT_CONF_MAP_MSEC,
1270 offsetof(nxt_socket_conf_t, idle_timeout),
1271 },
1272
1273 {
1274 nxt_string("header_read_timeout"),
1275 NXT_CONF_MAP_MSEC,
1276 offsetof(nxt_socket_conf_t, header_read_timeout),
1277 },
1278
1279 {
1280 nxt_string("body_read_timeout"),
1281 NXT_CONF_MAP_MSEC,
1282 offsetof(nxt_socket_conf_t, body_read_timeout),
1283 },
1284
1285 {
1286 nxt_string("send_timeout"),
1287 NXT_CONF_MAP_MSEC,
1288 offsetof(nxt_socket_conf_t, send_timeout),
1289 },
1290
1291 {
1292 nxt_string("body_temp_path"),
1293 NXT_CONF_MAP_STR,
1294 offsetof(nxt_socket_conf_t, body_temp_path),
1295 },
1296
1297 {
1298 nxt_string("discard_unsafe_fields"),
1299 NXT_CONF_MAP_INT8,
1300 offsetof(nxt_socket_conf_t, discard_unsafe_fields),
1301 },
1302};
1303
1304
1305static nxt_conf_map_t nxt_router_websocket_conf[] = {
1306 {
1307 nxt_string("max_frame_size"),
1308 NXT_CONF_MAP_SIZE,
1309 offsetof(nxt_websocket_conf_t, max_frame_size),
1310 },
1311
1312 {
1313 nxt_string("read_timeout"),
1314 NXT_CONF_MAP_MSEC,
1315 offsetof(nxt_websocket_conf_t, read_timeout),
1316 },
1317
1318 {
1319 nxt_string("keepalive_interval"),
1320 NXT_CONF_MAP_MSEC,
1321 offsetof(nxt_websocket_conf_t, keepalive_interval),
1322 },
1323
1324};
1325
1326
1327static nxt_int_t
1328nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1329 u_char *start, u_char *end)
1330{
1331 u_char *p;
1332 size_t size;
1333 nxt_mp_t *mp, *app_mp;
1334 uint32_t next, next_target;
1335 nxt_int_t ret;
1336 nxt_str_t name, path, target;
1337 nxt_app_t *app, *prev;
1338 nxt_str_t *t, *s, *targets;
1339 nxt_uint_t n, i;
1340 nxt_port_t *port;
1341 nxt_router_t *router;
1342 nxt_app_joint_t *app_joint;
1343#if (NXT_TLS)
1344 nxt_tls_init_t *tls_init;
1345 nxt_conf_value_t *certificate;
1346#endif
1347 nxt_conf_value_t *conf, *http, *value, *websocket;
1348 nxt_conf_value_t *applications, *application;
1349 nxt_conf_value_t *listeners, *listener;
1350 nxt_conf_value_t *routes_conf, *static_conf;
1351 nxt_socket_conf_t *skcf;
1352 nxt_http_routes_t *routes;
1353 nxt_event_engine_t *engine;
1354 nxt_app_lang_module_t *lang;
1355 nxt_router_app_conf_t apcf;
1356 nxt_router_access_log_t *access_log;
1357 nxt_router_listener_conf_t lscf;
1358
1359 static nxt_str_t http_path = nxt_string("/settings/http");
1360 static nxt_str_t applications_path = nxt_string("/applications");
1361 static nxt_str_t listeners_path = nxt_string("/listeners");
1362 static nxt_str_t routes_path = nxt_string("/routes");
1363 static nxt_str_t access_log_path = nxt_string("/access_log");
1364#if (NXT_TLS)
1365 static nxt_str_t certificate_path = nxt_string("/tls/certificate");
1366 static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands");
1367 static nxt_str_t conf_cache_path = nxt_string("/tls/session/cache_size");
1368 static nxt_str_t conf_timeout_path = nxt_string("/tls/session/timeout");
1369#endif
1370 static nxt_str_t static_path = nxt_string("/settings/http/static");
1371 static nxt_str_t websocket_path = nxt_string("/settings/http/websocket");
1372
1373 conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1374 if (conf == NULL) {
1375 nxt_alert(task, "configuration parsing error");
1376 return NXT_ERROR;
1377 }
1378
1379 mp = tmcf->router_conf->mem_pool;
1380
1381 ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1382 nxt_nitems(nxt_router_conf), tmcf->router_conf);
1383 if (ret != NXT_OK) {
1384 nxt_alert(task, "root map error");
1385 return NXT_ERROR;
1386 }
1387
1388 if (tmcf->router_conf->threads == 0) {
1389 tmcf->router_conf->threads = nxt_ncpu;
1390 }
1391
1392 static_conf = nxt_conf_get_path(conf, &static_path);
1393
1394 ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
1395 if (nxt_slow_path(ret != NXT_OK)) {
1396 return NXT_ERROR;
1397 }
1398
1399 router = tmcf->router_conf->router;
1400
1401 applications = nxt_conf_get_path(conf, &applications_path);
1402
1403 if (applications != NULL) {
1404 next = 0;
1405
1406 for ( ;; ) {
1407 application = nxt_conf_next_object_member(applications,
1408 &name, &next);
1409 if (application == NULL) {
1410 break;
1411 }
1412
1413 nxt_debug(task, "application \"%V\"", &name);
1414
1415 size = nxt_conf_json_length(application, NULL);
1416
1417 app_mp = nxt_mp_create(4096, 128, 1024, 64);
1418 if (nxt_slow_path(app_mp == NULL)) {
1419 goto fail;
1420 }
1421
1422 app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size);
1423 if (app == NULL) {
1424 goto app_fail;
1425 }
1426
1427 nxt_memzero(app, sizeof(nxt_app_t));
1428
1429 app->mem_pool = app_mp;
1430
1431 app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1432 app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
1433 + name.length);
1434
1435 p = nxt_conf_json_print(app->conf.start, application, NULL);
1436 app->conf.length = p - app->conf.start;
1437
1438 nxt_assert(app->conf.length <= size);
1439
1440 nxt_debug(task, "application conf \"%V\"", &app->conf);
1441
1442 prev = nxt_router_app_find(&router->apps, &name);
1443
1444 if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1445 nxt_mp_destroy(app_mp);
1446
1447 nxt_queue_remove(&prev->link);
1448 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1449
1450 ret = nxt_router_apps_hash_add(tmcf->router_conf, prev);
1451 if (nxt_slow_path(ret != NXT_OK)) {
1452 goto fail;
1453 }
1454
1455 continue;
1456 }
1457
1458 apcf.processes = 1;
1459 apcf.max_processes = 1;
1460 apcf.spare_processes = 0;
1461 apcf.timeout = 0;
1462 apcf.idle_timeout = 15000;
1463 apcf.requests = 0;
1464 apcf.limits_value = NULL;
1465 apcf.processes_value = NULL;
1466 apcf.targets_value = NULL;
1467
1468 app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
1469 if (nxt_slow_path(app_joint == NULL)) {
1470 goto app_fail;
1471 }
1472
1473 nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
1474
1475 ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1476 nxt_nitems(nxt_router_app_conf), &apcf);
1477 if (ret != NXT_OK) {
1478 nxt_alert(task, "application map error");
1479 goto app_fail;
1480 }
1481
1482 if (apcf.limits_value != NULL) {
1483
1484 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1485 nxt_alert(task, "application limits is not object");
1486 goto app_fail;
1487 }
1488
1489 ret = nxt_conf_map_object(mp, apcf.limits_value,
1490 nxt_router_app_limits_conf,
1491 nxt_nitems(nxt_router_app_limits_conf),
1492 &apcf);
1493 if (ret != NXT_OK) {
1494 nxt_alert(task, "application limits map error");
1495 goto app_fail;
1496 }
1497 }
1498
1499 if (apcf.processes_value != NULL
1500 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1501 {
1502 ret = nxt_conf_map_object(mp, apcf.processes_value,
1503 nxt_router_app_processes_conf,
1504 nxt_nitems(nxt_router_app_processes_conf),
1505 &apcf);
1506 if (ret != NXT_OK) {
1507 nxt_alert(task, "application processes map error");
1508 goto app_fail;
1509 }
1510
1511 } else {
1512 apcf.max_processes = apcf.processes;
1513 apcf.spare_processes = apcf.processes;
1514 }
1515
1516 if (apcf.targets_value != NULL) {
1517 n = nxt_conf_object_members_count(apcf.targets_value);
1518
1519 targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n);
1520 if (nxt_slow_path(targets == NULL)) {
1521 goto app_fail;
1522 }
1523
1524 next_target = 0;
1525
1526 for (i = 0; i < n; i++) {
1527 (void) nxt_conf_next_object_member(apcf.targets_value,
1528 &target, &next_target);
1529
1530 s = nxt_str_dup(app_mp, &targets[i], &target);
1531 if (nxt_slow_path(s == NULL)) {
1532 goto app_fail;
1533 }
1534 }
1535
1536 } else {
1537 targets = NULL;
1538 }
1539
1540 nxt_debug(task, "application type: %V", &apcf.type);
1541 nxt_debug(task, "application processes: %D", apcf.processes);
1542 nxt_debug(task, "application request timeout: %M", apcf.timeout);
1543 nxt_debug(task, "application requests: %D", apcf.requests);
1544
1545 lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1546
1547 if (lang == NULL) {
1548 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1549 goto app_fail;
1550 }
1551
1552 nxt_debug(task, "application language module: \"%s\"", lang->file);
1553
1554 ret = nxt_thread_mutex_create(&app->mutex);
1555 if (ret != NXT_OK) {
1556 goto app_fail;
1557 }
1558
1559 nxt_queue_init(&app->ports);
1560 nxt_queue_init(&app->spare_ports);
1561 nxt_queue_init(&app->idle_ports);
1562 nxt_queue_init(&app->ack_waiting_req);
1563
1564 app->name.length = name.length;
1565 nxt_memcpy(app->name.start, name.start, name.length);
1566
1567 app->type = lang->type;
1568 app->max_processes = apcf.max_processes;
1569 app->spare_processes = apcf.spare_processes;
1570 app->max_pending_processes = apcf.spare_processes
1571 ? apcf.spare_processes : 1;
1572 app->timeout = apcf.timeout;
1573 app->idle_timeout = apcf.idle_timeout;
1574 app->max_requests = apcf.requests;
1575
1576 app->targets = targets;
1577
1578 engine = task->thread->engine;
1579
1580 app->engine = engine;
1581
1582 app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1583 app->adjust_idle_work.task = &engine->task;
1584 app->adjust_idle_work.obj = app;
1585
1586 nxt_queue_insert_tail(&tmcf->apps, &app->link);
1587
1588 ret = nxt_router_apps_hash_add(tmcf->router_conf, app);
1589 if (nxt_slow_path(ret != NXT_OK)) {
1590 goto app_fail;
1591 }
1592
1593 nxt_router_app_use(task, app, 1);
1594
1595 app->joint = app_joint;
1596
1597 app_joint->use_count = 1;
1598 app_joint->app = app;
1599
1600 app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
1601 app_joint->idle_timer.work_queue = &engine->fast_work_queue;
1602 app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
1603 app_joint->idle_timer.task = &engine->task;
1604 app_joint->idle_timer.log = app_joint->idle_timer.task->log;
1605
1606 app_joint->free_app_work.handler = nxt_router_free_app;
1607 app_joint->free_app_work.task = &engine->task;
1608 app_joint->free_app_work.obj = app_joint;
1609
900nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
901 void *data)
902{
903 union {
904 nxt_pid_t removed_pid;
905 void *data;
906 } u;
907
908 u.data = data;
909
910 nxt_port_rpc_remove_peer(task, port, u.removed_pid);
911}
912
913
914static void
915nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
916{
917 nxt_event_engine_t *engine;
918
919 nxt_port_remove_pid_handler(task, msg);
920
921 nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0)
922 {
923 if (nxt_fast_path(engine->port != NULL)) {
924 nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid,
925 msg->u.data);
926 }
927 }
928 nxt_queue_loop;
929
930 if (msg->port_msg.stream == 0) {
931 return;
932 }
933
934 msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR;
935
936 nxt_port_rpc_handler(task, msg);
937}
938
939
940static nxt_router_temp_conf_t *
941nxt_router_temp_conf(nxt_task_t *task)
942{
943 nxt_mp_t *mp, *tmp;
944 nxt_router_conf_t *rtcf;
945 nxt_router_temp_conf_t *tmcf;
946
947 mp = nxt_mp_create(1024, 128, 256, 32);
948 if (nxt_slow_path(mp == NULL)) {
949 return NULL;
950 }
951
952 rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t));
953 if (nxt_slow_path(rtcf == NULL)) {
954 goto fail;
955 }
956
957 rtcf->mem_pool = mp;
958
959 tmp = nxt_mp_create(1024, 128, 256, 32);
960 if (nxt_slow_path(tmp == NULL)) {
961 goto fail;
962 }
963
964 tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t));
965 if (nxt_slow_path(tmcf == NULL)) {
966 goto temp_fail;
967 }
968
969 tmcf->mem_pool = tmp;
970 tmcf->router_conf = rtcf;
971 tmcf->count = 1;
972 tmcf->engine = task->thread->engine;
973
974 tmcf->engines = nxt_array_create(tmcf->mem_pool, 4,
975 sizeof(nxt_router_engine_conf_t));
976 if (nxt_slow_path(tmcf->engines == NULL)) {
977 goto temp_fail;
978 }
979
980 nxt_queue_init(&creating_sockets);
981 nxt_queue_init(&pending_sockets);
982 nxt_queue_init(&updating_sockets);
983 nxt_queue_init(&keeping_sockets);
984 nxt_queue_init(&deleting_sockets);
985
986#if (NXT_TLS)
987 nxt_queue_init(&tmcf->tls);
988#endif
989
990 nxt_queue_init(&tmcf->apps);
991 nxt_queue_init(&tmcf->previous);
992
993 return tmcf;
994
995temp_fail:
996
997 nxt_mp_destroy(tmp);
998
999fail:
1000
1001 nxt_mp_destroy(mp);
1002
1003 return NULL;
1004}
1005
1006
1007nxt_inline nxt_bool_t
1008nxt_router_app_can_start(nxt_app_t *app)
1009{
1010 return app->processes + app->pending_processes < app->max_processes
1011 && app->pending_processes < app->max_pending_processes;
1012}
1013
1014
1015nxt_inline nxt_bool_t
1016nxt_router_app_need_start(nxt_app_t *app)
1017{
1018 return (app->active_requests
1019 > app->port_hash_count + app->pending_processes)
1020 || (app->spare_processes
1021 > app->idle_processes + app->pending_processes);
1022}
1023
1024
1025static void
1026nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
1027{
1028 nxt_int_t ret;
1029 nxt_app_t *app;
1030 nxt_router_t *router;
1031 nxt_runtime_t *rt;
1032 nxt_queue_link_t *qlk;
1033 nxt_socket_conf_t *skcf;
1034 nxt_router_conf_t *rtcf;
1035 nxt_router_temp_conf_t *tmcf;
1036 const nxt_event_interface_t *interface;
1037#if (NXT_TLS)
1038 nxt_router_tlssock_t *tls;
1039#endif
1040
1041 tmcf = obj;
1042
1043 qlk = nxt_queue_first(&pending_sockets);
1044
1045 if (qlk != nxt_queue_tail(&pending_sockets)) {
1046 nxt_queue_remove(qlk);
1047 nxt_queue_insert_tail(&creating_sockets, qlk);
1048
1049 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1050
1051 nxt_router_listen_socket_rpc_create(task, tmcf, skcf);
1052
1053 return;
1054 }
1055
1056#if (NXT_TLS)
1057 qlk = nxt_queue_last(&tmcf->tls);
1058
1059 if (qlk != nxt_queue_head(&tmcf->tls)) {
1060 nxt_queue_remove(qlk);
1061
1062 tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
1063
1064 nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
1065 nxt_router_tls_rpc_handler, tls);
1066 return;
1067 }
1068#endif
1069
1070 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1071
1072 if (nxt_router_app_need_start(app)) {
1073 nxt_router_app_rpc_create(task, tmcf, app);
1074 return;
1075 }
1076
1077 } nxt_queue_loop;
1078
1079 rtcf = tmcf->router_conf;
1080
1081 if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) {
1082 nxt_router_access_log_open(task, tmcf);
1083 return;
1084 }
1085
1086 rt = task->thread->runtime;
1087
1088 interface = nxt_service_get(rt->services, "engine", NULL);
1089
1090 router = rtcf->router;
1091
1092 ret = nxt_router_engines_create(task, router, tmcf, interface);
1093 if (nxt_slow_path(ret != NXT_OK)) {
1094 goto fail;
1095 }
1096
1097 ret = nxt_router_threads_create(task, rt, tmcf);
1098 if (nxt_slow_path(ret != NXT_OK)) {
1099 goto fail;
1100 }
1101
1102 nxt_router_apps_sort(task, router, tmcf);
1103
1104 nxt_router_apps_hash_use(task, rtcf, 1);
1105
1106 nxt_router_engines_post(router, tmcf);
1107
1108 nxt_queue_add(&router->sockets, &updating_sockets);
1109 nxt_queue_add(&router->sockets, &creating_sockets);
1110
1111 router->access_log = rtcf->access_log;
1112
1113 nxt_router_conf_ready(task, tmcf);
1114
1115 return;
1116
1117fail:
1118
1119 nxt_router_conf_error(task, tmcf);
1120
1121 return;
1122}
1123
1124
1125static void
1126nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data)
1127{
1128 nxt_joint_job_t *job;
1129
1130 job = obj;
1131
1132 nxt_router_conf_ready(task, job->tmcf);
1133}
1134
1135
1136static void
1137nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1138{
1139 uint32_t count;
1140 nxt_router_conf_t *rtcf;
1141 nxt_thread_spinlock_t *lock;
1142
1143 nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count);
1144
1145 if (--tmcf->count > 0) {
1146 return;
1147 }
1148
1149 nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST);
1150
1151 rtcf = tmcf->router_conf;
1152
1153 lock = &rtcf->router->lock;
1154
1155 nxt_thread_spin_lock(lock);
1156
1157 count = rtcf->count;
1158
1159 nxt_thread_spin_unlock(lock);
1160
1161 nxt_debug(task, "rtcf %p: %D", rtcf, count);
1162
1163 if (count == 0) {
1164 nxt_router_apps_hash_use(task, rtcf, -1);
1165
1166 nxt_router_access_log_release(task, lock, rtcf->access_log);
1167
1168 nxt_mp_destroy(rtcf->mem_pool);
1169 }
1170
1171 nxt_mp_release(tmcf->mem_pool);
1172}
1173
1174
1175static void
1176nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
1177{
1178 nxt_app_t *app;
1179 nxt_queue_t new_socket_confs;
1180 nxt_socket_t s;
1181 nxt_router_t *router;
1182 nxt_queue_link_t *qlk;
1183 nxt_socket_conf_t *skcf;
1184 nxt_router_conf_t *rtcf;
1185
1186 nxt_alert(task, "failed to apply new conf");
1187
1188 for (qlk = nxt_queue_first(&creating_sockets);
1189 qlk != nxt_queue_tail(&creating_sockets);
1190 qlk = nxt_queue_next(qlk))
1191 {
1192 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
1193 s = skcf->listen->socket;
1194
1195 if (s != -1) {
1196 nxt_socket_close(task, s);
1197 }
1198
1199 nxt_free(skcf->listen);
1200 }
1201
1202 nxt_queue_init(&new_socket_confs);
1203 nxt_queue_add(&new_socket_confs, &updating_sockets);
1204 nxt_queue_add(&new_socket_confs, &pending_sockets);
1205 nxt_queue_add(&new_socket_confs, &creating_sockets);
1206
1207 rtcf = tmcf->router_conf;
1208
1209 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1210
1211 nxt_router_app_unlink(task, app);
1212
1213 } nxt_queue_loop;
1214
1215 router = rtcf->router;
1216
1217 nxt_queue_add(&router->sockets, &keeping_sockets);
1218 nxt_queue_add(&router->sockets, &deleting_sockets);
1219
1220 nxt_queue_add(&router->apps, &tmcf->previous);
1221
1222 // TODO: new engines and threads
1223
1224 nxt_router_access_log_release(task, &router->lock, rtcf->access_log);
1225
1226 nxt_mp_destroy(rtcf->mem_pool);
1227
1228 nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR);
1229
1230 nxt_mp_release(tmcf->mem_pool);
1231}
1232
1233
1234static void
1235nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1236 nxt_port_msg_type_t type)
1237{
1238 nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL);
1239
1240 nxt_port_use(task, tmcf->port, -1);
1241
1242 tmcf->port = NULL;
1243}
1244
1245
1246static nxt_conf_map_t nxt_router_conf[] = {
1247 {
1248 nxt_string("listeners_threads"),
1249 NXT_CONF_MAP_INT32,
1250 offsetof(nxt_router_conf_t, threads),
1251 },
1252};
1253
1254
1255static nxt_conf_map_t nxt_router_app_conf[] = {
1256 {
1257 nxt_string("type"),
1258 NXT_CONF_MAP_STR,
1259 offsetof(nxt_router_app_conf_t, type),
1260 },
1261
1262 {
1263 nxt_string("limits"),
1264 NXT_CONF_MAP_PTR,
1265 offsetof(nxt_router_app_conf_t, limits_value),
1266 },
1267
1268 {
1269 nxt_string("processes"),
1270 NXT_CONF_MAP_INT32,
1271 offsetof(nxt_router_app_conf_t, processes),
1272 },
1273
1274 {
1275 nxt_string("processes"),
1276 NXT_CONF_MAP_PTR,
1277 offsetof(nxt_router_app_conf_t, processes_value),
1278 },
1279
1280 {
1281 nxt_string("targets"),
1282 NXT_CONF_MAP_PTR,
1283 offsetof(nxt_router_app_conf_t, targets_value),
1284 },
1285};
1286
1287
1288static nxt_conf_map_t nxt_router_app_limits_conf[] = {
1289 {
1290 nxt_string("timeout"),
1291 NXT_CONF_MAP_MSEC,
1292 offsetof(nxt_router_app_conf_t, timeout),
1293 },
1294
1295 {
1296 nxt_string("requests"),
1297 NXT_CONF_MAP_INT32,
1298 offsetof(nxt_router_app_conf_t, requests),
1299 },
1300};
1301
1302
1303static nxt_conf_map_t nxt_router_app_processes_conf[] = {
1304 {
1305 nxt_string("spare"),
1306 NXT_CONF_MAP_INT32,
1307 offsetof(nxt_router_app_conf_t, spare_processes),
1308 },
1309
1310 {
1311 nxt_string("max"),
1312 NXT_CONF_MAP_INT32,
1313 offsetof(nxt_router_app_conf_t, max_processes),
1314 },
1315
1316 {
1317 nxt_string("idle_timeout"),
1318 NXT_CONF_MAP_MSEC,
1319 offsetof(nxt_router_app_conf_t, idle_timeout),
1320 },
1321};
1322
1323
1324static nxt_conf_map_t nxt_router_listener_conf[] = {
1325 {
1326 nxt_string("pass"),
1327 NXT_CONF_MAP_STR_COPY,
1328 offsetof(nxt_router_listener_conf_t, pass),
1329 },
1330
1331 {
1332 nxt_string("application"),
1333 NXT_CONF_MAP_STR_COPY,
1334 offsetof(nxt_router_listener_conf_t, application),
1335 },
1336};
1337
1338
1339static nxt_conf_map_t nxt_router_http_conf[] = {
1340 {
1341 nxt_string("header_buffer_size"),
1342 NXT_CONF_MAP_SIZE,
1343 offsetof(nxt_socket_conf_t, header_buffer_size),
1344 },
1345
1346 {
1347 nxt_string("large_header_buffer_size"),
1348 NXT_CONF_MAP_SIZE,
1349 offsetof(nxt_socket_conf_t, large_header_buffer_size),
1350 },
1351
1352 {
1353 nxt_string("large_header_buffers"),
1354 NXT_CONF_MAP_SIZE,
1355 offsetof(nxt_socket_conf_t, large_header_buffers),
1356 },
1357
1358 {
1359 nxt_string("body_buffer_size"),
1360 NXT_CONF_MAP_SIZE,
1361 offsetof(nxt_socket_conf_t, body_buffer_size),
1362 },
1363
1364 {
1365 nxt_string("max_body_size"),
1366 NXT_CONF_MAP_SIZE,
1367 offsetof(nxt_socket_conf_t, max_body_size),
1368 },
1369
1370 {
1371 nxt_string("idle_timeout"),
1372 NXT_CONF_MAP_MSEC,
1373 offsetof(nxt_socket_conf_t, idle_timeout),
1374 },
1375
1376 {
1377 nxt_string("header_read_timeout"),
1378 NXT_CONF_MAP_MSEC,
1379 offsetof(nxt_socket_conf_t, header_read_timeout),
1380 },
1381
1382 {
1383 nxt_string("body_read_timeout"),
1384 NXT_CONF_MAP_MSEC,
1385 offsetof(nxt_socket_conf_t, body_read_timeout),
1386 },
1387
1388 {
1389 nxt_string("send_timeout"),
1390 NXT_CONF_MAP_MSEC,
1391 offsetof(nxt_socket_conf_t, send_timeout),
1392 },
1393
1394 {
1395 nxt_string("body_temp_path"),
1396 NXT_CONF_MAP_STR,
1397 offsetof(nxt_socket_conf_t, body_temp_path),
1398 },
1399
1400 {
1401 nxt_string("discard_unsafe_fields"),
1402 NXT_CONF_MAP_INT8,
1403 offsetof(nxt_socket_conf_t, discard_unsafe_fields),
1404 },
1405};
1406
1407
1408static nxt_conf_map_t nxt_router_websocket_conf[] = {
1409 {
1410 nxt_string("max_frame_size"),
1411 NXT_CONF_MAP_SIZE,
1412 offsetof(nxt_websocket_conf_t, max_frame_size),
1413 },
1414
1415 {
1416 nxt_string("read_timeout"),
1417 NXT_CONF_MAP_MSEC,
1418 offsetof(nxt_websocket_conf_t, read_timeout),
1419 },
1420
1421 {
1422 nxt_string("keepalive_interval"),
1423 NXT_CONF_MAP_MSEC,
1424 offsetof(nxt_websocket_conf_t, keepalive_interval),
1425 },
1426
1427};
1428
1429
1430static nxt_int_t
1431nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
1432 u_char *start, u_char *end)
1433{
1434 u_char *p;
1435 size_t size;
1436 nxt_mp_t *mp, *app_mp;
1437 uint32_t next, next_target;
1438 nxt_int_t ret;
1439 nxt_str_t name, path, target;
1440 nxt_app_t *app, *prev;
1441 nxt_str_t *t, *s, *targets;
1442 nxt_uint_t n, i;
1443 nxt_port_t *port;
1444 nxt_router_t *router;
1445 nxt_app_joint_t *app_joint;
1446#if (NXT_TLS)
1447 nxt_tls_init_t *tls_init;
1448 nxt_conf_value_t *certificate;
1449#endif
1450 nxt_conf_value_t *conf, *http, *value, *websocket;
1451 nxt_conf_value_t *applications, *application;
1452 nxt_conf_value_t *listeners, *listener;
1453 nxt_conf_value_t *routes_conf, *static_conf;
1454 nxt_socket_conf_t *skcf;
1455 nxt_http_routes_t *routes;
1456 nxt_event_engine_t *engine;
1457 nxt_app_lang_module_t *lang;
1458 nxt_router_app_conf_t apcf;
1459 nxt_router_access_log_t *access_log;
1460 nxt_router_listener_conf_t lscf;
1461
1462 static nxt_str_t http_path = nxt_string("/settings/http");
1463 static nxt_str_t applications_path = nxt_string("/applications");
1464 static nxt_str_t listeners_path = nxt_string("/listeners");
1465 static nxt_str_t routes_path = nxt_string("/routes");
1466 static nxt_str_t access_log_path = nxt_string("/access_log");
1467#if (NXT_TLS)
1468 static nxt_str_t certificate_path = nxt_string("/tls/certificate");
1469 static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands");
1470 static nxt_str_t conf_cache_path = nxt_string("/tls/session/cache_size");
1471 static nxt_str_t conf_timeout_path = nxt_string("/tls/session/timeout");
1472#endif
1473 static nxt_str_t static_path = nxt_string("/settings/http/static");
1474 static nxt_str_t websocket_path = nxt_string("/settings/http/websocket");
1475
1476 conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
1477 if (conf == NULL) {
1478 nxt_alert(task, "configuration parsing error");
1479 return NXT_ERROR;
1480 }
1481
1482 mp = tmcf->router_conf->mem_pool;
1483
1484 ret = nxt_conf_map_object(mp, conf, nxt_router_conf,
1485 nxt_nitems(nxt_router_conf), tmcf->router_conf);
1486 if (ret != NXT_OK) {
1487 nxt_alert(task, "root map error");
1488 return NXT_ERROR;
1489 }
1490
1491 if (tmcf->router_conf->threads == 0) {
1492 tmcf->router_conf->threads = nxt_ncpu;
1493 }
1494
1495 static_conf = nxt_conf_get_path(conf, &static_path);
1496
1497 ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf);
1498 if (nxt_slow_path(ret != NXT_OK)) {
1499 return NXT_ERROR;
1500 }
1501
1502 router = tmcf->router_conf->router;
1503
1504 applications = nxt_conf_get_path(conf, &applications_path);
1505
1506 if (applications != NULL) {
1507 next = 0;
1508
1509 for ( ;; ) {
1510 application = nxt_conf_next_object_member(applications,
1511 &name, &next);
1512 if (application == NULL) {
1513 break;
1514 }
1515
1516 nxt_debug(task, "application \"%V\"", &name);
1517
1518 size = nxt_conf_json_length(application, NULL);
1519
1520 app_mp = nxt_mp_create(4096, 128, 1024, 64);
1521 if (nxt_slow_path(app_mp == NULL)) {
1522 goto fail;
1523 }
1524
1525 app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size);
1526 if (app == NULL) {
1527 goto app_fail;
1528 }
1529
1530 nxt_memzero(app, sizeof(nxt_app_t));
1531
1532 app->mem_pool = app_mp;
1533
1534 app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t));
1535 app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t)
1536 + name.length);
1537
1538 p = nxt_conf_json_print(app->conf.start, application, NULL);
1539 app->conf.length = p - app->conf.start;
1540
1541 nxt_assert(app->conf.length <= size);
1542
1543 nxt_debug(task, "application conf \"%V\"", &app->conf);
1544
1545 prev = nxt_router_app_find(&router->apps, &name);
1546
1547 if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) {
1548 nxt_mp_destroy(app_mp);
1549
1550 nxt_queue_remove(&prev->link);
1551 nxt_queue_insert_tail(&tmcf->previous, &prev->link);
1552
1553 ret = nxt_router_apps_hash_add(tmcf->router_conf, prev);
1554 if (nxt_slow_path(ret != NXT_OK)) {
1555 goto fail;
1556 }
1557
1558 continue;
1559 }
1560
1561 apcf.processes = 1;
1562 apcf.max_processes = 1;
1563 apcf.spare_processes = 0;
1564 apcf.timeout = 0;
1565 apcf.idle_timeout = 15000;
1566 apcf.requests = 0;
1567 apcf.limits_value = NULL;
1568 apcf.processes_value = NULL;
1569 apcf.targets_value = NULL;
1570
1571 app_joint = nxt_malloc(sizeof(nxt_app_joint_t));
1572 if (nxt_slow_path(app_joint == NULL)) {
1573 goto app_fail;
1574 }
1575
1576 nxt_memzero(app_joint, sizeof(nxt_app_joint_t));
1577
1578 ret = nxt_conf_map_object(mp, application, nxt_router_app_conf,
1579 nxt_nitems(nxt_router_app_conf), &apcf);
1580 if (ret != NXT_OK) {
1581 nxt_alert(task, "application map error");
1582 goto app_fail;
1583 }
1584
1585 if (apcf.limits_value != NULL) {
1586
1587 if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) {
1588 nxt_alert(task, "application limits is not object");
1589 goto app_fail;
1590 }
1591
1592 ret = nxt_conf_map_object(mp, apcf.limits_value,
1593 nxt_router_app_limits_conf,
1594 nxt_nitems(nxt_router_app_limits_conf),
1595 &apcf);
1596 if (ret != NXT_OK) {
1597 nxt_alert(task, "application limits map error");
1598 goto app_fail;
1599 }
1600 }
1601
1602 if (apcf.processes_value != NULL
1603 && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT)
1604 {
1605 ret = nxt_conf_map_object(mp, apcf.processes_value,
1606 nxt_router_app_processes_conf,
1607 nxt_nitems(nxt_router_app_processes_conf),
1608 &apcf);
1609 if (ret != NXT_OK) {
1610 nxt_alert(task, "application processes map error");
1611 goto app_fail;
1612 }
1613
1614 } else {
1615 apcf.max_processes = apcf.processes;
1616 apcf.spare_processes = apcf.processes;
1617 }
1618
1619 if (apcf.targets_value != NULL) {
1620 n = nxt_conf_object_members_count(apcf.targets_value);
1621
1622 targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n);
1623 if (nxt_slow_path(targets == NULL)) {
1624 goto app_fail;
1625 }
1626
1627 next_target = 0;
1628
1629 for (i = 0; i < n; i++) {
1630 (void) nxt_conf_next_object_member(apcf.targets_value,
1631 &target, &next_target);
1632
1633 s = nxt_str_dup(app_mp, &targets[i], &target);
1634 if (nxt_slow_path(s == NULL)) {
1635 goto app_fail;
1636 }
1637 }
1638
1639 } else {
1640 targets = NULL;
1641 }
1642
1643 nxt_debug(task, "application type: %V", &apcf.type);
1644 nxt_debug(task, "application processes: %D", apcf.processes);
1645 nxt_debug(task, "application request timeout: %M", apcf.timeout);
1646 nxt_debug(task, "application requests: %D", apcf.requests);
1647
1648 lang = nxt_app_lang_module(task->thread->runtime, &apcf.type);
1649
1650 if (lang == NULL) {
1651 nxt_alert(task, "unknown application type: \"%V\"", &apcf.type);
1652 goto app_fail;
1653 }
1654
1655 nxt_debug(task, "application language module: \"%s\"", lang->file);
1656
1657 ret = nxt_thread_mutex_create(&app->mutex);
1658 if (ret != NXT_OK) {
1659 goto app_fail;
1660 }
1661
1662 nxt_queue_init(&app->ports);
1663 nxt_queue_init(&app->spare_ports);
1664 nxt_queue_init(&app->idle_ports);
1665 nxt_queue_init(&app->ack_waiting_req);
1666
1667 app->name.length = name.length;
1668 nxt_memcpy(app->name.start, name.start, name.length);
1669
1670 app->type = lang->type;
1671 app->max_processes = apcf.max_processes;
1672 app->spare_processes = apcf.spare_processes;
1673 app->max_pending_processes = apcf.spare_processes
1674 ? apcf.spare_processes : 1;
1675 app->timeout = apcf.timeout;
1676 app->idle_timeout = apcf.idle_timeout;
1677 app->max_requests = apcf.requests;
1678
1679 app->targets = targets;
1680
1681 engine = task->thread->engine;
1682
1683 app->engine = engine;
1684
1685 app->adjust_idle_work.handler = nxt_router_adjust_idle_timer;
1686 app->adjust_idle_work.task = &engine->task;
1687 app->adjust_idle_work.obj = app;
1688
1689 nxt_queue_insert_tail(&tmcf->apps, &app->link);
1690
1691 ret = nxt_router_apps_hash_add(tmcf->router_conf, app);
1692 if (nxt_slow_path(ret != NXT_OK)) {
1693 goto app_fail;
1694 }
1695
1696 nxt_router_app_use(task, app, 1);
1697
1698 app->joint = app_joint;
1699
1700 app_joint->use_count = 1;
1701 app_joint->app = app;
1702
1703 app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS;
1704 app_joint->idle_timer.work_queue = &engine->fast_work_queue;
1705 app_joint->idle_timer.handler = nxt_router_app_idle_timeout;
1706 app_joint->idle_timer.task = &engine->task;
1707 app_joint->idle_timer.log = app_joint->idle_timer.task->log;
1708
1709 app_joint->free_app_work.handler = nxt_router_free_app;
1710 app_joint->free_app_work.task = &engine->task;
1711 app_joint->free_app_work.obj = app_joint;
1712
1610 port = nxt_port_new(task, (nxt_port_id_t) -1, nxt_pid,
1713 port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
1611 NXT_PROCESS_APP);
1612 if (nxt_slow_path(port == NULL)) {
1613 return NXT_ERROR;
1614 }
1615
1616 ret = nxt_port_socket_init(task, port, 0);
1617 if (nxt_slow_path(ret != NXT_OK)) {
1618 nxt_port_use(task, port, -1);
1619 return NXT_ERROR;
1620 }
1621
1622 ret = nxt_router_app_queue_init(task, port);
1623 if (nxt_slow_path(ret != NXT_OK)) {
1624 nxt_port_write_close(port);
1625 nxt_port_read_close(port);
1626 nxt_port_use(task, port, -1);
1627 return NXT_ERROR;
1628 }
1629
1630 nxt_port_write_enable(task, port);
1631 port->app = app;
1632
1633 app->shared_port = port;
1634
1635 nxt_thread_mutex_create(&app->outgoing.mutex);
1636 }
1637 }
1638
1639 routes_conf = nxt_conf_get_path(conf, &routes_path);
1640 if (nxt_fast_path(routes_conf != NULL)) {
1641 routes = nxt_http_routes_create(task, tmcf, routes_conf);
1642 if (nxt_slow_path(routes == NULL)) {
1643 return NXT_ERROR;
1644 }
1645 tmcf->router_conf->routes = routes;
1646 }
1647
1648 ret = nxt_upstreams_create(task, tmcf, conf);
1649 if (nxt_slow_path(ret != NXT_OK)) {
1650 return ret;
1651 }
1652
1653 http = nxt_conf_get_path(conf, &http_path);
1654#if 0
1655 if (http == NULL) {
1656 nxt_alert(task, "no \"http\" block");
1657 return NXT_ERROR;
1658 }
1659#endif
1660
1661 websocket = nxt_conf_get_path(conf, &websocket_path);
1662
1663 listeners = nxt_conf_get_path(conf, &listeners_path);
1664
1665 if (listeners != NULL) {
1666 next = 0;
1667
1668 for ( ;; ) {
1669 listener = nxt_conf_next_object_member(listeners, &name, &next);
1670 if (listener == NULL) {
1671 break;
1672 }
1673
1674 skcf = nxt_router_socket_conf(task, tmcf, &name);
1675 if (skcf == NULL) {
1676 goto fail;
1677 }
1678
1679 nxt_memzero(&lscf, sizeof(lscf));
1680
1681 ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1682 nxt_nitems(nxt_router_listener_conf),
1683 &lscf);
1684 if (ret != NXT_OK) {
1685 nxt_alert(task, "listener map error");
1686 goto fail;
1687 }
1688
1689 nxt_debug(task, "application: %V", &lscf.application);
1690
1691 // STUB, default values if http block is not defined.
1692 skcf->header_buffer_size = 2048;
1693 skcf->large_header_buffer_size = 8192;
1694 skcf->large_header_buffers = 4;
1695 skcf->discard_unsafe_fields = 1;
1696 skcf->body_buffer_size = 16 * 1024;
1697 skcf->max_body_size = 8 * 1024 * 1024;
1698 skcf->proxy_header_buffer_size = 64 * 1024;
1699 skcf->proxy_buffer_size = 4096;
1700 skcf->proxy_buffers = 256;
1701 skcf->idle_timeout = 180 * 1000;
1702 skcf->header_read_timeout = 30 * 1000;
1703 skcf->body_read_timeout = 30 * 1000;
1704 skcf->send_timeout = 30 * 1000;
1705 skcf->proxy_timeout = 60 * 1000;
1706 skcf->proxy_send_timeout = 30 * 1000;
1707 skcf->proxy_read_timeout = 30 * 1000;
1708
1709 skcf->websocket_conf.max_frame_size = 1024 * 1024;
1710 skcf->websocket_conf.read_timeout = 60 * 1000;
1711 skcf->websocket_conf.keepalive_interval = 30 * 1000;
1712
1713 nxt_str_null(&skcf->body_temp_path);
1714
1715 if (http != NULL) {
1716 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1717 nxt_nitems(nxt_router_http_conf),
1718 skcf);
1719 if (ret != NXT_OK) {
1720 nxt_alert(task, "http map error");
1721 goto fail;
1722 }
1723 }
1724
1725 if (websocket != NULL) {
1726 ret = nxt_conf_map_object(mp, websocket,
1727 nxt_router_websocket_conf,
1728 nxt_nitems(nxt_router_websocket_conf),
1729 &skcf->websocket_conf);
1730 if (ret != NXT_OK) {
1731 nxt_alert(task, "websocket map error");
1732 goto fail;
1733 }
1734 }
1735
1736 t = &skcf->body_temp_path;
1737
1738 if (t->length == 0) {
1739 t->start = (u_char *) task->thread->runtime->tmp;
1740 t->length = nxt_strlen(t->start);
1741 }
1742
1743#if (NXT_TLS)
1744 certificate = nxt_conf_get_path(listener, &certificate_path);
1745
1746 if (certificate != NULL) {
1747 tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t));
1748 if (nxt_slow_path(tls_init == NULL)) {
1749 return NXT_ERROR;
1750 }
1751
1752 tls_init->cache_size = 0;
1753 tls_init->timeout = 300;
1754
1755 value = nxt_conf_get_path(listener, &conf_cache_path);
1756 if (value != NULL) {
1757 tls_init->cache_size = nxt_conf_get_number(value);
1758 }
1759
1760 value = nxt_conf_get_path(listener, &conf_timeout_path);
1761 if (value != NULL) {
1762 tls_init->timeout = nxt_conf_get_number(value);
1763 }
1764
1765 tls_init->conf_cmds = nxt_conf_get_path(listener,
1766 &conf_commands_path);
1767
1768 if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) {
1769 n = nxt_conf_array_elements_count(certificate);
1770
1771 for (i = 0; i < n; i++) {
1772 value = nxt_conf_get_array_element(certificate, i);
1773
1774 nxt_assert(value != NULL);
1775
1776 ret = nxt_router_conf_tls_insert(tmcf, value, skcf,
1777 tls_init, i == 0);
1778 if (nxt_slow_path(ret != NXT_OK)) {
1779 goto fail;
1780 }
1781 }
1782
1783 } else {
1784 /* NXT_CONF_STRING */
1785 ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf,
1786 tls_init, 1);
1787 if (nxt_slow_path(ret != NXT_OK)) {
1788 goto fail;
1789 }
1790 }
1791 }
1792#endif
1793
1794 skcf->listen->handler = nxt_http_conn_init;
1795 skcf->router_conf = tmcf->router_conf;
1796 skcf->router_conf->count++;
1797
1798 if (lscf.pass.length != 0) {
1799 skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass);
1800
1801 /* COMPATIBILITY: listener application. */
1802 } else if (lscf.application.length > 0) {
1803 skcf->action = nxt_http_pass_application(task,
1804 tmcf->router_conf,
1805 &lscf.application);
1806 }
1807
1808 if (nxt_slow_path(skcf->action == NULL)) {
1809 goto fail;
1810 }
1811 }
1812 }
1813
1814 ret = nxt_http_routes_resolve(task, tmcf);
1815 if (nxt_slow_path(ret != NXT_OK)) {
1816 goto fail;
1817 }
1818
1819 value = nxt_conf_get_path(conf, &access_log_path);
1820
1821 if (value != NULL) {
1822 nxt_conf_get_string(value, &path);
1823
1824 access_log = router->access_log;
1825
1826 if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1827 nxt_thread_spin_lock(&router->lock);
1828 access_log->count++;
1829 nxt_thread_spin_unlock(&router->lock);
1830
1831 } else {
1832 access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1833 + path.length);
1834 if (access_log == NULL) {
1835 nxt_alert(task, "failed to allocate access log structure");
1836 goto fail;
1837 }
1838
1839 access_log->fd = -1;
1840 access_log->handler = &nxt_router_access_log_writer;
1841 access_log->count = 1;
1842
1843 access_log->path.length = path.length;
1844 access_log->path.start = (u_char *) access_log
1845 + sizeof(nxt_router_access_log_t);
1846
1847 nxt_memcpy(access_log->path.start, path.start, path.length);
1848 }
1849
1850 tmcf->router_conf->access_log = access_log;
1851 }
1852
1853 nxt_queue_add(&deleting_sockets, &router->sockets);
1854 nxt_queue_init(&router->sockets);
1855
1856 return NXT_OK;
1857
1858app_fail:
1859
1860 nxt_mp_destroy(app_mp);
1861
1862fail:
1863
1864 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1865
1866 nxt_queue_remove(&app->link);
1867 nxt_thread_mutex_destroy(&app->mutex);
1868 nxt_mp_destroy(app->mem_pool);
1869
1870 } nxt_queue_loop;
1871
1872 return NXT_ERROR;
1873}
1874
1875
1876#if (NXT_TLS)
1877
1878static nxt_int_t
1879nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
1880 nxt_conf_value_t *value, nxt_socket_conf_t *skcf,
1881 nxt_tls_init_t *tls_init, nxt_bool_t last)
1882{
1883 nxt_router_tlssock_t *tls;
1884
1885 tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t));
1886 if (nxt_slow_path(tls == NULL)) {
1887 return NXT_ERROR;
1888 }
1889
1890 tls->tls_init = tls_init;
1891 tls->socket_conf = skcf;
1892 tls->temp_conf = tmcf;
1893 tls->last = last;
1894 nxt_conf_get_string(value, &tls->name);
1895
1896 nxt_queue_insert_tail(&tmcf->tls, &tls->link);
1897
1898 return NXT_OK;
1899}
1900
1901#endif
1902
1903
1904static nxt_int_t
1905nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
1906 nxt_conf_value_t *conf)
1907{
1908 uint32_t next, i;
1909 nxt_mp_t *mp;
1910 nxt_str_t *type, exten, str;
1911 nxt_int_t ret;
1912 nxt_uint_t exts;
1913 nxt_conf_value_t *mtypes_conf, *ext_conf, *value;
1914
1915 static nxt_str_t mtypes_path = nxt_string("/mime_types");
1916
1917 mp = rtcf->mem_pool;
1918
1919 ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
1920 if (nxt_slow_path(ret != NXT_OK)) {
1921 return NXT_ERROR;
1922 }
1923
1924 if (conf == NULL) {
1925 return NXT_OK;
1926 }
1927
1928 mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
1929
1930 if (mtypes_conf != NULL) {
1931 next = 0;
1932
1933 for ( ;; ) {
1934 ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
1935
1936 if (ext_conf == NULL) {
1937 break;
1938 }
1939
1940 type = nxt_str_dup(mp, NULL, &str);
1941 if (nxt_slow_path(type == NULL)) {
1942 return NXT_ERROR;
1943 }
1944
1945 if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
1946 nxt_conf_get_string(ext_conf, &str);
1947
1948 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
1949 return NXT_ERROR;
1950 }
1951
1952 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
1953 &exten, type);
1954 if (nxt_slow_path(ret != NXT_OK)) {
1955 return NXT_ERROR;
1956 }
1957
1958 continue;
1959 }
1960
1961 exts = nxt_conf_array_elements_count(ext_conf);
1962
1963 for (i = 0; i < exts; i++) {
1964 value = nxt_conf_get_array_element(ext_conf, i);
1965
1966 nxt_conf_get_string(value, &str);
1967
1968 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
1969 return NXT_ERROR;
1970 }
1971
1972 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
1973 &exten, type);
1974 if (nxt_slow_path(ret != NXT_OK)) {
1975 return NXT_ERROR;
1976 }
1977 }
1978 }
1979 }
1980
1981 return NXT_OK;
1982}
1983
1984
1985static nxt_app_t *
1986nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
1987{
1988 nxt_app_t *app;
1989
1990 nxt_queue_each(app, queue, nxt_app_t, link) {
1991
1992 if (nxt_strstr_eq(name, &app->name)) {
1993 return app;
1994 }
1995
1996 } nxt_queue_loop;
1997
1998 return NULL;
1999}
2000
2001
2002static nxt_int_t
2003nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port)
2004{
2005 void *mem;
2006 nxt_int_t fd;
2007
2008 fd = nxt_shm_open(task, sizeof(nxt_app_queue_t));
2009 if (nxt_slow_path(fd == -1)) {
2010 return NXT_ERROR;
2011 }
2012
2013 mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t),
2014 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2015 if (nxt_slow_path(mem == MAP_FAILED)) {
2016 nxt_fd_close(fd);
2017
2018 return NXT_ERROR;
2019 }
2020
2021 nxt_app_queue_init(mem);
2022
2023 port->queue_fd = fd;
2024 port->queue = mem;
2025
2026 return NXT_OK;
2027}
2028
2029
2030static nxt_int_t
2031nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port)
2032{
2033 void *mem;
2034 nxt_int_t fd;
2035
2036 fd = nxt_shm_open(task, sizeof(nxt_port_queue_t));
2037 if (nxt_slow_path(fd == -1)) {
2038 return NXT_ERROR;
2039 }
2040
2041 mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
2042 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2043 if (nxt_slow_path(mem == MAP_FAILED)) {
2044 nxt_fd_close(fd);
2045
2046 return NXT_ERROR;
2047 }
2048
2049 nxt_port_queue_init(mem);
2050
2051 port->queue_fd = fd;
2052 port->queue = mem;
2053
2054 return NXT_OK;
2055}
2056
2057
2058static nxt_int_t
2059nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd)
2060{
2061 void *mem;
2062
2063 nxt_assert(fd != -1);
2064
2065 mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
2066 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2067 if (nxt_slow_path(mem == MAP_FAILED)) {
2068
2069 return NXT_ERROR;
2070 }
2071
2072 port->queue = mem;
2073
2074 return NXT_OK;
2075}
2076
2077
2078static const nxt_lvlhsh_proto_t nxt_router_apps_hash_proto nxt_aligned(64) = {
2079 NXT_LVLHSH_DEFAULT,
2080 nxt_router_apps_hash_test,
2081 nxt_mp_lvlhsh_alloc,
2082 nxt_mp_lvlhsh_free,
2083};
2084
2085
2086static nxt_int_t
2087nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
2088{
2089 nxt_app_t *app;
2090
2091 app = data;
2092
2093 return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED;
2094}
2095
2096
2097static nxt_int_t
2098nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app)
2099{
2100 nxt_lvlhsh_query_t lhq;
2101
2102 lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length);
2103 lhq.replace = 0;
2104 lhq.key = app->name;
2105 lhq.value = app;
2106 lhq.proto = &nxt_router_apps_hash_proto;
2107 lhq.pool = rtcf->mem_pool;
2108
2109 switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) {
2110
2111 case NXT_OK:
2112 return NXT_OK;
2113
2114 case NXT_DECLINED:
2115 nxt_thread_log_alert("router app hash adding failed: "
2116 "\"%V\" is already in hash", &lhq.key);
2117 /* Fall through. */
2118 default:
2119 return NXT_ERROR;
2120 }
2121}
2122
2123
2124static nxt_app_t *
2125nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name)
2126{
2127 nxt_lvlhsh_query_t lhq;
2128
2129 lhq.key_hash = nxt_djb_hash(name->start, name->length);
2130 lhq.key = *name;
2131 lhq.proto = &nxt_router_apps_hash_proto;
2132
2133 if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) {
2134 return NULL;
2135 }
2136
2137 return lhq.value;
2138}
2139
2140
2141static void
2142nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i)
2143{
2144 nxt_app_t *app;
2145 nxt_lvlhsh_each_t lhe;
2146
2147 nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto);
2148
2149 for ( ;; ) {
2150 app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe);
2151
2152 if (app == NULL) {
2153 break;
2154 }
2155
2156 nxt_router_app_use(task, app, i);
2157 }
2158}
2159
2160
2161typedef struct {
2162 nxt_app_t *app;
2163 nxt_int_t target;
2164} nxt_http_app_conf_t;
2165
2166
2167nxt_int_t
2168nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name,
2169 nxt_str_t *target, nxt_http_action_t *action)
2170{
2171 nxt_app_t *app;
2172 nxt_str_t *targets;
2173 nxt_uint_t i;
2174 nxt_http_app_conf_t *conf;
2175
2176 app = nxt_router_apps_hash_get(rtcf, name);
2177 if (app == NULL) {
2178 return NXT_DECLINED;
2179 }
2180
2181 conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t));
2182 if (nxt_slow_path(conf == NULL)) {
2183 return NXT_ERROR;
2184 }
2185
2186 action->handler = nxt_http_application_handler;
2187 action->u.conf = conf;
2188
2189 conf->app = app;
2190
2191 if (target != NULL && target->length != 0) {
2192 targets = app->targets;
2193
2194 for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++);
2195
2196 conf->target = i;
2197
2198 } else {
2199 conf->target = 0;
2200 }
2201
2202 return NXT_OK;
2203}
2204
2205
2206static nxt_socket_conf_t *
2207nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2208 nxt_str_t *name)
2209{
2210 size_t size;
2211 nxt_int_t ret;
2212 nxt_bool_t wildcard;
2213 nxt_sockaddr_t *sa;
2214 nxt_socket_conf_t *skcf;
2215 nxt_listen_socket_t *ls;
2216
2217 sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
2218 if (nxt_slow_path(sa == NULL)) {
2219 nxt_alert(task, "invalid listener \"%V\"", name);
2220 return NULL;
2221 }
2222
2223 sa->type = SOCK_STREAM;
2224
2225 nxt_debug(task, "router listener: \"%*s\"",
2226 (size_t) sa->length, nxt_sockaddr_start(sa));
2227
2228 skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
2229 if (nxt_slow_path(skcf == NULL)) {
2230 return NULL;
2231 }
2232
2233 size = nxt_sockaddr_size(sa);
2234
2235 ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
2236
2237 if (ret != NXT_OK) {
2238
2239 ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
2240 if (nxt_slow_path(ls == NULL)) {
2241 return NULL;
2242 }
2243
2244 skcf->listen = ls;
2245
2246 ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
2247 nxt_memcpy(ls->sockaddr, sa, size);
2248
2249 nxt_listen_socket_remote_size(ls);
2250
2251 ls->socket = -1;
2252 ls->backlog = NXT_LISTEN_BACKLOG;
2253 ls->flags = NXT_NONBLOCK;
2254 ls->read_after_accept = 1;
2255 }
2256
2257 switch (sa->u.sockaddr.sa_family) {
2258#if (NXT_HAVE_UNIX_DOMAIN)
2259 case AF_UNIX:
2260 wildcard = 0;
2261 break;
2262#endif
2263#if (NXT_INET6)
2264 case AF_INET6:
2265 wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
2266 break;
2267#endif
2268 case AF_INET:
2269 default:
2270 wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
2271 break;
2272 }
2273
2274 if (!wildcard) {
2275 skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
2276 if (nxt_slow_path(skcf->sockaddr == NULL)) {
2277 return NULL;
2278 }
2279
2280 nxt_memcpy(skcf->sockaddr, sa, size);
2281 }
2282
2283 return skcf;
2284}
2285
2286
2287static nxt_int_t
2288nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
2289 nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
2290{
2291 nxt_router_t *router;
2292 nxt_queue_link_t *qlk;
2293 nxt_socket_conf_t *skcf;
2294
2295 router = tmcf->router_conf->router;
2296
2297 for (qlk = nxt_queue_first(&router->sockets);
2298 qlk != nxt_queue_tail(&router->sockets);
2299 qlk = nxt_queue_next(qlk))
2300 {
2301 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2302
2303 if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2304 nskcf->listen = skcf->listen;
2305
2306 nxt_queue_remove(qlk);
2307 nxt_queue_insert_tail(&keeping_sockets, qlk);
2308
2309 nxt_queue_insert_tail(&updating_sockets, &nskcf->link);
2310
2311 return NXT_OK;
2312 }
2313 }
2314
2315 nxt_queue_insert_tail(&pending_sockets, &nskcf->link);
2316
2317 return NXT_DECLINED;
2318}
2319
2320
2321static void
2322nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2323 nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2324{
2325 size_t size;
2326 uint32_t stream;
2327 nxt_int_t ret;
2328 nxt_buf_t *b;
2329 nxt_port_t *main_port, *router_port;
2330 nxt_runtime_t *rt;
2331 nxt_socket_rpc_t *rpc;
2332
2333 rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2334 if (rpc == NULL) {
2335 goto fail;
2336 }
2337
2338 rpc->socket_conf = skcf;
2339 rpc->temp_conf = tmcf;
2340
2341 size = nxt_sockaddr_size(skcf->listen->sockaddr);
2342
2343 b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2344 if (b == NULL) {
2345 goto fail;
2346 }
2347
2348 b->completion_handler = nxt_router_dummy_buf_completion;
2349
2350 b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2351
2352 rt = task->thread->runtime;
2353 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2354 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2355
2356 stream = nxt_port_rpc_register_handler(task, router_port,
2357 nxt_router_listen_socket_ready,
2358 nxt_router_listen_socket_error,
2359 main_port->pid, rpc);
2360 if (nxt_slow_path(stream == 0)) {
2361 goto fail;
2362 }
2363
2364 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2365 stream, router_port->id, b);
2366
2367 if (nxt_slow_path(ret != NXT_OK)) {
2368 nxt_port_rpc_cancel(task, router_port, stream);
2369 goto fail;
2370 }
2371
2372 return;
2373
2374fail:
2375
2376 nxt_router_conf_error(task, tmcf);
2377}
2378
2379
2380static void
2381nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2382 void *data)
2383{
2384 nxt_int_t ret;
2385 nxt_socket_t s;
2386 nxt_socket_rpc_t *rpc;
2387
2388 rpc = data;
2389
2390 s = msg->fd[0];
2391
2392 ret = nxt_socket_nonblocking(task, s);
2393 if (nxt_slow_path(ret != NXT_OK)) {
2394 goto fail;
2395 }
2396
2397 nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2398
2399 ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2400 if (nxt_slow_path(ret != NXT_OK)) {
2401 goto fail;
2402 }
2403
2404 rpc->socket_conf->listen->socket = s;
2405
2406 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2407 nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2408
2409 return;
2410
2411fail:
2412
2413 nxt_socket_close(task, s);
2414
2415 nxt_router_conf_error(task, rpc->temp_conf);
2416}
2417
2418
2419static void
2420nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2421 void *data)
2422{
2423 nxt_socket_rpc_t *rpc;
2424 nxt_router_temp_conf_t *tmcf;
2425
2426 rpc = data;
2427 tmcf = rpc->temp_conf;
2428
2429#if 0
2430 u_char *p;
2431 size_t size;
2432 uint8_t error;
2433 nxt_buf_t *in, *out;
2434 nxt_sockaddr_t *sa;
2435
2436 static nxt_str_t socket_errors[] = {
2437 nxt_string("ListenerSystem"),
2438 nxt_string("ListenerNoIPv6"),
2439 nxt_string("ListenerPort"),
2440 nxt_string("ListenerInUse"),
2441 nxt_string("ListenerNoAddress"),
2442 nxt_string("ListenerNoAccess"),
2443 nxt_string("ListenerPath"),
2444 };
2445
2446 sa = rpc->socket_conf->listen->sockaddr;
2447
2448 in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2449
2450 if (nxt_slow_path(in == NULL)) {
2451 return;
2452 }
2453
2454 p = in->mem.pos;
2455
2456 error = *p++;
2457
2458 size = nxt_length("listen socket error: ")
2459 + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2460 + sa->length + socket_errors[error].length + (in->mem.free - p);
2461
2462 out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2463 if (nxt_slow_path(out == NULL)) {
2464 return;
2465 }
2466
2467 out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2468 "listen socket error: "
2469 "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2470 (size_t) sa->length, nxt_sockaddr_start(sa),
2471 &socket_errors[error], in->mem.free - p, p);
2472
2473 nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2474#endif
2475
2476 nxt_router_conf_error(task, tmcf);
2477}
2478
2479
2480#if (NXT_TLS)
2481
2482static void
2483nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2484 void *data)
2485{
2486 nxt_mp_t *mp;
2487 nxt_int_t ret;
2488 nxt_tls_conf_t *tlscf;
2489 nxt_router_tlssock_t *tls;
2490 nxt_tls_bundle_conf_t *bundle;
2491 nxt_router_temp_conf_t *tmcf;
2492
2493 nxt_debug(task, "tls rpc handler");
2494
2495 tls = data;
2496 tmcf = tls->temp_conf;
2497
2498 if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2499 goto fail;
2500 }
2501
2502 mp = tmcf->router_conf->mem_pool;
2503
2504 if (tls->socket_conf->tls == NULL){
2505 tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2506 if (nxt_slow_path(tlscf == NULL)) {
2507 goto fail;
2508 }
2509
2510 tlscf->no_wait_shutdown = 1;
2511 tls->socket_conf->tls = tlscf;
2512
2513 } else {
2514 tlscf = tls->socket_conf->tls;
2515 }
2516
2517 tls->tls_init->conf = tlscf;
2518
2519 bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t));
2520 if (nxt_slow_path(bundle == NULL)) {
2521 goto fail;
2522 }
2523
2524 if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) {
2525 goto fail;
2526 }
2527
2528 bundle->chain_file = msg->fd[0];
2529 bundle->next = tlscf->bundle;
2530 tlscf->bundle = bundle;
2531
2532 ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init,
2533 tls->last);
2534 if (nxt_slow_path(ret != NXT_OK)) {
2535 goto fail;
2536 }
2537
2538 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2539 nxt_router_conf_apply, task, tmcf, NULL);
2540 return;
2541
2542fail:
2543
2544 nxt_router_conf_error(task, tmcf);
2545}
2546
2547#endif
2548
2549
2550static void
2551nxt_router_app_rpc_create(nxt_task_t *task,
2552 nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2553{
2554 size_t size;
2555 uint32_t stream;
2556 nxt_int_t ret;
2557 nxt_buf_t *b;
2558 nxt_port_t *main_port, *router_port;
2559 nxt_runtime_t *rt;
2560 nxt_app_rpc_t *rpc;
2561
2562 rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2563 if (rpc == NULL) {
2564 goto fail;
2565 }
2566
2567 rpc->app = app;
2568 rpc->temp_conf = tmcf;
2569
2570 nxt_debug(task, "app '%V' prefork", &app->name);
2571
2572 size = app->name.length + 1 + app->conf.length;
2573
2574 b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2575 if (nxt_slow_path(b == NULL)) {
2576 goto fail;
2577 }
2578
2579 b->completion_handler = nxt_router_dummy_buf_completion;
2580
2581 nxt_buf_cpystr(b, &app->name);
2582 *b->mem.free++ = '\0';
2583 nxt_buf_cpystr(b, &app->conf);
2584
2585 rt = task->thread->runtime;
2586 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2587 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2588
2589 stream = nxt_port_rpc_register_handler(task, router_port,
2590 nxt_router_app_prefork_ready,
2591 nxt_router_app_prefork_error,
2592 -1, rpc);
2593 if (nxt_slow_path(stream == 0)) {
2594 goto fail;
2595 }
2596
2597 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
2598 -1, stream, router_port->id, b);
2599
2600 if (nxt_slow_path(ret != NXT_OK)) {
2601 nxt_port_rpc_cancel(task, router_port, stream);
2602 goto fail;
2603 }
2604
2605 app->pending_processes++;
2606
2607 return;
2608
2609fail:
2610
2611 nxt_router_conf_error(task, tmcf);
2612}
2613
2614
2615static void
2616nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2617 void *data)
2618{
2619 nxt_app_t *app;
2620 nxt_port_t *port;
2621 nxt_app_rpc_t *rpc;
2622 nxt_event_engine_t *engine;
2623
2624 rpc = data;
2625 app = rpc->app;
2626
2627 port = msg->u.new_port;
2628
2629 nxt_assert(port != NULL);
2630 nxt_assert(port->type == NXT_PROCESS_APP);
2631 nxt_assert(port->id == 0);
2632
2633 port->app = app;
2634 port->main_app_port = port;
2635
2636 app->pending_processes--;
2637 app->processes++;
2638 app->idle_processes++;
2639
2640 engine = task->thread->engine;
2641
2642 nxt_queue_insert_tail(&app->ports, &port->app_link);
2643 nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2644
2645 nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports",
2646 &app->name, port->pid, port->id);
2647
2648 nxt_port_hash_add(&app->port_hash, port);
2649 app->port_hash_count++;
2650
2651 port->idle_start = 0;
2652
2653 nxt_port_inc_use(port);
2654
2655 nxt_router_app_shared_port_send(task, port);
2656
2657 nxt_work_queue_add(&engine->fast_work_queue,
2658 nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2659}
2660
2661
2662static void
2663nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2664 void *data)
2665{
2666 nxt_app_t *app;
2667 nxt_app_rpc_t *rpc;
2668 nxt_router_temp_conf_t *tmcf;
2669
2670 rpc = data;
2671 app = rpc->app;
2672 tmcf = rpc->temp_conf;
2673
2674 nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2675 &app->name);
2676
2677 app->pending_processes--;
2678
2679 nxt_router_conf_error(task, tmcf);
2680}
2681
2682
2683static nxt_int_t
2684nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
2685 nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
2686{
2687 nxt_int_t ret;
2688 nxt_uint_t n, threads;
2689 nxt_queue_link_t *qlk;
2690 nxt_router_engine_conf_t *recf;
2691
2692 threads = tmcf->router_conf->threads;
2693
2694 tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
2695 sizeof(nxt_router_engine_conf_t));
2696 if (nxt_slow_path(tmcf->engines == NULL)) {
2697 return NXT_ERROR;
2698 }
2699
2700 n = 0;
2701
2702 for (qlk = nxt_queue_first(&router->engines);
2703 qlk != nxt_queue_tail(&router->engines);
2704 qlk = nxt_queue_next(qlk))
2705 {
2706 recf = nxt_array_zero_add(tmcf->engines);
2707 if (nxt_slow_path(recf == NULL)) {
2708 return NXT_ERROR;
2709 }
2710
2711 recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
2712
2713 if (n < threads) {
2714 recf->action = NXT_ROUTER_ENGINE_KEEP;
2715 ret = nxt_router_engine_conf_update(tmcf, recf);
2716
2717 } else {
2718 recf->action = NXT_ROUTER_ENGINE_DELETE;
2719 ret = nxt_router_engine_conf_delete(tmcf, recf);
2720 }
2721
2722 if (nxt_slow_path(ret != NXT_OK)) {
2723 return ret;
2724 }
2725
2726 n++;
2727 }
2728
2729 tmcf->new_threads = n;
2730
2731 while (n < threads) {
2732 recf = nxt_array_zero_add(tmcf->engines);
2733 if (nxt_slow_path(recf == NULL)) {
2734 return NXT_ERROR;
2735 }
2736
2737 recf->action = NXT_ROUTER_ENGINE_ADD;
2738
2739 recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
2740 if (nxt_slow_path(recf->engine == NULL)) {
2741 return NXT_ERROR;
2742 }
2743
2744 ret = nxt_router_engine_conf_create(tmcf, recf);
2745 if (nxt_slow_path(ret != NXT_OK)) {
2746 return ret;
2747 }
2748
2749 n++;
2750 }
2751
2752 return NXT_OK;
2753}
2754
2755
2756static nxt_int_t
2757nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2758 nxt_router_engine_conf_t *recf)
2759{
2760 nxt_int_t ret;
2761
2762 ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2763 nxt_router_listen_socket_create);
2764 if (nxt_slow_path(ret != NXT_OK)) {
2765 return ret;
2766 }
2767
2768 ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2769 nxt_router_listen_socket_create);
2770 if (nxt_slow_path(ret != NXT_OK)) {
2771 return ret;
2772 }
2773
2774 return ret;
2775}
2776
2777
2778static nxt_int_t
2779nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2780 nxt_router_engine_conf_t *recf)
2781{
2782 nxt_int_t ret;
2783
2784 ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2785 nxt_router_listen_socket_create);
2786 if (nxt_slow_path(ret != NXT_OK)) {
2787 return ret;
2788 }
2789
2790 ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2791 nxt_router_listen_socket_update);
2792 if (nxt_slow_path(ret != NXT_OK)) {
2793 return ret;
2794 }
2795
2796 ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
2797 if (nxt_slow_path(ret != NXT_OK)) {
2798 return ret;
2799 }
2800
2801 return ret;
2802}
2803
2804
2805static nxt_int_t
2806nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2807 nxt_router_engine_conf_t *recf)
2808{
2809 nxt_int_t ret;
2810
2811 ret = nxt_router_engine_quit(tmcf, recf);
2812 if (nxt_slow_path(ret != NXT_OK)) {
2813 return ret;
2814 }
2815
2816 ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets);
2817 if (nxt_slow_path(ret != NXT_OK)) {
2818 return ret;
2819 }
2820
2821 return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
2822}
2823
2824
2825static nxt_int_t
2826nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2827 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
2828 nxt_work_handler_t handler)
2829{
2830 nxt_int_t ret;
2831 nxt_joint_job_t *job;
2832 nxt_queue_link_t *qlk;
2833 nxt_socket_conf_t *skcf;
2834 nxt_socket_conf_joint_t *joint;
2835
2836 for (qlk = nxt_queue_first(sockets);
2837 qlk != nxt_queue_tail(sockets);
2838 qlk = nxt_queue_next(qlk))
2839 {
2840 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2841 if (nxt_slow_path(job == NULL)) {
2842 return NXT_ERROR;
2843 }
2844
2845 job->work.next = recf->jobs;
2846 recf->jobs = &job->work;
2847
2848 job->task = tmcf->engine->task;
2849 job->work.handler = handler;
2850 job->work.task = &job->task;
2851 job->work.obj = job;
2852 job->tmcf = tmcf;
2853
2854 tmcf->count++;
2855
2856 joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2857 sizeof(nxt_socket_conf_joint_t));
2858 if (nxt_slow_path(joint == NULL)) {
2859 return NXT_ERROR;
2860 }
2861
2862 job->work.data = joint;
2863
2864 ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams);
2865 if (nxt_slow_path(ret != NXT_OK)) {
2866 return ret;
2867 }
2868
2869 joint->count = 1;
2870
2871 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2872 skcf->count++;
2873 joint->socket_conf = skcf;
2874
2875 joint->engine = recf->engine;
2876 }
2877
2878 return NXT_OK;
2879}
2880
2881
2882static nxt_int_t
2883nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2884 nxt_router_engine_conf_t *recf)
2885{
2886 nxt_joint_job_t *job;
2887
2888 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2889 if (nxt_slow_path(job == NULL)) {
2890 return NXT_ERROR;
2891 }
2892
2893 job->work.next = recf->jobs;
2894 recf->jobs = &job->work;
2895
2896 job->task = tmcf->engine->task;
2897 job->work.handler = nxt_router_worker_thread_quit;
2898 job->work.task = &job->task;
2899 job->work.obj = NULL;
2900 job->work.data = NULL;
2901 job->tmcf = NULL;
2902
2903 return NXT_OK;
2904}
2905
2906
2907static nxt_int_t
2908nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
2909 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
2910{
2911 nxt_joint_job_t *job;
2912 nxt_queue_link_t *qlk;
2913
2914 for (qlk = nxt_queue_first(sockets);
2915 qlk != nxt_queue_tail(sockets);
2916 qlk = nxt_queue_next(qlk))
2917 {
2918 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2919 if (nxt_slow_path(job == NULL)) {
2920 return NXT_ERROR;
2921 }
2922
2923 job->work.next = recf->jobs;
2924 recf->jobs = &job->work;
2925
2926 job->task = tmcf->engine->task;
2927 job->work.handler = nxt_router_listen_socket_delete;
2928 job->work.task = &job->task;
2929 job->work.obj = job;
2930 job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2931 job->tmcf = tmcf;
2932
2933 tmcf->count++;
2934 }
2935
2936 return NXT_OK;
2937}
2938
2939
2940static nxt_int_t
2941nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
2942 nxt_router_temp_conf_t *tmcf)
2943{
2944 nxt_int_t ret;
2945 nxt_uint_t i, threads;
2946 nxt_router_engine_conf_t *recf;
2947
2948 recf = tmcf->engines->elts;
2949 threads = tmcf->router_conf->threads;
2950
2951 for (i = tmcf->new_threads; i < threads; i++) {
2952 ret = nxt_router_thread_create(task, rt, recf[i].engine);
2953 if (nxt_slow_path(ret != NXT_OK)) {
2954 return ret;
2955 }
2956 }
2957
2958 return NXT_OK;
2959}
2960
2961
2962static nxt_int_t
2963nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
2964 nxt_event_engine_t *engine)
2965{
2966 nxt_int_t ret;
2967 nxt_thread_link_t *link;
2968 nxt_thread_handle_t handle;
2969
2970 link = nxt_zalloc(sizeof(nxt_thread_link_t));
2971
2972 if (nxt_slow_path(link == NULL)) {
2973 return NXT_ERROR;
2974 }
2975
2976 link->start = nxt_router_thread_start;
2977 link->engine = engine;
2978 link->work.handler = nxt_router_thread_exit_handler;
2979 link->work.task = task;
2980 link->work.data = link;
2981
2982 nxt_queue_insert_tail(&rt->engines, &engine->link);
2983
2984 ret = nxt_thread_create(&handle, link);
2985
2986 if (nxt_slow_path(ret != NXT_OK)) {
2987 nxt_queue_remove(&engine->link);
2988 }
2989
2990 return ret;
2991}
2992
2993
2994static void
2995nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
2996 nxt_router_temp_conf_t *tmcf)
2997{
2998 nxt_app_t *app;
2999
3000 nxt_queue_each(app, &router->apps, nxt_app_t, link) {
3001
3002 nxt_router_app_unlink(task, app);
3003
3004 } nxt_queue_loop;
3005
3006 nxt_queue_add(&router->apps, &tmcf->previous);
3007 nxt_queue_add(&router->apps, &tmcf->apps);
3008}
3009
3010
3011static void
3012nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
3013{
3014 nxt_uint_t n;
3015 nxt_event_engine_t *engine;
3016 nxt_router_engine_conf_t *recf;
3017
3018 recf = tmcf->engines->elts;
3019
3020 for (n = tmcf->engines->nelts; n != 0; n--) {
3021 engine = recf->engine;
3022
3023 switch (recf->action) {
3024
3025 case NXT_ROUTER_ENGINE_KEEP:
3026 break;
3027
3028 case NXT_ROUTER_ENGINE_ADD:
3029 nxt_queue_insert_tail(&router->engines, &engine->link0);
3030 break;
3031
3032 case NXT_ROUTER_ENGINE_DELETE:
3033 nxt_queue_remove(&engine->link0);
3034 break;
3035 }
3036
3037 nxt_router_engine_post(engine, recf->jobs);
3038
3039 recf++;
3040 }
3041}
3042
3043
3044static void
3045nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
3046{
3047 nxt_work_t *work, *next;
3048
3049 for (work = jobs; work != NULL; work = next) {
3050 next = work->next;
3051 work->next = NULL;
3052
3053 nxt_event_engine_post(engine, work);
3054 }
3055}
3056
3057
3058static nxt_port_handlers_t nxt_router_app_port_handlers = {
3059 .rpc_error = nxt_port_rpc_handler,
3060 .mmap = nxt_port_mmap_handler,
3061 .data = nxt_port_rpc_handler,
3062 .oosm = nxt_router_oosm_handler,
3063 .req_headers_ack = nxt_port_rpc_handler,
3064};
3065
3066
3067static void
3068nxt_router_thread_start(void *data)
3069{
3070 nxt_int_t ret;
3071 nxt_port_t *port;
3072 nxt_task_t *task;
3073 nxt_work_t *work;
3074 nxt_thread_t *thread;
3075 nxt_thread_link_t *link;
3076 nxt_event_engine_t *engine;
3077
3078 link = data;
3079 engine = link->engine;
3080 task = &engine->task;
3081
3082 thread = nxt_thread();
3083
3084 nxt_event_engine_thread_adopt(engine);
3085
3086 /* STUB */
3087 thread->runtime = engine->task.thread->runtime;
3088
3089 engine->task.thread = thread;
3090 engine->task.log = thread->log;
3091 thread->engine = engine;
3092 thread->task = &engine->task;
3093#if 0
3094 thread->fiber = &engine->fibers->fiber;
3095#endif
3096
3097 engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
3098 if (nxt_slow_path(engine->mem_pool == NULL)) {
3099 return;
3100 }
3101
3102 port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
3103 NXT_PROCESS_ROUTER);
3104 if (nxt_slow_path(port == NULL)) {
3105 return;
3106 }
3107
3108 ret = nxt_port_socket_init(task, port, 0);
3109 if (nxt_slow_path(ret != NXT_OK)) {
3110 nxt_port_use(task, port, -1);
3111 return;
3112 }
3113
3114 ret = nxt_router_port_queue_init(task, port);
3115 if (nxt_slow_path(ret != NXT_OK)) {
3116 nxt_port_use(task, port, -1);
3117 return;
3118 }
3119
3120 engine->port = port;
3121
3122 nxt_port_enable(task, port, &nxt_router_app_port_handlers);
3123
3124 work = nxt_zalloc(sizeof(nxt_work_t));
3125 if (nxt_slow_path(work == NULL)) {
3126 return;
3127 }
3128
3129 work->handler = nxt_router_rt_add_port;
3130 work->task = link->work.task;
3131 work->obj = work;
3132 work->data = port;
3133
3134 nxt_event_engine_post(link->work.task->thread->engine, work);
3135
3136 nxt_event_engine_start(engine);
3137}
3138
3139
3140static void
3141nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data)
3142{
3143 nxt_int_t res;
3144 nxt_port_t *port;
3145 nxt_runtime_t *rt;
3146
3147 rt = task->thread->runtime;
3148 port = data;
3149
3150 nxt_free(obj);
3151
3152 res = nxt_port_hash_add(&rt->ports, port);
3153
3154 if (nxt_fast_path(res == NXT_OK)) {
3155 nxt_port_use(task, port, 1);
3156 }
3157}
3158
3159
3160static void
3161nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
3162{
3163 nxt_joint_job_t *job;
3164 nxt_socket_conf_t *skcf;
3165 nxt_listen_event_t *lev;
3166 nxt_listen_socket_t *ls;
3167 nxt_thread_spinlock_t *lock;
3168 nxt_socket_conf_joint_t *joint;
3169
3170 job = obj;
3171 joint = data;
3172
3173 nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
3174
3175 skcf = joint->socket_conf;
3176 ls = skcf->listen;
3177
3178 lev = nxt_listen_event(task, ls);
3179 if (nxt_slow_path(lev == NULL)) {
3180 nxt_router_listen_socket_release(task, skcf);
3181 return;
3182 }
3183
3184 lev->socket.data = joint;
3185
3186 lock = &skcf->router_conf->router->lock;
3187
3188 nxt_thread_spin_lock(lock);
3189 ls->count++;
3190 nxt_thread_spin_unlock(lock);
3191
3192 job->work.next = NULL;
3193 job->work.handler = nxt_router_conf_wait;
3194
3195 nxt_event_engine_post(job->tmcf->engine, &job->work);
3196}
3197
3198
3199nxt_inline nxt_listen_event_t *
3200nxt_router_listen_event(nxt_queue_t *listen_connections,
3201 nxt_socket_conf_t *skcf)
3202{
3203 nxt_socket_t fd;
3204 nxt_queue_link_t *qlk;
3205 nxt_listen_event_t *lev;
3206
3207 fd = skcf->listen->socket;
3208
3209 for (qlk = nxt_queue_first(listen_connections);
3210 qlk != nxt_queue_tail(listen_connections);
3211 qlk = nxt_queue_next(qlk))
3212 {
3213 lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
3214
3215 if (fd == lev->socket.fd) {
3216 return lev;
3217 }
3218 }
3219
3220 return NULL;
3221}
3222
3223
3224static void
3225nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
3226{
3227 nxt_joint_job_t *job;
3228 nxt_event_engine_t *engine;
3229 nxt_listen_event_t *lev;
3230 nxt_socket_conf_joint_t *joint, *old;
3231
3232 job = obj;
3233 joint = data;
3234
3235 engine = task->thread->engine;
3236
3237 nxt_queue_insert_tail(&engine->joints, &joint->link);
3238
3239 lev = nxt_router_listen_event(&engine->listen_connections,
3240 joint->socket_conf);
3241
3242 old = lev->socket.data;
3243 lev->socket.data = joint;
3244 lev->listen = joint->socket_conf->listen;
3245
3246 job->work.next = NULL;
3247 job->work.handler = nxt_router_conf_wait;
3248
3249 nxt_event_engine_post(job->tmcf->engine, &job->work);
3250
3251 /*
3252 * The task is allocated from configuration temporary
3253 * memory pool so it can be freed after engine post operation.
3254 */
3255
3256 nxt_router_conf_release(&engine->task, old);
3257}
3258
3259
3260static void
3261nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
3262{
3263 nxt_socket_conf_t *skcf;
3264 nxt_listen_event_t *lev;
3265 nxt_event_engine_t *engine;
3266 nxt_socket_conf_joint_t *joint;
3267
3268 skcf = data;
3269
3270 engine = task->thread->engine;
3271
3272 lev = nxt_router_listen_event(&engine->listen_connections, skcf);
3273
3274 nxt_fd_event_delete(engine, &lev->socket);
3275
3276 nxt_debug(task, "engine %p: listen socket delete: %d", engine,
3277 lev->socket.fd);
3278
3279 joint = lev->socket.data;
3280 joint->close_job = obj;
3281
3282 lev->timer.handler = nxt_router_listen_socket_close;
3283 lev->timer.work_queue = &engine->fast_work_queue;
3284
3285 nxt_timer_add(engine, &lev->timer, 0);
3286}
3287
3288
3289static void
3290nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
3291{
3292 nxt_event_engine_t *engine;
3293
3294 nxt_debug(task, "router worker thread quit");
3295
3296 engine = task->thread->engine;
3297
3298 engine->shutdown = 1;
3299
3300 if (nxt_queue_is_empty(&engine->joints)) {
3301 nxt_thread_exit(task->thread);
3302 }
3303}
3304
3305
3306static void
3307nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
3308{
3309 nxt_timer_t *timer;
3310 nxt_joint_job_t *job;
3311 nxt_listen_event_t *lev;
3312 nxt_socket_conf_joint_t *joint;
3313
3314 timer = obj;
3315 lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
3316
3317 nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
3318 lev->socket.fd);
3319
3320 nxt_queue_remove(&lev->link);
3321
3322 joint = lev->socket.data;
3323 lev->socket.data = NULL;
3324
3325 /* 'task' refers to lev->task and we cannot use after nxt_free() */
3326 task = &task->thread->engine->task;
3327
3328 nxt_router_listen_socket_release(task, joint->socket_conf);
3329
3330 job = joint->close_job;
3331 job->work.next = NULL;
3332 job->work.handler = nxt_router_conf_wait;
3333
3334 nxt_event_engine_post(job->tmcf->engine, &job->work);
3335
3336 nxt_router_listen_event_release(task, lev, joint);
3337}
3338
3339
3340static void
3341nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
3342{
3343 nxt_listen_socket_t *ls;
3344 nxt_thread_spinlock_t *lock;
3345
3346 ls = skcf->listen;
3347 lock = &skcf->router_conf->router->lock;
3348
3349 nxt_thread_spin_lock(lock);
3350
3351 nxt_debug(task, "engine %p: listen socket release: ls->count %D",
3352 task->thread->engine, ls->count);
3353
3354 if (--ls->count != 0) {
3355 ls = NULL;
3356 }
3357
3358 nxt_thread_spin_unlock(lock);
3359
3360 if (ls != NULL) {
3361 nxt_socket_close(task, ls->socket);
3362 nxt_free(ls);
3363 }
3364}
3365
3366
3367void
3368nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3369 nxt_socket_conf_joint_t *joint)
3370{
3371 nxt_event_engine_t *engine;
3372
3373 nxt_debug(task, "listen event count: %D", lev->count);
3374
3375 engine = task->thread->engine;
3376
3377 if (--lev->count == 0) {
3378 if (lev->next != NULL) {
3379 nxt_sockaddr_cache_free(engine, lev->next);
3380
3381 nxt_conn_free(task, lev->next);
3382 }
3383
3384 nxt_free(lev);
3385 }
3386
3387 if (joint != NULL) {
3388 nxt_router_conf_release(task, joint);
3389 }
3390
3391 if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3392 nxt_thread_exit(task->thread);
3393 }
3394}
3395
3396
3397void
3398nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
3399{
3400 nxt_socket_conf_t *skcf;
3401 nxt_router_conf_t *rtcf;
3402 nxt_thread_spinlock_t *lock;
3403
3404 nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
3405
3406 if (--joint->count != 0) {
3407 return;
3408 }
3409
3410 nxt_queue_remove(&joint->link);
3411
3412 /*
3413 * The joint content can not be safely used after the critical
3414 * section protected by the spinlock because its memory pool may
3415 * be already destroyed by another thread.
3416 */
3417 skcf = joint->socket_conf;
3418 rtcf = skcf->router_conf;
3419 lock = &rtcf->router->lock;
3420
3421 nxt_thread_spin_lock(lock);
3422
3423 nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3424 rtcf, rtcf->count);
3425
3426 if (--skcf->count != 0) {
3427 skcf = NULL;
3428 rtcf = NULL;
3429
3430 } else {
3431 nxt_queue_remove(&skcf->link);
3432
3433 if (--rtcf->count != 0) {
3434 rtcf = NULL;
3435 }
3436 }
3437
3438 nxt_thread_spin_unlock(lock);
3439
3440#if (NXT_TLS)
3441 if (skcf != NULL && skcf->tls != NULL) {
3442 task->thread->runtime->tls->server_free(task, skcf->tls);
3443 }
3444#endif
3445
3446 /* TODO remove engine->port */
3447
3448 if (rtcf != NULL) {
3449 nxt_debug(task, "old router conf is destroyed");
3450
3451 nxt_router_apps_hash_use(task, rtcf, -1);
3452
3453 nxt_router_access_log_release(task, lock, rtcf->access_log);
3454
3455 nxt_mp_thread_adopt(rtcf->mem_pool);
3456
3457 nxt_mp_destroy(rtcf->mem_pool);
3458 }
3459}
3460
3461
3462static void
3463nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3464 nxt_router_access_log_t *access_log)
3465{
3466 size_t size;
3467 u_char *buf, *p;
3468 nxt_off_t bytes;
3469
3470 static nxt_time_string_t date_cache = {
3471 (nxt_atomic_uint_t) -1,
3472 nxt_router_access_log_date,
3473 "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3474 nxt_length("31/Dec/1986:19:40:00 +0300"),
3475 NXT_THREAD_TIME_LOCAL,
3476 NXT_THREAD_TIME_SEC,
3477 };
3478
3479 size = r->remote->address_length
3480 + 6 /* ' - - [' */
3481 + date_cache.size
3482 + 3 /* '] "' */
3483 + r->method->length
3484 + 1 /* space */
3485 + r->target.length
3486 + 1 /* space */
3487 + r->version.length
3488 + 2 /* '" ' */
3489 + 3 /* status */
3490 + 1 /* space */
3491 + NXT_OFF_T_LEN
3492 + 2 /* ' "' */
3493 + (r->referer != NULL ? r->referer->value_length : 1)
3494 + 3 /* '" "' */
3495 + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3496 + 2 /* '"\n' */
3497 ;
3498
3499 buf = nxt_mp_nget(r->mem_pool, size);
3500 if (nxt_slow_path(buf == NULL)) {
3501 return;
3502 }
3503
3504 p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3505 r->remote->address_length);
3506
3507 p = nxt_cpymem(p, " - - [", 6);
3508
3509 p = nxt_thread_time_string(task->thread, &date_cache, p);
3510
3511 p = nxt_cpymem(p, "] \"", 3);
3512
3513 if (r->method->length != 0) {
3514 p = nxt_cpymem(p, r->method->start, r->method->length);
3515
3516 if (r->target.length != 0) {
3517 *p++ = ' ';
3518 p = nxt_cpymem(p, r->target.start, r->target.length);
3519
3520 if (r->version.length != 0) {
3521 *p++ = ' ';
3522 p = nxt_cpymem(p, r->version.start, r->version.length);
3523 }
3524 }
3525
3526 } else {
3527 *p++ = '-';
3528 }
3529
3530 p = nxt_cpymem(p, "\" ", 2);
3531
3532 p = nxt_sprintf(p, p + 3, "%03d", r->status);
3533
3534 *p++ = ' ';
3535
3536 bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3537
3538 p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3539
3540 p = nxt_cpymem(p, " \"", 2);
3541
3542 if (r->referer != NULL) {
3543 p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3544
3545 } else {
3546 *p++ = '-';
3547 }
3548
3549 p = nxt_cpymem(p, "\" \"", 3);
3550
3551 if (r->user_agent != NULL) {
3552 p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3553
3554 } else {
3555 *p++ = '-';
3556 }
3557
3558 p = nxt_cpymem(p, "\"\n", 2);
3559
3560 nxt_fd_write(access_log->fd, buf, p - buf);
3561}
3562
3563
3564static u_char *
3565nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3566 size_t size, const char *format)
3567{
3568 u_char sign;
3569 time_t gmtoff;
3570
3571 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3572 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3573
3574 gmtoff = nxt_timezone(tm) / 60;
3575
3576 if (gmtoff < 0) {
3577 gmtoff = -gmtoff;
3578 sign = '-';
3579
3580 } else {
3581 sign = '+';
3582 }
3583
3584 return nxt_sprintf(buf, buf + size, format,
3585 tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3586 tm->tm_hour, tm->tm_min, tm->tm_sec,
3587 sign, gmtoff / 60, gmtoff % 60);
3588}
3589
3590
3591static void
3592nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3593{
3594 uint32_t stream;
3595 nxt_int_t ret;
3596 nxt_buf_t *b;
3597 nxt_port_t *main_port, *router_port;
3598 nxt_runtime_t *rt;
3599 nxt_router_access_log_t *access_log;
3600
3601 access_log = tmcf->router_conf->access_log;
3602
3603 b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3604 if (nxt_slow_path(b == NULL)) {
3605 goto fail;
3606 }
3607
3608 b->completion_handler = nxt_router_dummy_buf_completion;
3609
3610 nxt_buf_cpystr(b, &access_log->path);
3611 *b->mem.free++ = '\0';
3612
3613 rt = task->thread->runtime;
3614 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3615 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3616
3617 stream = nxt_port_rpc_register_handler(task, router_port,
3618 nxt_router_access_log_ready,
3619 nxt_router_access_log_error,
3620 -1, tmcf);
3621 if (nxt_slow_path(stream == 0)) {
3622 goto fail;
3623 }
3624
3625 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3626 stream, router_port->id, b);
3627
3628 if (nxt_slow_path(ret != NXT_OK)) {
3629 nxt_port_rpc_cancel(task, router_port, stream);
3630 goto fail;
3631 }
3632
3633 return;
3634
3635fail:
3636
3637 nxt_router_conf_error(task, tmcf);
3638}
3639
3640
3641static void
3642nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3643 void *data)
3644{
3645 nxt_router_temp_conf_t *tmcf;
3646 nxt_router_access_log_t *access_log;
3647
3648 tmcf = data;
3649
3650 access_log = tmcf->router_conf->access_log;
3651
3652 access_log->fd = msg->fd[0];
3653
3654 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3655 nxt_router_conf_apply, task, tmcf, NULL);
3656}
3657
3658
3659static void
3660nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3661 void *data)
3662{
3663 nxt_router_temp_conf_t *tmcf;
3664
3665 tmcf = data;
3666
3667 nxt_router_conf_error(task, tmcf);
3668}
3669
3670
3671static void
3672nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3673 nxt_router_access_log_t *access_log)
3674{
3675 if (access_log == NULL) {
3676 return;
3677 }
3678
3679 nxt_thread_spin_lock(lock);
3680
3681 if (--access_log->count != 0) {
3682 access_log = NULL;
3683 }
3684
3685 nxt_thread_spin_unlock(lock);
3686
3687 if (access_log != NULL) {
3688
3689 if (access_log->fd != -1) {
3690 nxt_fd_close(access_log->fd);
3691 }
3692
3693 nxt_free(access_log);
3694 }
3695}
3696
3697
3698typedef struct {
3699 nxt_mp_t *mem_pool;
3700 nxt_router_access_log_t *access_log;
3701} nxt_router_access_log_reopen_t;
3702
3703
3704static void
3705nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3706{
3707 nxt_mp_t *mp;
3708 uint32_t stream;
3709 nxt_int_t ret;
3710 nxt_buf_t *b;
3711 nxt_port_t *main_port, *router_port;
3712 nxt_runtime_t *rt;
3713 nxt_router_access_log_t *access_log;
3714 nxt_router_access_log_reopen_t *reopen;
3715
3716 access_log = nxt_router->access_log;
3717
3718 if (access_log == NULL) {
3719 return;
3720 }
3721
3722 mp = nxt_mp_create(1024, 128, 256, 32);
3723 if (nxt_slow_path(mp == NULL)) {
3724 return;
3725 }
3726
3727 reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3728 if (nxt_slow_path(reopen == NULL)) {
3729 goto fail;
3730 }
3731
3732 reopen->mem_pool = mp;
3733 reopen->access_log = access_log;
3734
3735 b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3736 if (nxt_slow_path(b == NULL)) {
3737 goto fail;
3738 }
3739
3740 b->completion_handler = nxt_router_access_log_reopen_completion;
3741
3742 nxt_buf_cpystr(b, &access_log->path);
3743 *b->mem.free++ = '\0';
3744
3745 rt = task->thread->runtime;
3746 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3747 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3748
3749 stream = nxt_port_rpc_register_handler(task, router_port,
3750 nxt_router_access_log_reopen_ready,
3751 nxt_router_access_log_reopen_error,
3752 -1, reopen);
3753 if (nxt_slow_path(stream == 0)) {
3754 goto fail;
3755 }
3756
3757 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3758 stream, router_port->id, b);
3759
3760 if (nxt_slow_path(ret != NXT_OK)) {
3761 nxt_port_rpc_cancel(task, router_port, stream);
3762 goto fail;
3763 }
3764
3765 nxt_mp_retain(mp);
3766
3767 return;
3768
3769fail:
3770
3771 nxt_mp_destroy(mp);
3772}
3773
3774
3775static void
3776nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3777{
3778 nxt_mp_t *mp;
3779 nxt_buf_t *b;
3780
3781 b = obj;
3782 mp = b->data;
3783
3784 nxt_mp_release(mp);
3785}
3786
3787
3788static void
3789nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3790 void *data)
3791{
3792 nxt_router_access_log_t *access_log;
3793 nxt_router_access_log_reopen_t *reopen;
3794
3795 reopen = data;
3796
3797 access_log = reopen->access_log;
3798
3799 if (access_log == nxt_router->access_log) {
3800
3801 if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
3802 nxt_alert(task, "dup2(%FD, %FD) failed %E",
3803 msg->fd[0], access_log->fd, nxt_errno);
3804 }
3805 }
3806
3807 nxt_fd_close(msg->fd[0]);
3808 nxt_mp_release(reopen->mem_pool);
3809}
3810
3811
3812static void
3813nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3814 void *data)
3815{
3816 nxt_router_access_log_reopen_t *reopen;
3817
3818 reopen = data;
3819
3820 nxt_mp_release(reopen->mem_pool);
3821}
3822
3823
3824static void
3825nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
3826{
3827 nxt_port_t *port;
3828 nxt_thread_link_t *link;
3829 nxt_event_engine_t *engine;
3830 nxt_thread_handle_t handle;
3831
3832 handle = (nxt_thread_handle_t) (uintptr_t) obj;
3833 link = data;
3834
3835 nxt_thread_wait(handle);
3836
3837 engine = link->engine;
3838
3839 nxt_queue_remove(&engine->link);
3840
3841 port = engine->port;
3842
3843 // TODO notify all apps
3844
3845 port->engine = task->thread->engine;
3846 nxt_mp_thread_adopt(port->mem_pool);
3847 nxt_port_use(task, port, -1);
3848
3849 nxt_mp_thread_adopt(engine->mem_pool);
3850 nxt_mp_destroy(engine->mem_pool);
3851
3852 nxt_event_engine_free(engine);
3853
3854 nxt_free(link);
3855}
3856
3857
3858static void
3859nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3860 void *data)
3861{
3862 size_t b_size, count;
3863 nxt_int_t ret;
3864 nxt_app_t *app;
3865 nxt_buf_t *b, *next;
3866 nxt_port_t *app_port;
3867 nxt_unit_field_t *f;
3868 nxt_http_field_t *field;
3869 nxt_http_request_t *r;
3870 nxt_unit_response_t *resp;
3871 nxt_request_rpc_data_t *req_rpc_data;
3872
3873 req_rpc_data = data;
3874
3875 r = req_rpc_data->request;
3876 if (nxt_slow_path(r == NULL)) {
3877 return;
3878 }
3879
3880 if (r->error) {
3881 nxt_request_rpc_data_unlink(task, req_rpc_data);
3882 return;
3883 }
3884
3885 app = req_rpc_data->app;
3886 nxt_assert(app != NULL);
3887
3888 if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) {
3889 nxt_router_req_headers_ack_handler(task, msg, req_rpc_data);
3890
3891 return;
3892 }
3893
3894 b = (msg->size == 0) ? NULL : msg->buf;
3895
3896 if (msg->port_msg.last != 0) {
3897 nxt_debug(task, "router data create last buf");
3898
3899 nxt_buf_chain_add(&b, nxt_http_buf_last(r));
3900
3901 req_rpc_data->rpc_cancel = 0;
3902
3903 if (req_rpc_data->apr_action == NXT_APR_REQUEST_FAILED) {
3904 req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE;
3905 }
3906
3907 nxt_request_rpc_data_unlink(task, req_rpc_data);
3908
3909 } else {
3910 if (app->timeout != 0) {
3911 r->timer.handler = nxt_router_app_timeout;
3912 r->timer_data = req_rpc_data;
3913 nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
3914 }
3915 }
3916
3917 if (b == NULL) {
3918 return;
3919 }
3920
3921 if (msg->buf == b) {
3922 /* Disable instant buffer completion/re-using by port. */
3923 msg->buf = NULL;
3924 }
3925
3926 if (r->header_sent) {
3927 nxt_buf_chain_add(&r->out, b);
3928 nxt_http_request_send_body(task, r, NULL);
3929
3930 } else {
3931 b_size = nxt_buf_is_mem(b) ? nxt_buf_mem_used_size(&b->mem) : 0;
3932
3933 if (nxt_slow_path(b_size < sizeof(nxt_unit_response_t))) {
3934 nxt_alert(task, "response buffer too small: %z", b_size);
3935 goto fail;
3936 }
3937
3938 resp = (void *) b->mem.pos;
3939 count = (b_size - sizeof(nxt_unit_response_t))
3940 / sizeof(nxt_unit_field_t);
3941
3942 if (nxt_slow_path(count < resp->fields_count)) {
3943 nxt_alert(task, "response buffer too small for fields count: %D",
3944 resp->fields_count);
3945 goto fail;
3946 }
3947
3948 field = NULL;
3949
3950 for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
3951 if (f->skip) {
3952 continue;
3953 }
3954
3955 field = nxt_list_add(r->resp.fields);
3956
3957 if (nxt_slow_path(field == NULL)) {
3958 goto fail;
3959 }
3960
3961 field->hash = f->hash;
3962 field->skip = 0;
3963 field->hopbyhop = 0;
3964
3965 field->name_length = f->name_length;
3966 field->value_length = f->value_length;
3967 field->name = nxt_unit_sptr_get(&f->name);
3968 field->value = nxt_unit_sptr_get(&f->value);
3969
3970 ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
3971 if (nxt_slow_path(ret != NXT_OK)) {
3972 goto fail;
3973 }
3974
3975 nxt_debug(task, "header%s: %*s: %*s",
3976 (field->skip ? " skipped" : ""),
3977 (size_t) field->name_length, field->name,
3978 (size_t) field->value_length, field->value);
3979
3980 if (field->skip) {
3981 r->resp.fields->last->nelts--;
3982 }
3983 }
3984
3985 r->status = resp->status;
3986
3987 if (resp->piggyback_content_length != 0) {
3988 b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
3989 b->mem.free = b->mem.pos + resp->piggyback_content_length;
3990
3991 } else {
3992 b->mem.pos = b->mem.free;
3993 }
3994
3995 if (nxt_buf_mem_used_size(&b->mem) == 0) {
3996 next = b->next;
3997 b->next = NULL;
3998
3999 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4000 b->completion_handler, task, b, b->parent);
4001
4002 b = next;
4003 }
4004
4005 if (b != NULL) {
4006 nxt_buf_chain_add(&r->out, b);
4007 }
4008
4009 nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL);
4010
4011 if (r->websocket_handshake
4012 && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
4013 {
4014 app_port = req_rpc_data->app_port;
4015 if (nxt_slow_path(app_port == NULL)) {
4016 goto fail;
4017 }
4018
4019 nxt_thread_mutex_lock(&app->mutex);
4020
4021 app_port->main_app_port->active_websockets++;
4022
4023 nxt_thread_mutex_unlock(&app->mutex);
4024
4025 nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE);
4026 req_rpc_data->apr_action = NXT_APR_CLOSE;
4027
4028 nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream);
4029
4030 r->state = &nxt_http_websocket;
4031
4032 } else {
4033 r->state = &nxt_http_request_send_state;
4034 }
4035 }
4036
4037 return;
4038
4039fail:
4040
4041 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
4042
4043 nxt_request_rpc_data_unlink(task, req_rpc_data);
4044}
4045
4046
4047static void
4048nxt_router_req_headers_ack_handler(nxt_task_t *task,
4049 nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data)
4050{
4051 int res;
4052 nxt_app_t *app;
4053 nxt_buf_t *b;
4054 nxt_bool_t start_process, unlinked;
4055 nxt_port_t *app_port, *main_app_port, *idle_port;
4056 nxt_queue_link_t *idle_lnk;
4057 nxt_http_request_t *r;
4058
4059 nxt_debug(task, "stream #%uD: got ack from %PI:%d",
4060 req_rpc_data->stream,
4061 msg->port_msg.pid, msg->port_msg.reply_port);
4062
4063 nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data,
4064 msg->port_msg.pid);
4065
4066 app = req_rpc_data->app;
4067 r = req_rpc_data->request;
4068
4069 start_process = 0;
4070 unlinked = 0;
4071
4072 nxt_thread_mutex_lock(&app->mutex);
4073
4074 if (r->app_link.next != NULL) {
4075 nxt_queue_remove(&r->app_link);
4076 r->app_link.next = NULL;
4077
4078 unlinked = 1;
4079 }
4080
4081 app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid,
4082 msg->port_msg.reply_port);
4083 if (nxt_slow_path(app_port == NULL)) {
4084 nxt_thread_mutex_unlock(&app->mutex);
4085
4086 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4087
4088 if (unlinked) {
4089 nxt_mp_release(r->mem_pool);
4090 }
4091
4092 return;
4093 }
4094
4095 main_app_port = app_port->main_app_port;
4096
4097 if (nxt_queue_chk_remove(&main_app_port->idle_link)) {
4098 app->idle_processes--;
4099
4100 nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)",
4101 &app->name, main_app_port->pid, main_app_port->id,
4102 (main_app_port->idle_start ? "idle_ports" : "spare_ports"));
4103
4104 /* Check port was in 'spare_ports' using idle_start field. */
4105 if (main_app_port->idle_start == 0
4106 && app->idle_processes >= app->spare_processes)
4107 {
4108 /*
4109 * If there is a vacant space in spare ports,
4110 * move the last idle to spare_ports.
4111 */
4112 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4113
4114 idle_lnk = nxt_queue_last(&app->idle_ports);
4115 idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4116 nxt_queue_remove(idle_lnk);
4117
4118 nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4119
4120 idle_port->idle_start = 0;
4121
4122 nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
4123 "to spare_ports",
4124 &app->name, idle_port->pid, idle_port->id);
4125 }
4126
4127 if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
4128 app->pending_processes++;
4129 start_process = 1;
4130 }
4131 }
4132
4133 main_app_port->active_requests++;
4134
4135 nxt_port_inc_use(app_port);
4136
4137 nxt_thread_mutex_unlock(&app->mutex);
4138
4139 if (unlinked) {
4140 nxt_mp_release(r->mem_pool);
4141 }
4142
4143 if (start_process) {
4144 nxt_router_start_app_process(task, app);
4145 }
4146
4147 nxt_port_use(task, req_rpc_data->app_port, -1);
4148
4149 req_rpc_data->app_port = app_port;
4150
4151 b = req_rpc_data->msg_info.buf;
4152
4153 if (b != NULL) {
4154 /* First buffer is already sent. Start from second. */
4155 b = b->next;
4156
4157 req_rpc_data->msg_info.buf->next = NULL;
4158 }
4159
4160 if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) {
4161 nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream,
4162 req_rpc_data->msg_info.body_fd);
4163
4164 if (req_rpc_data->msg_info.body_fd != -1) {
4165 lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET);
4166 }
4167
4168 res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY,
4169 req_rpc_data->msg_info.body_fd,
4170 req_rpc_data->stream,
4171 task->thread->engine->port->id, b);
4172
4173 if (nxt_slow_path(res != NXT_OK)) {
4174 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4175 }
4176 }
4177
4178 if (app->timeout != 0) {
4179 r->timer.handler = nxt_router_app_timeout;
4180 r->timer_data = req_rpc_data;
4181 nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
4182 }
4183}
4184
4185
4186static const nxt_http_request_state_t nxt_http_request_send_state
4187 nxt_aligned(64) =
4188{
4189 .error_handler = nxt_http_request_error_handler,
4190};
4191
4192
4193static void
4194nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
4195{
4196 nxt_buf_t *out;
4197 nxt_http_request_t *r;
4198
4199 r = obj;
4200
4201 out = r->out;
4202
4203 if (out != NULL) {
4204 r->out = NULL;
4205 nxt_http_request_send(task, r, out);
4206 }
4207}
4208
4209
4210static void
4211nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4212 void *data)
4213{
4214 nxt_request_rpc_data_t *req_rpc_data;
4215
4216 req_rpc_data = data;
4217
4218 req_rpc_data->rpc_cancel = 0;
4219
4220 /* TODO cancel message and return if cancelled. */
4221 // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
4222
4223 if (req_rpc_data->request != NULL) {
4224 nxt_http_request_error(task, req_rpc_data->request,
4225 NXT_HTTP_SERVICE_UNAVAILABLE);
4226 }
4227
4228 nxt_request_rpc_data_unlink(task, req_rpc_data);
4229}
4230
4231
4232static void
4233nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4234 void *data)
4235{
1714 NXT_PROCESS_APP);
1715 if (nxt_slow_path(port == NULL)) {
1716 return NXT_ERROR;
1717 }
1718
1719 ret = nxt_port_socket_init(task, port, 0);
1720 if (nxt_slow_path(ret != NXT_OK)) {
1721 nxt_port_use(task, port, -1);
1722 return NXT_ERROR;
1723 }
1724
1725 ret = nxt_router_app_queue_init(task, port);
1726 if (nxt_slow_path(ret != NXT_OK)) {
1727 nxt_port_write_close(port);
1728 nxt_port_read_close(port);
1729 nxt_port_use(task, port, -1);
1730 return NXT_ERROR;
1731 }
1732
1733 nxt_port_write_enable(task, port);
1734 port->app = app;
1735
1736 app->shared_port = port;
1737
1738 nxt_thread_mutex_create(&app->outgoing.mutex);
1739 }
1740 }
1741
1742 routes_conf = nxt_conf_get_path(conf, &routes_path);
1743 if (nxt_fast_path(routes_conf != NULL)) {
1744 routes = nxt_http_routes_create(task, tmcf, routes_conf);
1745 if (nxt_slow_path(routes == NULL)) {
1746 return NXT_ERROR;
1747 }
1748 tmcf->router_conf->routes = routes;
1749 }
1750
1751 ret = nxt_upstreams_create(task, tmcf, conf);
1752 if (nxt_slow_path(ret != NXT_OK)) {
1753 return ret;
1754 }
1755
1756 http = nxt_conf_get_path(conf, &http_path);
1757#if 0
1758 if (http == NULL) {
1759 nxt_alert(task, "no \"http\" block");
1760 return NXT_ERROR;
1761 }
1762#endif
1763
1764 websocket = nxt_conf_get_path(conf, &websocket_path);
1765
1766 listeners = nxt_conf_get_path(conf, &listeners_path);
1767
1768 if (listeners != NULL) {
1769 next = 0;
1770
1771 for ( ;; ) {
1772 listener = nxt_conf_next_object_member(listeners, &name, &next);
1773 if (listener == NULL) {
1774 break;
1775 }
1776
1777 skcf = nxt_router_socket_conf(task, tmcf, &name);
1778 if (skcf == NULL) {
1779 goto fail;
1780 }
1781
1782 nxt_memzero(&lscf, sizeof(lscf));
1783
1784 ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf,
1785 nxt_nitems(nxt_router_listener_conf),
1786 &lscf);
1787 if (ret != NXT_OK) {
1788 nxt_alert(task, "listener map error");
1789 goto fail;
1790 }
1791
1792 nxt_debug(task, "application: %V", &lscf.application);
1793
1794 // STUB, default values if http block is not defined.
1795 skcf->header_buffer_size = 2048;
1796 skcf->large_header_buffer_size = 8192;
1797 skcf->large_header_buffers = 4;
1798 skcf->discard_unsafe_fields = 1;
1799 skcf->body_buffer_size = 16 * 1024;
1800 skcf->max_body_size = 8 * 1024 * 1024;
1801 skcf->proxy_header_buffer_size = 64 * 1024;
1802 skcf->proxy_buffer_size = 4096;
1803 skcf->proxy_buffers = 256;
1804 skcf->idle_timeout = 180 * 1000;
1805 skcf->header_read_timeout = 30 * 1000;
1806 skcf->body_read_timeout = 30 * 1000;
1807 skcf->send_timeout = 30 * 1000;
1808 skcf->proxy_timeout = 60 * 1000;
1809 skcf->proxy_send_timeout = 30 * 1000;
1810 skcf->proxy_read_timeout = 30 * 1000;
1811
1812 skcf->websocket_conf.max_frame_size = 1024 * 1024;
1813 skcf->websocket_conf.read_timeout = 60 * 1000;
1814 skcf->websocket_conf.keepalive_interval = 30 * 1000;
1815
1816 nxt_str_null(&skcf->body_temp_path);
1817
1818 if (http != NULL) {
1819 ret = nxt_conf_map_object(mp, http, nxt_router_http_conf,
1820 nxt_nitems(nxt_router_http_conf),
1821 skcf);
1822 if (ret != NXT_OK) {
1823 nxt_alert(task, "http map error");
1824 goto fail;
1825 }
1826 }
1827
1828 if (websocket != NULL) {
1829 ret = nxt_conf_map_object(mp, websocket,
1830 nxt_router_websocket_conf,
1831 nxt_nitems(nxt_router_websocket_conf),
1832 &skcf->websocket_conf);
1833 if (ret != NXT_OK) {
1834 nxt_alert(task, "websocket map error");
1835 goto fail;
1836 }
1837 }
1838
1839 t = &skcf->body_temp_path;
1840
1841 if (t->length == 0) {
1842 t->start = (u_char *) task->thread->runtime->tmp;
1843 t->length = nxt_strlen(t->start);
1844 }
1845
1846#if (NXT_TLS)
1847 certificate = nxt_conf_get_path(listener, &certificate_path);
1848
1849 if (certificate != NULL) {
1850 tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t));
1851 if (nxt_slow_path(tls_init == NULL)) {
1852 return NXT_ERROR;
1853 }
1854
1855 tls_init->cache_size = 0;
1856 tls_init->timeout = 300;
1857
1858 value = nxt_conf_get_path(listener, &conf_cache_path);
1859 if (value != NULL) {
1860 tls_init->cache_size = nxt_conf_get_number(value);
1861 }
1862
1863 value = nxt_conf_get_path(listener, &conf_timeout_path);
1864 if (value != NULL) {
1865 tls_init->timeout = nxt_conf_get_number(value);
1866 }
1867
1868 tls_init->conf_cmds = nxt_conf_get_path(listener,
1869 &conf_commands_path);
1870
1871 if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) {
1872 n = nxt_conf_array_elements_count(certificate);
1873
1874 for (i = 0; i < n; i++) {
1875 value = nxt_conf_get_array_element(certificate, i);
1876
1877 nxt_assert(value != NULL);
1878
1879 ret = nxt_router_conf_tls_insert(tmcf, value, skcf,
1880 tls_init, i == 0);
1881 if (nxt_slow_path(ret != NXT_OK)) {
1882 goto fail;
1883 }
1884 }
1885
1886 } else {
1887 /* NXT_CONF_STRING */
1888 ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf,
1889 tls_init, 1);
1890 if (nxt_slow_path(ret != NXT_OK)) {
1891 goto fail;
1892 }
1893 }
1894 }
1895#endif
1896
1897 skcf->listen->handler = nxt_http_conn_init;
1898 skcf->router_conf = tmcf->router_conf;
1899 skcf->router_conf->count++;
1900
1901 if (lscf.pass.length != 0) {
1902 skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass);
1903
1904 /* COMPATIBILITY: listener application. */
1905 } else if (lscf.application.length > 0) {
1906 skcf->action = nxt_http_pass_application(task,
1907 tmcf->router_conf,
1908 &lscf.application);
1909 }
1910
1911 if (nxt_slow_path(skcf->action == NULL)) {
1912 goto fail;
1913 }
1914 }
1915 }
1916
1917 ret = nxt_http_routes_resolve(task, tmcf);
1918 if (nxt_slow_path(ret != NXT_OK)) {
1919 goto fail;
1920 }
1921
1922 value = nxt_conf_get_path(conf, &access_log_path);
1923
1924 if (value != NULL) {
1925 nxt_conf_get_string(value, &path);
1926
1927 access_log = router->access_log;
1928
1929 if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) {
1930 nxt_thread_spin_lock(&router->lock);
1931 access_log->count++;
1932 nxt_thread_spin_unlock(&router->lock);
1933
1934 } else {
1935 access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
1936 + path.length);
1937 if (access_log == NULL) {
1938 nxt_alert(task, "failed to allocate access log structure");
1939 goto fail;
1940 }
1941
1942 access_log->fd = -1;
1943 access_log->handler = &nxt_router_access_log_writer;
1944 access_log->count = 1;
1945
1946 access_log->path.length = path.length;
1947 access_log->path.start = (u_char *) access_log
1948 + sizeof(nxt_router_access_log_t);
1949
1950 nxt_memcpy(access_log->path.start, path.start, path.length);
1951 }
1952
1953 tmcf->router_conf->access_log = access_log;
1954 }
1955
1956 nxt_queue_add(&deleting_sockets, &router->sockets);
1957 nxt_queue_init(&router->sockets);
1958
1959 return NXT_OK;
1960
1961app_fail:
1962
1963 nxt_mp_destroy(app_mp);
1964
1965fail:
1966
1967 nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
1968
1969 nxt_queue_remove(&app->link);
1970 nxt_thread_mutex_destroy(&app->mutex);
1971 nxt_mp_destroy(app->mem_pool);
1972
1973 } nxt_queue_loop;
1974
1975 return NXT_ERROR;
1976}
1977
1978
1979#if (NXT_TLS)
1980
1981static nxt_int_t
1982nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
1983 nxt_conf_value_t *value, nxt_socket_conf_t *skcf,
1984 nxt_tls_init_t *tls_init, nxt_bool_t last)
1985{
1986 nxt_router_tlssock_t *tls;
1987
1988 tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t));
1989 if (nxt_slow_path(tls == NULL)) {
1990 return NXT_ERROR;
1991 }
1992
1993 tls->tls_init = tls_init;
1994 tls->socket_conf = skcf;
1995 tls->temp_conf = tmcf;
1996 tls->last = last;
1997 nxt_conf_get_string(value, &tls->name);
1998
1999 nxt_queue_insert_tail(&tmcf->tls, &tls->link);
2000
2001 return NXT_OK;
2002}
2003
2004#endif
2005
2006
2007static nxt_int_t
2008nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
2009 nxt_conf_value_t *conf)
2010{
2011 uint32_t next, i;
2012 nxt_mp_t *mp;
2013 nxt_str_t *type, exten, str;
2014 nxt_int_t ret;
2015 nxt_uint_t exts;
2016 nxt_conf_value_t *mtypes_conf, *ext_conf, *value;
2017
2018 static nxt_str_t mtypes_path = nxt_string("/mime_types");
2019
2020 mp = rtcf->mem_pool;
2021
2022 ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash);
2023 if (nxt_slow_path(ret != NXT_OK)) {
2024 return NXT_ERROR;
2025 }
2026
2027 if (conf == NULL) {
2028 return NXT_OK;
2029 }
2030
2031 mtypes_conf = nxt_conf_get_path(conf, &mtypes_path);
2032
2033 if (mtypes_conf != NULL) {
2034 next = 0;
2035
2036 for ( ;; ) {
2037 ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next);
2038
2039 if (ext_conf == NULL) {
2040 break;
2041 }
2042
2043 type = nxt_str_dup(mp, NULL, &str);
2044 if (nxt_slow_path(type == NULL)) {
2045 return NXT_ERROR;
2046 }
2047
2048 if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
2049 nxt_conf_get_string(ext_conf, &str);
2050
2051 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
2052 return NXT_ERROR;
2053 }
2054
2055 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
2056 &exten, type);
2057 if (nxt_slow_path(ret != NXT_OK)) {
2058 return NXT_ERROR;
2059 }
2060
2061 continue;
2062 }
2063
2064 exts = nxt_conf_array_elements_count(ext_conf);
2065
2066 for (i = 0; i < exts; i++) {
2067 value = nxt_conf_get_array_element(ext_conf, i);
2068
2069 nxt_conf_get_string(value, &str);
2070
2071 if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
2072 return NXT_ERROR;
2073 }
2074
2075 ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
2076 &exten, type);
2077 if (nxt_slow_path(ret != NXT_OK)) {
2078 return NXT_ERROR;
2079 }
2080 }
2081 }
2082 }
2083
2084 return NXT_OK;
2085}
2086
2087
2088static nxt_app_t *
2089nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
2090{
2091 nxt_app_t *app;
2092
2093 nxt_queue_each(app, queue, nxt_app_t, link) {
2094
2095 if (nxt_strstr_eq(name, &app->name)) {
2096 return app;
2097 }
2098
2099 } nxt_queue_loop;
2100
2101 return NULL;
2102}
2103
2104
2105static nxt_int_t
2106nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port)
2107{
2108 void *mem;
2109 nxt_int_t fd;
2110
2111 fd = nxt_shm_open(task, sizeof(nxt_app_queue_t));
2112 if (nxt_slow_path(fd == -1)) {
2113 return NXT_ERROR;
2114 }
2115
2116 mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t),
2117 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2118 if (nxt_slow_path(mem == MAP_FAILED)) {
2119 nxt_fd_close(fd);
2120
2121 return NXT_ERROR;
2122 }
2123
2124 nxt_app_queue_init(mem);
2125
2126 port->queue_fd = fd;
2127 port->queue = mem;
2128
2129 return NXT_OK;
2130}
2131
2132
2133static nxt_int_t
2134nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port)
2135{
2136 void *mem;
2137 nxt_int_t fd;
2138
2139 fd = nxt_shm_open(task, sizeof(nxt_port_queue_t));
2140 if (nxt_slow_path(fd == -1)) {
2141 return NXT_ERROR;
2142 }
2143
2144 mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
2145 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2146 if (nxt_slow_path(mem == MAP_FAILED)) {
2147 nxt_fd_close(fd);
2148
2149 return NXT_ERROR;
2150 }
2151
2152 nxt_port_queue_init(mem);
2153
2154 port->queue_fd = fd;
2155 port->queue = mem;
2156
2157 return NXT_OK;
2158}
2159
2160
2161static nxt_int_t
2162nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd)
2163{
2164 void *mem;
2165
2166 nxt_assert(fd != -1);
2167
2168 mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t),
2169 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2170 if (nxt_slow_path(mem == MAP_FAILED)) {
2171
2172 return NXT_ERROR;
2173 }
2174
2175 port->queue = mem;
2176
2177 return NXT_OK;
2178}
2179
2180
2181static const nxt_lvlhsh_proto_t nxt_router_apps_hash_proto nxt_aligned(64) = {
2182 NXT_LVLHSH_DEFAULT,
2183 nxt_router_apps_hash_test,
2184 nxt_mp_lvlhsh_alloc,
2185 nxt_mp_lvlhsh_free,
2186};
2187
2188
2189static nxt_int_t
2190nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
2191{
2192 nxt_app_t *app;
2193
2194 app = data;
2195
2196 return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED;
2197}
2198
2199
2200static nxt_int_t
2201nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app)
2202{
2203 nxt_lvlhsh_query_t lhq;
2204
2205 lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length);
2206 lhq.replace = 0;
2207 lhq.key = app->name;
2208 lhq.value = app;
2209 lhq.proto = &nxt_router_apps_hash_proto;
2210 lhq.pool = rtcf->mem_pool;
2211
2212 switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) {
2213
2214 case NXT_OK:
2215 return NXT_OK;
2216
2217 case NXT_DECLINED:
2218 nxt_thread_log_alert("router app hash adding failed: "
2219 "\"%V\" is already in hash", &lhq.key);
2220 /* Fall through. */
2221 default:
2222 return NXT_ERROR;
2223 }
2224}
2225
2226
2227static nxt_app_t *
2228nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name)
2229{
2230 nxt_lvlhsh_query_t lhq;
2231
2232 lhq.key_hash = nxt_djb_hash(name->start, name->length);
2233 lhq.key = *name;
2234 lhq.proto = &nxt_router_apps_hash_proto;
2235
2236 if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) {
2237 return NULL;
2238 }
2239
2240 return lhq.value;
2241}
2242
2243
2244static void
2245nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i)
2246{
2247 nxt_app_t *app;
2248 nxt_lvlhsh_each_t lhe;
2249
2250 nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto);
2251
2252 for ( ;; ) {
2253 app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe);
2254
2255 if (app == NULL) {
2256 break;
2257 }
2258
2259 nxt_router_app_use(task, app, i);
2260 }
2261}
2262
2263
2264typedef struct {
2265 nxt_app_t *app;
2266 nxt_int_t target;
2267} nxt_http_app_conf_t;
2268
2269
2270nxt_int_t
2271nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name,
2272 nxt_str_t *target, nxt_http_action_t *action)
2273{
2274 nxt_app_t *app;
2275 nxt_str_t *targets;
2276 nxt_uint_t i;
2277 nxt_http_app_conf_t *conf;
2278
2279 app = nxt_router_apps_hash_get(rtcf, name);
2280 if (app == NULL) {
2281 return NXT_DECLINED;
2282 }
2283
2284 conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t));
2285 if (nxt_slow_path(conf == NULL)) {
2286 return NXT_ERROR;
2287 }
2288
2289 action->handler = nxt_http_application_handler;
2290 action->u.conf = conf;
2291
2292 conf->app = app;
2293
2294 if (target != NULL && target->length != 0) {
2295 targets = app->targets;
2296
2297 for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++);
2298
2299 conf->target = i;
2300
2301 } else {
2302 conf->target = 0;
2303 }
2304
2305 return NXT_OK;
2306}
2307
2308
2309static nxt_socket_conf_t *
2310nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
2311 nxt_str_t *name)
2312{
2313 size_t size;
2314 nxt_int_t ret;
2315 nxt_bool_t wildcard;
2316 nxt_sockaddr_t *sa;
2317 nxt_socket_conf_t *skcf;
2318 nxt_listen_socket_t *ls;
2319
2320 sa = nxt_sockaddr_parse(tmcf->mem_pool, name);
2321 if (nxt_slow_path(sa == NULL)) {
2322 nxt_alert(task, "invalid listener \"%V\"", name);
2323 return NULL;
2324 }
2325
2326 sa->type = SOCK_STREAM;
2327
2328 nxt_debug(task, "router listener: \"%*s\"",
2329 (size_t) sa->length, nxt_sockaddr_start(sa));
2330
2331 skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t));
2332 if (nxt_slow_path(skcf == NULL)) {
2333 return NULL;
2334 }
2335
2336 size = nxt_sockaddr_size(sa);
2337
2338 ret = nxt_router_listen_socket_find(tmcf, skcf, sa);
2339
2340 if (ret != NXT_OK) {
2341
2342 ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size);
2343 if (nxt_slow_path(ls == NULL)) {
2344 return NULL;
2345 }
2346
2347 skcf->listen = ls;
2348
2349 ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t));
2350 nxt_memcpy(ls->sockaddr, sa, size);
2351
2352 nxt_listen_socket_remote_size(ls);
2353
2354 ls->socket = -1;
2355 ls->backlog = NXT_LISTEN_BACKLOG;
2356 ls->flags = NXT_NONBLOCK;
2357 ls->read_after_accept = 1;
2358 }
2359
2360 switch (sa->u.sockaddr.sa_family) {
2361#if (NXT_HAVE_UNIX_DOMAIN)
2362 case AF_UNIX:
2363 wildcard = 0;
2364 break;
2365#endif
2366#if (NXT_INET6)
2367 case AF_INET6:
2368 wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr);
2369 break;
2370#endif
2371 case AF_INET:
2372 default:
2373 wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY);
2374 break;
2375 }
2376
2377 if (!wildcard) {
2378 skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size);
2379 if (nxt_slow_path(skcf->sockaddr == NULL)) {
2380 return NULL;
2381 }
2382
2383 nxt_memcpy(skcf->sockaddr, sa, size);
2384 }
2385
2386 return skcf;
2387}
2388
2389
2390static nxt_int_t
2391nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf,
2392 nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa)
2393{
2394 nxt_router_t *router;
2395 nxt_queue_link_t *qlk;
2396 nxt_socket_conf_t *skcf;
2397
2398 router = tmcf->router_conf->router;
2399
2400 for (qlk = nxt_queue_first(&router->sockets);
2401 qlk != nxt_queue_tail(&router->sockets);
2402 qlk = nxt_queue_next(qlk))
2403 {
2404 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2405
2406 if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) {
2407 nskcf->listen = skcf->listen;
2408
2409 nxt_queue_remove(qlk);
2410 nxt_queue_insert_tail(&keeping_sockets, qlk);
2411
2412 nxt_queue_insert_tail(&updating_sockets, &nskcf->link);
2413
2414 return NXT_OK;
2415 }
2416 }
2417
2418 nxt_queue_insert_tail(&pending_sockets, &nskcf->link);
2419
2420 return NXT_DECLINED;
2421}
2422
2423
2424static void
2425nxt_router_listen_socket_rpc_create(nxt_task_t *task,
2426 nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf)
2427{
2428 size_t size;
2429 uint32_t stream;
2430 nxt_int_t ret;
2431 nxt_buf_t *b;
2432 nxt_port_t *main_port, *router_port;
2433 nxt_runtime_t *rt;
2434 nxt_socket_rpc_t *rpc;
2435
2436 rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
2437 if (rpc == NULL) {
2438 goto fail;
2439 }
2440
2441 rpc->socket_conf = skcf;
2442 rpc->temp_conf = tmcf;
2443
2444 size = nxt_sockaddr_size(skcf->listen->sockaddr);
2445
2446 b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2447 if (b == NULL) {
2448 goto fail;
2449 }
2450
2451 b->completion_handler = nxt_router_dummy_buf_completion;
2452
2453 b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
2454
2455 rt = task->thread->runtime;
2456 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2457 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2458
2459 stream = nxt_port_rpc_register_handler(task, router_port,
2460 nxt_router_listen_socket_ready,
2461 nxt_router_listen_socket_error,
2462 main_port->pid, rpc);
2463 if (nxt_slow_path(stream == 0)) {
2464 goto fail;
2465 }
2466
2467 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1,
2468 stream, router_port->id, b);
2469
2470 if (nxt_slow_path(ret != NXT_OK)) {
2471 nxt_port_rpc_cancel(task, router_port, stream);
2472 goto fail;
2473 }
2474
2475 return;
2476
2477fail:
2478
2479 nxt_router_conf_error(task, tmcf);
2480}
2481
2482
2483static void
2484nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2485 void *data)
2486{
2487 nxt_int_t ret;
2488 nxt_socket_t s;
2489 nxt_socket_rpc_t *rpc;
2490
2491 rpc = data;
2492
2493 s = msg->fd[0];
2494
2495 ret = nxt_socket_nonblocking(task, s);
2496 if (nxt_slow_path(ret != NXT_OK)) {
2497 goto fail;
2498 }
2499
2500 nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr);
2501
2502 ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG);
2503 if (nxt_slow_path(ret != NXT_OK)) {
2504 goto fail;
2505 }
2506
2507 rpc->socket_conf->listen->socket = s;
2508
2509 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2510 nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2511
2512 return;
2513
2514fail:
2515
2516 nxt_socket_close(task, s);
2517
2518 nxt_router_conf_error(task, rpc->temp_conf);
2519}
2520
2521
2522static void
2523nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2524 void *data)
2525{
2526 nxt_socket_rpc_t *rpc;
2527 nxt_router_temp_conf_t *tmcf;
2528
2529 rpc = data;
2530 tmcf = rpc->temp_conf;
2531
2532#if 0
2533 u_char *p;
2534 size_t size;
2535 uint8_t error;
2536 nxt_buf_t *in, *out;
2537 nxt_sockaddr_t *sa;
2538
2539 static nxt_str_t socket_errors[] = {
2540 nxt_string("ListenerSystem"),
2541 nxt_string("ListenerNoIPv6"),
2542 nxt_string("ListenerPort"),
2543 nxt_string("ListenerInUse"),
2544 nxt_string("ListenerNoAddress"),
2545 nxt_string("ListenerNoAccess"),
2546 nxt_string("ListenerPath"),
2547 };
2548
2549 sa = rpc->socket_conf->listen->sockaddr;
2550
2551 in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size);
2552
2553 if (nxt_slow_path(in == NULL)) {
2554 return;
2555 }
2556
2557 p = in->mem.pos;
2558
2559 error = *p++;
2560
2561 size = nxt_length("listen socket error: ")
2562 + nxt_length("{listener: \"\", code:\"\", message: \"\"}")
2563 + sa->length + socket_errors[error].length + (in->mem.free - p);
2564
2565 out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2566 if (nxt_slow_path(out == NULL)) {
2567 return;
2568 }
2569
2570 out->mem.free = nxt_sprintf(out->mem.free, out->mem.end,
2571 "listen socket error: "
2572 "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}",
2573 (size_t) sa->length, nxt_sockaddr_start(sa),
2574 &socket_errors[error], in->mem.free - p, p);
2575
2576 nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos);
2577#endif
2578
2579 nxt_router_conf_error(task, tmcf);
2580}
2581
2582
2583#if (NXT_TLS)
2584
2585static void
2586nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2587 void *data)
2588{
2589 nxt_mp_t *mp;
2590 nxt_int_t ret;
2591 nxt_tls_conf_t *tlscf;
2592 nxt_router_tlssock_t *tls;
2593 nxt_tls_bundle_conf_t *bundle;
2594 nxt_router_temp_conf_t *tmcf;
2595
2596 nxt_debug(task, "tls rpc handler");
2597
2598 tls = data;
2599 tmcf = tls->temp_conf;
2600
2601 if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2602 goto fail;
2603 }
2604
2605 mp = tmcf->router_conf->mem_pool;
2606
2607 if (tls->socket_conf->tls == NULL){
2608 tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
2609 if (nxt_slow_path(tlscf == NULL)) {
2610 goto fail;
2611 }
2612
2613 tlscf->no_wait_shutdown = 1;
2614 tls->socket_conf->tls = tlscf;
2615
2616 } else {
2617 tlscf = tls->socket_conf->tls;
2618 }
2619
2620 tls->tls_init->conf = tlscf;
2621
2622 bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t));
2623 if (nxt_slow_path(bundle == NULL)) {
2624 goto fail;
2625 }
2626
2627 if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) {
2628 goto fail;
2629 }
2630
2631 bundle->chain_file = msg->fd[0];
2632 bundle->next = tlscf->bundle;
2633 tlscf->bundle = bundle;
2634
2635 ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init,
2636 tls->last);
2637 if (nxt_slow_path(ret != NXT_OK)) {
2638 goto fail;
2639 }
2640
2641 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
2642 nxt_router_conf_apply, task, tmcf, NULL);
2643 return;
2644
2645fail:
2646
2647 nxt_router_conf_error(task, tmcf);
2648}
2649
2650#endif
2651
2652
2653static void
2654nxt_router_app_rpc_create(nxt_task_t *task,
2655 nxt_router_temp_conf_t *tmcf, nxt_app_t *app)
2656{
2657 size_t size;
2658 uint32_t stream;
2659 nxt_int_t ret;
2660 nxt_buf_t *b;
2661 nxt_port_t *main_port, *router_port;
2662 nxt_runtime_t *rt;
2663 nxt_app_rpc_t *rpc;
2664
2665 rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t));
2666 if (rpc == NULL) {
2667 goto fail;
2668 }
2669
2670 rpc->app = app;
2671 rpc->temp_conf = tmcf;
2672
2673 nxt_debug(task, "app '%V' prefork", &app->name);
2674
2675 size = app->name.length + 1 + app->conf.length;
2676
2677 b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0);
2678 if (nxt_slow_path(b == NULL)) {
2679 goto fail;
2680 }
2681
2682 b->completion_handler = nxt_router_dummy_buf_completion;
2683
2684 nxt_buf_cpystr(b, &app->name);
2685 *b->mem.free++ = '\0';
2686 nxt_buf_cpystr(b, &app->conf);
2687
2688 rt = task->thread->runtime;
2689 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2690 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2691
2692 stream = nxt_port_rpc_register_handler(task, router_port,
2693 nxt_router_app_prefork_ready,
2694 nxt_router_app_prefork_error,
2695 -1, rpc);
2696 if (nxt_slow_path(stream == 0)) {
2697 goto fail;
2698 }
2699
2700 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
2701 -1, stream, router_port->id, b);
2702
2703 if (nxt_slow_path(ret != NXT_OK)) {
2704 nxt_port_rpc_cancel(task, router_port, stream);
2705 goto fail;
2706 }
2707
2708 app->pending_processes++;
2709
2710 return;
2711
2712fail:
2713
2714 nxt_router_conf_error(task, tmcf);
2715}
2716
2717
2718static void
2719nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2720 void *data)
2721{
2722 nxt_app_t *app;
2723 nxt_port_t *port;
2724 nxt_app_rpc_t *rpc;
2725 nxt_event_engine_t *engine;
2726
2727 rpc = data;
2728 app = rpc->app;
2729
2730 port = msg->u.new_port;
2731
2732 nxt_assert(port != NULL);
2733 nxt_assert(port->type == NXT_PROCESS_APP);
2734 nxt_assert(port->id == 0);
2735
2736 port->app = app;
2737 port->main_app_port = port;
2738
2739 app->pending_processes--;
2740 app->processes++;
2741 app->idle_processes++;
2742
2743 engine = task->thread->engine;
2744
2745 nxt_queue_insert_tail(&app->ports, &port->app_link);
2746 nxt_queue_insert_tail(&app->spare_ports, &port->idle_link);
2747
2748 nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports",
2749 &app->name, port->pid, port->id);
2750
2751 nxt_port_hash_add(&app->port_hash, port);
2752 app->port_hash_count++;
2753
2754 port->idle_start = 0;
2755
2756 nxt_port_inc_use(port);
2757
2758 nxt_router_app_shared_port_send(task, port);
2759
2760 nxt_work_queue_add(&engine->fast_work_queue,
2761 nxt_router_conf_apply, task, rpc->temp_conf, NULL);
2762}
2763
2764
2765static void
2766nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2767 void *data)
2768{
2769 nxt_app_t *app;
2770 nxt_app_rpc_t *rpc;
2771 nxt_router_temp_conf_t *tmcf;
2772
2773 rpc = data;
2774 app = rpc->app;
2775 tmcf = rpc->temp_conf;
2776
2777 nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"",
2778 &app->name);
2779
2780 app->pending_processes--;
2781
2782 nxt_router_conf_error(task, tmcf);
2783}
2784
2785
2786static nxt_int_t
2787nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router,
2788 nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface)
2789{
2790 nxt_int_t ret;
2791 nxt_uint_t n, threads;
2792 nxt_queue_link_t *qlk;
2793 nxt_router_engine_conf_t *recf;
2794
2795 threads = tmcf->router_conf->threads;
2796
2797 tmcf->engines = nxt_array_create(tmcf->mem_pool, threads,
2798 sizeof(nxt_router_engine_conf_t));
2799 if (nxt_slow_path(tmcf->engines == NULL)) {
2800 return NXT_ERROR;
2801 }
2802
2803 n = 0;
2804
2805 for (qlk = nxt_queue_first(&router->engines);
2806 qlk != nxt_queue_tail(&router->engines);
2807 qlk = nxt_queue_next(qlk))
2808 {
2809 recf = nxt_array_zero_add(tmcf->engines);
2810 if (nxt_slow_path(recf == NULL)) {
2811 return NXT_ERROR;
2812 }
2813
2814 recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0);
2815
2816 if (n < threads) {
2817 recf->action = NXT_ROUTER_ENGINE_KEEP;
2818 ret = nxt_router_engine_conf_update(tmcf, recf);
2819
2820 } else {
2821 recf->action = NXT_ROUTER_ENGINE_DELETE;
2822 ret = nxt_router_engine_conf_delete(tmcf, recf);
2823 }
2824
2825 if (nxt_slow_path(ret != NXT_OK)) {
2826 return ret;
2827 }
2828
2829 n++;
2830 }
2831
2832 tmcf->new_threads = n;
2833
2834 while (n < threads) {
2835 recf = nxt_array_zero_add(tmcf->engines);
2836 if (nxt_slow_path(recf == NULL)) {
2837 return NXT_ERROR;
2838 }
2839
2840 recf->action = NXT_ROUTER_ENGINE_ADD;
2841
2842 recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0);
2843 if (nxt_slow_path(recf->engine == NULL)) {
2844 return NXT_ERROR;
2845 }
2846
2847 ret = nxt_router_engine_conf_create(tmcf, recf);
2848 if (nxt_slow_path(ret != NXT_OK)) {
2849 return ret;
2850 }
2851
2852 n++;
2853 }
2854
2855 return NXT_OK;
2856}
2857
2858
2859static nxt_int_t
2860nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf,
2861 nxt_router_engine_conf_t *recf)
2862{
2863 nxt_int_t ret;
2864
2865 ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2866 nxt_router_listen_socket_create);
2867 if (nxt_slow_path(ret != NXT_OK)) {
2868 return ret;
2869 }
2870
2871 ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2872 nxt_router_listen_socket_create);
2873 if (nxt_slow_path(ret != NXT_OK)) {
2874 return ret;
2875 }
2876
2877 return ret;
2878}
2879
2880
2881static nxt_int_t
2882nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf,
2883 nxt_router_engine_conf_t *recf)
2884{
2885 nxt_int_t ret;
2886
2887 ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets,
2888 nxt_router_listen_socket_create);
2889 if (nxt_slow_path(ret != NXT_OK)) {
2890 return ret;
2891 }
2892
2893 ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets,
2894 nxt_router_listen_socket_update);
2895 if (nxt_slow_path(ret != NXT_OK)) {
2896 return ret;
2897 }
2898
2899 ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
2900 if (nxt_slow_path(ret != NXT_OK)) {
2901 return ret;
2902 }
2903
2904 return ret;
2905}
2906
2907
2908static nxt_int_t
2909nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf,
2910 nxt_router_engine_conf_t *recf)
2911{
2912 nxt_int_t ret;
2913
2914 ret = nxt_router_engine_quit(tmcf, recf);
2915 if (nxt_slow_path(ret != NXT_OK)) {
2916 return ret;
2917 }
2918
2919 ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets);
2920 if (nxt_slow_path(ret != NXT_OK)) {
2921 return ret;
2922 }
2923
2924 return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets);
2925}
2926
2927
2928static nxt_int_t
2929nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf,
2930 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets,
2931 nxt_work_handler_t handler)
2932{
2933 nxt_int_t ret;
2934 nxt_joint_job_t *job;
2935 nxt_queue_link_t *qlk;
2936 nxt_socket_conf_t *skcf;
2937 nxt_socket_conf_joint_t *joint;
2938
2939 for (qlk = nxt_queue_first(sockets);
2940 qlk != nxt_queue_tail(sockets);
2941 qlk = nxt_queue_next(qlk))
2942 {
2943 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2944 if (nxt_slow_path(job == NULL)) {
2945 return NXT_ERROR;
2946 }
2947
2948 job->work.next = recf->jobs;
2949 recf->jobs = &job->work;
2950
2951 job->task = tmcf->engine->task;
2952 job->work.handler = handler;
2953 job->work.task = &job->task;
2954 job->work.obj = job;
2955 job->tmcf = tmcf;
2956
2957 tmcf->count++;
2958
2959 joint = nxt_mp_alloc(tmcf->router_conf->mem_pool,
2960 sizeof(nxt_socket_conf_joint_t));
2961 if (nxt_slow_path(joint == NULL)) {
2962 return NXT_ERROR;
2963 }
2964
2965 job->work.data = joint;
2966
2967 ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams);
2968 if (nxt_slow_path(ret != NXT_OK)) {
2969 return ret;
2970 }
2971
2972 joint->count = 1;
2973
2974 skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
2975 skcf->count++;
2976 joint->socket_conf = skcf;
2977
2978 joint->engine = recf->engine;
2979 }
2980
2981 return NXT_OK;
2982}
2983
2984
2985static nxt_int_t
2986nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf,
2987 nxt_router_engine_conf_t *recf)
2988{
2989 nxt_joint_job_t *job;
2990
2991 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
2992 if (nxt_slow_path(job == NULL)) {
2993 return NXT_ERROR;
2994 }
2995
2996 job->work.next = recf->jobs;
2997 recf->jobs = &job->work;
2998
2999 job->task = tmcf->engine->task;
3000 job->work.handler = nxt_router_worker_thread_quit;
3001 job->work.task = &job->task;
3002 job->work.obj = NULL;
3003 job->work.data = NULL;
3004 job->tmcf = NULL;
3005
3006 return NXT_OK;
3007}
3008
3009
3010static nxt_int_t
3011nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf,
3012 nxt_router_engine_conf_t *recf, nxt_queue_t *sockets)
3013{
3014 nxt_joint_job_t *job;
3015 nxt_queue_link_t *qlk;
3016
3017 for (qlk = nxt_queue_first(sockets);
3018 qlk != nxt_queue_tail(sockets);
3019 qlk = nxt_queue_next(qlk))
3020 {
3021 job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t));
3022 if (nxt_slow_path(job == NULL)) {
3023 return NXT_ERROR;
3024 }
3025
3026 job->work.next = recf->jobs;
3027 recf->jobs = &job->work;
3028
3029 job->task = tmcf->engine->task;
3030 job->work.handler = nxt_router_listen_socket_delete;
3031 job->work.task = &job->task;
3032 job->work.obj = job;
3033 job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link);
3034 job->tmcf = tmcf;
3035
3036 tmcf->count++;
3037 }
3038
3039 return NXT_OK;
3040}
3041
3042
3043static nxt_int_t
3044nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt,
3045 nxt_router_temp_conf_t *tmcf)
3046{
3047 nxt_int_t ret;
3048 nxt_uint_t i, threads;
3049 nxt_router_engine_conf_t *recf;
3050
3051 recf = tmcf->engines->elts;
3052 threads = tmcf->router_conf->threads;
3053
3054 for (i = tmcf->new_threads; i < threads; i++) {
3055 ret = nxt_router_thread_create(task, rt, recf[i].engine);
3056 if (nxt_slow_path(ret != NXT_OK)) {
3057 return ret;
3058 }
3059 }
3060
3061 return NXT_OK;
3062}
3063
3064
3065static nxt_int_t
3066nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt,
3067 nxt_event_engine_t *engine)
3068{
3069 nxt_int_t ret;
3070 nxt_thread_link_t *link;
3071 nxt_thread_handle_t handle;
3072
3073 link = nxt_zalloc(sizeof(nxt_thread_link_t));
3074
3075 if (nxt_slow_path(link == NULL)) {
3076 return NXT_ERROR;
3077 }
3078
3079 link->start = nxt_router_thread_start;
3080 link->engine = engine;
3081 link->work.handler = nxt_router_thread_exit_handler;
3082 link->work.task = task;
3083 link->work.data = link;
3084
3085 nxt_queue_insert_tail(&rt->engines, &engine->link);
3086
3087 ret = nxt_thread_create(&handle, link);
3088
3089 if (nxt_slow_path(ret != NXT_OK)) {
3090 nxt_queue_remove(&engine->link);
3091 }
3092
3093 return ret;
3094}
3095
3096
3097static void
3098nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router,
3099 nxt_router_temp_conf_t *tmcf)
3100{
3101 nxt_app_t *app;
3102
3103 nxt_queue_each(app, &router->apps, nxt_app_t, link) {
3104
3105 nxt_router_app_unlink(task, app);
3106
3107 } nxt_queue_loop;
3108
3109 nxt_queue_add(&router->apps, &tmcf->previous);
3110 nxt_queue_add(&router->apps, &tmcf->apps);
3111}
3112
3113
3114static void
3115nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf)
3116{
3117 nxt_uint_t n;
3118 nxt_event_engine_t *engine;
3119 nxt_router_engine_conf_t *recf;
3120
3121 recf = tmcf->engines->elts;
3122
3123 for (n = tmcf->engines->nelts; n != 0; n--) {
3124 engine = recf->engine;
3125
3126 switch (recf->action) {
3127
3128 case NXT_ROUTER_ENGINE_KEEP:
3129 break;
3130
3131 case NXT_ROUTER_ENGINE_ADD:
3132 nxt_queue_insert_tail(&router->engines, &engine->link0);
3133 break;
3134
3135 case NXT_ROUTER_ENGINE_DELETE:
3136 nxt_queue_remove(&engine->link0);
3137 break;
3138 }
3139
3140 nxt_router_engine_post(engine, recf->jobs);
3141
3142 recf++;
3143 }
3144}
3145
3146
3147static void
3148nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs)
3149{
3150 nxt_work_t *work, *next;
3151
3152 for (work = jobs; work != NULL; work = next) {
3153 next = work->next;
3154 work->next = NULL;
3155
3156 nxt_event_engine_post(engine, work);
3157 }
3158}
3159
3160
3161static nxt_port_handlers_t nxt_router_app_port_handlers = {
3162 .rpc_error = nxt_port_rpc_handler,
3163 .mmap = nxt_port_mmap_handler,
3164 .data = nxt_port_rpc_handler,
3165 .oosm = nxt_router_oosm_handler,
3166 .req_headers_ack = nxt_port_rpc_handler,
3167};
3168
3169
3170static void
3171nxt_router_thread_start(void *data)
3172{
3173 nxt_int_t ret;
3174 nxt_port_t *port;
3175 nxt_task_t *task;
3176 nxt_work_t *work;
3177 nxt_thread_t *thread;
3178 nxt_thread_link_t *link;
3179 nxt_event_engine_t *engine;
3180
3181 link = data;
3182 engine = link->engine;
3183 task = &engine->task;
3184
3185 thread = nxt_thread();
3186
3187 nxt_event_engine_thread_adopt(engine);
3188
3189 /* STUB */
3190 thread->runtime = engine->task.thread->runtime;
3191
3192 engine->task.thread = thread;
3193 engine->task.log = thread->log;
3194 thread->engine = engine;
3195 thread->task = &engine->task;
3196#if 0
3197 thread->fiber = &engine->fibers->fiber;
3198#endif
3199
3200 engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64);
3201 if (nxt_slow_path(engine->mem_pool == NULL)) {
3202 return;
3203 }
3204
3205 port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid,
3206 NXT_PROCESS_ROUTER);
3207 if (nxt_slow_path(port == NULL)) {
3208 return;
3209 }
3210
3211 ret = nxt_port_socket_init(task, port, 0);
3212 if (nxt_slow_path(ret != NXT_OK)) {
3213 nxt_port_use(task, port, -1);
3214 return;
3215 }
3216
3217 ret = nxt_router_port_queue_init(task, port);
3218 if (nxt_slow_path(ret != NXT_OK)) {
3219 nxt_port_use(task, port, -1);
3220 return;
3221 }
3222
3223 engine->port = port;
3224
3225 nxt_port_enable(task, port, &nxt_router_app_port_handlers);
3226
3227 work = nxt_zalloc(sizeof(nxt_work_t));
3228 if (nxt_slow_path(work == NULL)) {
3229 return;
3230 }
3231
3232 work->handler = nxt_router_rt_add_port;
3233 work->task = link->work.task;
3234 work->obj = work;
3235 work->data = port;
3236
3237 nxt_event_engine_post(link->work.task->thread->engine, work);
3238
3239 nxt_event_engine_start(engine);
3240}
3241
3242
3243static void
3244nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data)
3245{
3246 nxt_int_t res;
3247 nxt_port_t *port;
3248 nxt_runtime_t *rt;
3249
3250 rt = task->thread->runtime;
3251 port = data;
3252
3253 nxt_free(obj);
3254
3255 res = nxt_port_hash_add(&rt->ports, port);
3256
3257 if (nxt_fast_path(res == NXT_OK)) {
3258 nxt_port_use(task, port, 1);
3259 }
3260}
3261
3262
3263static void
3264nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data)
3265{
3266 nxt_joint_job_t *job;
3267 nxt_socket_conf_t *skcf;
3268 nxt_listen_event_t *lev;
3269 nxt_listen_socket_t *ls;
3270 nxt_thread_spinlock_t *lock;
3271 nxt_socket_conf_joint_t *joint;
3272
3273 job = obj;
3274 joint = data;
3275
3276 nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link);
3277
3278 skcf = joint->socket_conf;
3279 ls = skcf->listen;
3280
3281 lev = nxt_listen_event(task, ls);
3282 if (nxt_slow_path(lev == NULL)) {
3283 nxt_router_listen_socket_release(task, skcf);
3284 return;
3285 }
3286
3287 lev->socket.data = joint;
3288
3289 lock = &skcf->router_conf->router->lock;
3290
3291 nxt_thread_spin_lock(lock);
3292 ls->count++;
3293 nxt_thread_spin_unlock(lock);
3294
3295 job->work.next = NULL;
3296 job->work.handler = nxt_router_conf_wait;
3297
3298 nxt_event_engine_post(job->tmcf->engine, &job->work);
3299}
3300
3301
3302nxt_inline nxt_listen_event_t *
3303nxt_router_listen_event(nxt_queue_t *listen_connections,
3304 nxt_socket_conf_t *skcf)
3305{
3306 nxt_socket_t fd;
3307 nxt_queue_link_t *qlk;
3308 nxt_listen_event_t *lev;
3309
3310 fd = skcf->listen->socket;
3311
3312 for (qlk = nxt_queue_first(listen_connections);
3313 qlk != nxt_queue_tail(listen_connections);
3314 qlk = nxt_queue_next(qlk))
3315 {
3316 lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link);
3317
3318 if (fd == lev->socket.fd) {
3319 return lev;
3320 }
3321 }
3322
3323 return NULL;
3324}
3325
3326
3327static void
3328nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data)
3329{
3330 nxt_joint_job_t *job;
3331 nxt_event_engine_t *engine;
3332 nxt_listen_event_t *lev;
3333 nxt_socket_conf_joint_t *joint, *old;
3334
3335 job = obj;
3336 joint = data;
3337
3338 engine = task->thread->engine;
3339
3340 nxt_queue_insert_tail(&engine->joints, &joint->link);
3341
3342 lev = nxt_router_listen_event(&engine->listen_connections,
3343 joint->socket_conf);
3344
3345 old = lev->socket.data;
3346 lev->socket.data = joint;
3347 lev->listen = joint->socket_conf->listen;
3348
3349 job->work.next = NULL;
3350 job->work.handler = nxt_router_conf_wait;
3351
3352 nxt_event_engine_post(job->tmcf->engine, &job->work);
3353
3354 /*
3355 * The task is allocated from configuration temporary
3356 * memory pool so it can be freed after engine post operation.
3357 */
3358
3359 nxt_router_conf_release(&engine->task, old);
3360}
3361
3362
3363static void
3364nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data)
3365{
3366 nxt_socket_conf_t *skcf;
3367 nxt_listen_event_t *lev;
3368 nxt_event_engine_t *engine;
3369 nxt_socket_conf_joint_t *joint;
3370
3371 skcf = data;
3372
3373 engine = task->thread->engine;
3374
3375 lev = nxt_router_listen_event(&engine->listen_connections, skcf);
3376
3377 nxt_fd_event_delete(engine, &lev->socket);
3378
3379 nxt_debug(task, "engine %p: listen socket delete: %d", engine,
3380 lev->socket.fd);
3381
3382 joint = lev->socket.data;
3383 joint->close_job = obj;
3384
3385 lev->timer.handler = nxt_router_listen_socket_close;
3386 lev->timer.work_queue = &engine->fast_work_queue;
3387
3388 nxt_timer_add(engine, &lev->timer, 0);
3389}
3390
3391
3392static void
3393nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data)
3394{
3395 nxt_event_engine_t *engine;
3396
3397 nxt_debug(task, "router worker thread quit");
3398
3399 engine = task->thread->engine;
3400
3401 engine->shutdown = 1;
3402
3403 if (nxt_queue_is_empty(&engine->joints)) {
3404 nxt_thread_exit(task->thread);
3405 }
3406}
3407
3408
3409static void
3410nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data)
3411{
3412 nxt_timer_t *timer;
3413 nxt_joint_job_t *job;
3414 nxt_listen_event_t *lev;
3415 nxt_socket_conf_joint_t *joint;
3416
3417 timer = obj;
3418 lev = nxt_timer_data(timer, nxt_listen_event_t, timer);
3419
3420 nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine,
3421 lev->socket.fd);
3422
3423 nxt_queue_remove(&lev->link);
3424
3425 joint = lev->socket.data;
3426 lev->socket.data = NULL;
3427
3428 /* 'task' refers to lev->task and we cannot use after nxt_free() */
3429 task = &task->thread->engine->task;
3430
3431 nxt_router_listen_socket_release(task, joint->socket_conf);
3432
3433 job = joint->close_job;
3434 job->work.next = NULL;
3435 job->work.handler = nxt_router_conf_wait;
3436
3437 nxt_event_engine_post(job->tmcf->engine, &job->work);
3438
3439 nxt_router_listen_event_release(task, lev, joint);
3440}
3441
3442
3443static void
3444nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf)
3445{
3446 nxt_listen_socket_t *ls;
3447 nxt_thread_spinlock_t *lock;
3448
3449 ls = skcf->listen;
3450 lock = &skcf->router_conf->router->lock;
3451
3452 nxt_thread_spin_lock(lock);
3453
3454 nxt_debug(task, "engine %p: listen socket release: ls->count %D",
3455 task->thread->engine, ls->count);
3456
3457 if (--ls->count != 0) {
3458 ls = NULL;
3459 }
3460
3461 nxt_thread_spin_unlock(lock);
3462
3463 if (ls != NULL) {
3464 nxt_socket_close(task, ls->socket);
3465 nxt_free(ls);
3466 }
3467}
3468
3469
3470void
3471nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
3472 nxt_socket_conf_joint_t *joint)
3473{
3474 nxt_event_engine_t *engine;
3475
3476 nxt_debug(task, "listen event count: %D", lev->count);
3477
3478 engine = task->thread->engine;
3479
3480 if (--lev->count == 0) {
3481 if (lev->next != NULL) {
3482 nxt_sockaddr_cache_free(engine, lev->next);
3483
3484 nxt_conn_free(task, lev->next);
3485 }
3486
3487 nxt_free(lev);
3488 }
3489
3490 if (joint != NULL) {
3491 nxt_router_conf_release(task, joint);
3492 }
3493
3494 if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) {
3495 nxt_thread_exit(task->thread);
3496 }
3497}
3498
3499
3500void
3501nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
3502{
3503 nxt_socket_conf_t *skcf;
3504 nxt_router_conf_t *rtcf;
3505 nxt_thread_spinlock_t *lock;
3506
3507 nxt_debug(task, "conf joint %p count: %D", joint, joint->count);
3508
3509 if (--joint->count != 0) {
3510 return;
3511 }
3512
3513 nxt_queue_remove(&joint->link);
3514
3515 /*
3516 * The joint content can not be safely used after the critical
3517 * section protected by the spinlock because its memory pool may
3518 * be already destroyed by another thread.
3519 */
3520 skcf = joint->socket_conf;
3521 rtcf = skcf->router_conf;
3522 lock = &rtcf->router->lock;
3523
3524 nxt_thread_spin_lock(lock);
3525
3526 nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count,
3527 rtcf, rtcf->count);
3528
3529 if (--skcf->count != 0) {
3530 skcf = NULL;
3531 rtcf = NULL;
3532
3533 } else {
3534 nxt_queue_remove(&skcf->link);
3535
3536 if (--rtcf->count != 0) {
3537 rtcf = NULL;
3538 }
3539 }
3540
3541 nxt_thread_spin_unlock(lock);
3542
3543#if (NXT_TLS)
3544 if (skcf != NULL && skcf->tls != NULL) {
3545 task->thread->runtime->tls->server_free(task, skcf->tls);
3546 }
3547#endif
3548
3549 /* TODO remove engine->port */
3550
3551 if (rtcf != NULL) {
3552 nxt_debug(task, "old router conf is destroyed");
3553
3554 nxt_router_apps_hash_use(task, rtcf, -1);
3555
3556 nxt_router_access_log_release(task, lock, rtcf->access_log);
3557
3558 nxt_mp_thread_adopt(rtcf->mem_pool);
3559
3560 nxt_mp_destroy(rtcf->mem_pool);
3561 }
3562}
3563
3564
3565static void
3566nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
3567 nxt_router_access_log_t *access_log)
3568{
3569 size_t size;
3570 u_char *buf, *p;
3571 nxt_off_t bytes;
3572
3573 static nxt_time_string_t date_cache = {
3574 (nxt_atomic_uint_t) -1,
3575 nxt_router_access_log_date,
3576 "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d",
3577 nxt_length("31/Dec/1986:19:40:00 +0300"),
3578 NXT_THREAD_TIME_LOCAL,
3579 NXT_THREAD_TIME_SEC,
3580 };
3581
3582 size = r->remote->address_length
3583 + 6 /* ' - - [' */
3584 + date_cache.size
3585 + 3 /* '] "' */
3586 + r->method->length
3587 + 1 /* space */
3588 + r->target.length
3589 + 1 /* space */
3590 + r->version.length
3591 + 2 /* '" ' */
3592 + 3 /* status */
3593 + 1 /* space */
3594 + NXT_OFF_T_LEN
3595 + 2 /* ' "' */
3596 + (r->referer != NULL ? r->referer->value_length : 1)
3597 + 3 /* '" "' */
3598 + (r->user_agent != NULL ? r->user_agent->value_length : 1)
3599 + 2 /* '"\n' */
3600 ;
3601
3602 buf = nxt_mp_nget(r->mem_pool, size);
3603 if (nxt_slow_path(buf == NULL)) {
3604 return;
3605 }
3606
3607 p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote),
3608 r->remote->address_length);
3609
3610 p = nxt_cpymem(p, " - - [", 6);
3611
3612 p = nxt_thread_time_string(task->thread, &date_cache, p);
3613
3614 p = nxt_cpymem(p, "] \"", 3);
3615
3616 if (r->method->length != 0) {
3617 p = nxt_cpymem(p, r->method->start, r->method->length);
3618
3619 if (r->target.length != 0) {
3620 *p++ = ' ';
3621 p = nxt_cpymem(p, r->target.start, r->target.length);
3622
3623 if (r->version.length != 0) {
3624 *p++ = ' ';
3625 p = nxt_cpymem(p, r->version.start, r->version.length);
3626 }
3627 }
3628
3629 } else {
3630 *p++ = '-';
3631 }
3632
3633 p = nxt_cpymem(p, "\" ", 2);
3634
3635 p = nxt_sprintf(p, p + 3, "%03d", r->status);
3636
3637 *p++ = ' ';
3638
3639 bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto);
3640
3641 p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes);
3642
3643 p = nxt_cpymem(p, " \"", 2);
3644
3645 if (r->referer != NULL) {
3646 p = nxt_cpymem(p, r->referer->value, r->referer->value_length);
3647
3648 } else {
3649 *p++ = '-';
3650 }
3651
3652 p = nxt_cpymem(p, "\" \"", 3);
3653
3654 if (r->user_agent != NULL) {
3655 p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length);
3656
3657 } else {
3658 *p++ = '-';
3659 }
3660
3661 p = nxt_cpymem(p, "\"\n", 2);
3662
3663 nxt_fd_write(access_log->fd, buf, p - buf);
3664}
3665
3666
3667static u_char *
3668nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
3669 size_t size, const char *format)
3670{
3671 u_char sign;
3672 time_t gmtoff;
3673
3674 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3675 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
3676
3677 gmtoff = nxt_timezone(tm) / 60;
3678
3679 if (gmtoff < 0) {
3680 gmtoff = -gmtoff;
3681 sign = '-';
3682
3683 } else {
3684 sign = '+';
3685 }
3686
3687 return nxt_sprintf(buf, buf + size, format,
3688 tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900,
3689 tm->tm_hour, tm->tm_min, tm->tm_sec,
3690 sign, gmtoff / 60, gmtoff % 60);
3691}
3692
3693
3694static void
3695nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
3696{
3697 uint32_t stream;
3698 nxt_int_t ret;
3699 nxt_buf_t *b;
3700 nxt_port_t *main_port, *router_port;
3701 nxt_runtime_t *rt;
3702 nxt_router_access_log_t *access_log;
3703
3704 access_log = tmcf->router_conf->access_log;
3705
3706 b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
3707 if (nxt_slow_path(b == NULL)) {
3708 goto fail;
3709 }
3710
3711 b->completion_handler = nxt_router_dummy_buf_completion;
3712
3713 nxt_buf_cpystr(b, &access_log->path);
3714 *b->mem.free++ = '\0';
3715
3716 rt = task->thread->runtime;
3717 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3718 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3719
3720 stream = nxt_port_rpc_register_handler(task, router_port,
3721 nxt_router_access_log_ready,
3722 nxt_router_access_log_error,
3723 -1, tmcf);
3724 if (nxt_slow_path(stream == 0)) {
3725 goto fail;
3726 }
3727
3728 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3729 stream, router_port->id, b);
3730
3731 if (nxt_slow_path(ret != NXT_OK)) {
3732 nxt_port_rpc_cancel(task, router_port, stream);
3733 goto fail;
3734 }
3735
3736 return;
3737
3738fail:
3739
3740 nxt_router_conf_error(task, tmcf);
3741}
3742
3743
3744static void
3745nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3746 void *data)
3747{
3748 nxt_router_temp_conf_t *tmcf;
3749 nxt_router_access_log_t *access_log;
3750
3751 tmcf = data;
3752
3753 access_log = tmcf->router_conf->access_log;
3754
3755 access_log->fd = msg->fd[0];
3756
3757 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
3758 nxt_router_conf_apply, task, tmcf, NULL);
3759}
3760
3761
3762static void
3763nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3764 void *data)
3765{
3766 nxt_router_temp_conf_t *tmcf;
3767
3768 tmcf = data;
3769
3770 nxt_router_conf_error(task, tmcf);
3771}
3772
3773
3774static void
3775nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
3776 nxt_router_access_log_t *access_log)
3777{
3778 if (access_log == NULL) {
3779 return;
3780 }
3781
3782 nxt_thread_spin_lock(lock);
3783
3784 if (--access_log->count != 0) {
3785 access_log = NULL;
3786 }
3787
3788 nxt_thread_spin_unlock(lock);
3789
3790 if (access_log != NULL) {
3791
3792 if (access_log->fd != -1) {
3793 nxt_fd_close(access_log->fd);
3794 }
3795
3796 nxt_free(access_log);
3797 }
3798}
3799
3800
3801typedef struct {
3802 nxt_mp_t *mem_pool;
3803 nxt_router_access_log_t *access_log;
3804} nxt_router_access_log_reopen_t;
3805
3806
3807static void
3808nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
3809{
3810 nxt_mp_t *mp;
3811 uint32_t stream;
3812 nxt_int_t ret;
3813 nxt_buf_t *b;
3814 nxt_port_t *main_port, *router_port;
3815 nxt_runtime_t *rt;
3816 nxt_router_access_log_t *access_log;
3817 nxt_router_access_log_reopen_t *reopen;
3818
3819 access_log = nxt_router->access_log;
3820
3821 if (access_log == NULL) {
3822 return;
3823 }
3824
3825 mp = nxt_mp_create(1024, 128, 256, 32);
3826 if (nxt_slow_path(mp == NULL)) {
3827 return;
3828 }
3829
3830 reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
3831 if (nxt_slow_path(reopen == NULL)) {
3832 goto fail;
3833 }
3834
3835 reopen->mem_pool = mp;
3836 reopen->access_log = access_log;
3837
3838 b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
3839 if (nxt_slow_path(b == NULL)) {
3840 goto fail;
3841 }
3842
3843 b->completion_handler = nxt_router_access_log_reopen_completion;
3844
3845 nxt_buf_cpystr(b, &access_log->path);
3846 *b->mem.free++ = '\0';
3847
3848 rt = task->thread->runtime;
3849 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
3850 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
3851
3852 stream = nxt_port_rpc_register_handler(task, router_port,
3853 nxt_router_access_log_reopen_ready,
3854 nxt_router_access_log_reopen_error,
3855 -1, reopen);
3856 if (nxt_slow_path(stream == 0)) {
3857 goto fail;
3858 }
3859
3860 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
3861 stream, router_port->id, b);
3862
3863 if (nxt_slow_path(ret != NXT_OK)) {
3864 nxt_port_rpc_cancel(task, router_port, stream);
3865 goto fail;
3866 }
3867
3868 nxt_mp_retain(mp);
3869
3870 return;
3871
3872fail:
3873
3874 nxt_mp_destroy(mp);
3875}
3876
3877
3878static void
3879nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
3880{
3881 nxt_mp_t *mp;
3882 nxt_buf_t *b;
3883
3884 b = obj;
3885 mp = b->data;
3886
3887 nxt_mp_release(mp);
3888}
3889
3890
3891static void
3892nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3893 void *data)
3894{
3895 nxt_router_access_log_t *access_log;
3896 nxt_router_access_log_reopen_t *reopen;
3897
3898 reopen = data;
3899
3900 access_log = reopen->access_log;
3901
3902 if (access_log == nxt_router->access_log) {
3903
3904 if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
3905 nxt_alert(task, "dup2(%FD, %FD) failed %E",
3906 msg->fd[0], access_log->fd, nxt_errno);
3907 }
3908 }
3909
3910 nxt_fd_close(msg->fd[0]);
3911 nxt_mp_release(reopen->mem_pool);
3912}
3913
3914
3915static void
3916nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3917 void *data)
3918{
3919 nxt_router_access_log_reopen_t *reopen;
3920
3921 reopen = data;
3922
3923 nxt_mp_release(reopen->mem_pool);
3924}
3925
3926
3927static void
3928nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
3929{
3930 nxt_port_t *port;
3931 nxt_thread_link_t *link;
3932 nxt_event_engine_t *engine;
3933 nxt_thread_handle_t handle;
3934
3935 handle = (nxt_thread_handle_t) (uintptr_t) obj;
3936 link = data;
3937
3938 nxt_thread_wait(handle);
3939
3940 engine = link->engine;
3941
3942 nxt_queue_remove(&engine->link);
3943
3944 port = engine->port;
3945
3946 // TODO notify all apps
3947
3948 port->engine = task->thread->engine;
3949 nxt_mp_thread_adopt(port->mem_pool);
3950 nxt_port_use(task, port, -1);
3951
3952 nxt_mp_thread_adopt(engine->mem_pool);
3953 nxt_mp_destroy(engine->mem_pool);
3954
3955 nxt_event_engine_free(engine);
3956
3957 nxt_free(link);
3958}
3959
3960
3961static void
3962nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
3963 void *data)
3964{
3965 size_t b_size, count;
3966 nxt_int_t ret;
3967 nxt_app_t *app;
3968 nxt_buf_t *b, *next;
3969 nxt_port_t *app_port;
3970 nxt_unit_field_t *f;
3971 nxt_http_field_t *field;
3972 nxt_http_request_t *r;
3973 nxt_unit_response_t *resp;
3974 nxt_request_rpc_data_t *req_rpc_data;
3975
3976 req_rpc_data = data;
3977
3978 r = req_rpc_data->request;
3979 if (nxt_slow_path(r == NULL)) {
3980 return;
3981 }
3982
3983 if (r->error) {
3984 nxt_request_rpc_data_unlink(task, req_rpc_data);
3985 return;
3986 }
3987
3988 app = req_rpc_data->app;
3989 nxt_assert(app != NULL);
3990
3991 if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) {
3992 nxt_router_req_headers_ack_handler(task, msg, req_rpc_data);
3993
3994 return;
3995 }
3996
3997 b = (msg->size == 0) ? NULL : msg->buf;
3998
3999 if (msg->port_msg.last != 0) {
4000 nxt_debug(task, "router data create last buf");
4001
4002 nxt_buf_chain_add(&b, nxt_http_buf_last(r));
4003
4004 req_rpc_data->rpc_cancel = 0;
4005
4006 if (req_rpc_data->apr_action == NXT_APR_REQUEST_FAILED) {
4007 req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE;
4008 }
4009
4010 nxt_request_rpc_data_unlink(task, req_rpc_data);
4011
4012 } else {
4013 if (app->timeout != 0) {
4014 r->timer.handler = nxt_router_app_timeout;
4015 r->timer_data = req_rpc_data;
4016 nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
4017 }
4018 }
4019
4020 if (b == NULL) {
4021 return;
4022 }
4023
4024 if (msg->buf == b) {
4025 /* Disable instant buffer completion/re-using by port. */
4026 msg->buf = NULL;
4027 }
4028
4029 if (r->header_sent) {
4030 nxt_buf_chain_add(&r->out, b);
4031 nxt_http_request_send_body(task, r, NULL);
4032
4033 } else {
4034 b_size = nxt_buf_is_mem(b) ? nxt_buf_mem_used_size(&b->mem) : 0;
4035
4036 if (nxt_slow_path(b_size < sizeof(nxt_unit_response_t))) {
4037 nxt_alert(task, "response buffer too small: %z", b_size);
4038 goto fail;
4039 }
4040
4041 resp = (void *) b->mem.pos;
4042 count = (b_size - sizeof(nxt_unit_response_t))
4043 / sizeof(nxt_unit_field_t);
4044
4045 if (nxt_slow_path(count < resp->fields_count)) {
4046 nxt_alert(task, "response buffer too small for fields count: %D",
4047 resp->fields_count);
4048 goto fail;
4049 }
4050
4051 field = NULL;
4052
4053 for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
4054 if (f->skip) {
4055 continue;
4056 }
4057
4058 field = nxt_list_add(r->resp.fields);
4059
4060 if (nxt_slow_path(field == NULL)) {
4061 goto fail;
4062 }
4063
4064 field->hash = f->hash;
4065 field->skip = 0;
4066 field->hopbyhop = 0;
4067
4068 field->name_length = f->name_length;
4069 field->value_length = f->value_length;
4070 field->name = nxt_unit_sptr_get(&f->name);
4071 field->value = nxt_unit_sptr_get(&f->value);
4072
4073 ret = nxt_http_field_process(field, &nxt_response_fields_hash, r);
4074 if (nxt_slow_path(ret != NXT_OK)) {
4075 goto fail;
4076 }
4077
4078 nxt_debug(task, "header%s: %*s: %*s",
4079 (field->skip ? " skipped" : ""),
4080 (size_t) field->name_length, field->name,
4081 (size_t) field->value_length, field->value);
4082
4083 if (field->skip) {
4084 r->resp.fields->last->nelts--;
4085 }
4086 }
4087
4088 r->status = resp->status;
4089
4090 if (resp->piggyback_content_length != 0) {
4091 b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
4092 b->mem.free = b->mem.pos + resp->piggyback_content_length;
4093
4094 } else {
4095 b->mem.pos = b->mem.free;
4096 }
4097
4098 if (nxt_buf_mem_used_size(&b->mem) == 0) {
4099 next = b->next;
4100 b->next = NULL;
4101
4102 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
4103 b->completion_handler, task, b, b->parent);
4104
4105 b = next;
4106 }
4107
4108 if (b != NULL) {
4109 nxt_buf_chain_add(&r->out, b);
4110 }
4111
4112 nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL);
4113
4114 if (r->websocket_handshake
4115 && r->status == NXT_HTTP_SWITCHING_PROTOCOLS)
4116 {
4117 app_port = req_rpc_data->app_port;
4118 if (nxt_slow_path(app_port == NULL)) {
4119 goto fail;
4120 }
4121
4122 nxt_thread_mutex_lock(&app->mutex);
4123
4124 app_port->main_app_port->active_websockets++;
4125
4126 nxt_thread_mutex_unlock(&app->mutex);
4127
4128 nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE);
4129 req_rpc_data->apr_action = NXT_APR_CLOSE;
4130
4131 nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream);
4132
4133 r->state = &nxt_http_websocket;
4134
4135 } else {
4136 r->state = &nxt_http_request_send_state;
4137 }
4138 }
4139
4140 return;
4141
4142fail:
4143
4144 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
4145
4146 nxt_request_rpc_data_unlink(task, req_rpc_data);
4147}
4148
4149
4150static void
4151nxt_router_req_headers_ack_handler(nxt_task_t *task,
4152 nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data)
4153{
4154 int res;
4155 nxt_app_t *app;
4156 nxt_buf_t *b;
4157 nxt_bool_t start_process, unlinked;
4158 nxt_port_t *app_port, *main_app_port, *idle_port;
4159 nxt_queue_link_t *idle_lnk;
4160 nxt_http_request_t *r;
4161
4162 nxt_debug(task, "stream #%uD: got ack from %PI:%d",
4163 req_rpc_data->stream,
4164 msg->port_msg.pid, msg->port_msg.reply_port);
4165
4166 nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data,
4167 msg->port_msg.pid);
4168
4169 app = req_rpc_data->app;
4170 r = req_rpc_data->request;
4171
4172 start_process = 0;
4173 unlinked = 0;
4174
4175 nxt_thread_mutex_lock(&app->mutex);
4176
4177 if (r->app_link.next != NULL) {
4178 nxt_queue_remove(&r->app_link);
4179 r->app_link.next = NULL;
4180
4181 unlinked = 1;
4182 }
4183
4184 app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid,
4185 msg->port_msg.reply_port);
4186 if (nxt_slow_path(app_port == NULL)) {
4187 nxt_thread_mutex_unlock(&app->mutex);
4188
4189 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4190
4191 if (unlinked) {
4192 nxt_mp_release(r->mem_pool);
4193 }
4194
4195 return;
4196 }
4197
4198 main_app_port = app_port->main_app_port;
4199
4200 if (nxt_queue_chk_remove(&main_app_port->idle_link)) {
4201 app->idle_processes--;
4202
4203 nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)",
4204 &app->name, main_app_port->pid, main_app_port->id,
4205 (main_app_port->idle_start ? "idle_ports" : "spare_ports"));
4206
4207 /* Check port was in 'spare_ports' using idle_start field. */
4208 if (main_app_port->idle_start == 0
4209 && app->idle_processes >= app->spare_processes)
4210 {
4211 /*
4212 * If there is a vacant space in spare ports,
4213 * move the last idle to spare_ports.
4214 */
4215 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4216
4217 idle_lnk = nxt_queue_last(&app->idle_ports);
4218 idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4219 nxt_queue_remove(idle_lnk);
4220
4221 nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4222
4223 idle_port->idle_start = 0;
4224
4225 nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
4226 "to spare_ports",
4227 &app->name, idle_port->pid, idle_port->id);
4228 }
4229
4230 if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
4231 app->pending_processes++;
4232 start_process = 1;
4233 }
4234 }
4235
4236 main_app_port->active_requests++;
4237
4238 nxt_port_inc_use(app_port);
4239
4240 nxt_thread_mutex_unlock(&app->mutex);
4241
4242 if (unlinked) {
4243 nxt_mp_release(r->mem_pool);
4244 }
4245
4246 if (start_process) {
4247 nxt_router_start_app_process(task, app);
4248 }
4249
4250 nxt_port_use(task, req_rpc_data->app_port, -1);
4251
4252 req_rpc_data->app_port = app_port;
4253
4254 b = req_rpc_data->msg_info.buf;
4255
4256 if (b != NULL) {
4257 /* First buffer is already sent. Start from second. */
4258 b = b->next;
4259
4260 req_rpc_data->msg_info.buf->next = NULL;
4261 }
4262
4263 if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) {
4264 nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream,
4265 req_rpc_data->msg_info.body_fd);
4266
4267 if (req_rpc_data->msg_info.body_fd != -1) {
4268 lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET);
4269 }
4270
4271 res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY,
4272 req_rpc_data->msg_info.body_fd,
4273 req_rpc_data->stream,
4274 task->thread->engine->port->id, b);
4275
4276 if (nxt_slow_path(res != NXT_OK)) {
4277 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4278 }
4279 }
4280
4281 if (app->timeout != 0) {
4282 r->timer.handler = nxt_router_app_timeout;
4283 r->timer_data = req_rpc_data;
4284 nxt_timer_add(task->thread->engine, &r->timer, app->timeout);
4285 }
4286}
4287
4288
4289static const nxt_http_request_state_t nxt_http_request_send_state
4290 nxt_aligned(64) =
4291{
4292 .error_handler = nxt_http_request_error_handler,
4293};
4294
4295
4296static void
4297nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data)
4298{
4299 nxt_buf_t *out;
4300 nxt_http_request_t *r;
4301
4302 r = obj;
4303
4304 out = r->out;
4305
4306 if (out != NULL) {
4307 r->out = NULL;
4308 nxt_http_request_send(task, r, out);
4309 }
4310}
4311
4312
4313static void
4314nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4315 void *data)
4316{
4317 nxt_request_rpc_data_t *req_rpc_data;
4318
4319 req_rpc_data = data;
4320
4321 req_rpc_data->rpc_cancel = 0;
4322
4323 /* TODO cancel message and return if cancelled. */
4324 // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream);
4325
4326 if (req_rpc_data->request != NULL) {
4327 nxt_http_request_error(task, req_rpc_data->request,
4328 NXT_HTTP_SERVICE_UNAVAILABLE);
4329 }
4330
4331 nxt_request_rpc_data_unlink(task, req_rpc_data);
4332}
4333
4334
4335static void
4336nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4337 void *data)
4338{
4236 nxt_app_t *app;
4237 nxt_port_t *port;
4238 nxt_app_joint_t *app_joint;
4339 nxt_app_t *app;
4340 nxt_bool_t start_process;
4341 nxt_port_t *port;
4342 nxt_app_joint_t *app_joint;
4343 nxt_app_joint_rpc_t *app_joint_rpc;
4239
4344
4240 app_joint = data;
4345 nxt_assert(data != NULL);
4346
4347 app_joint_rpc = data;
4348 app_joint = app_joint_rpc->app_joint;
4241 port = msg->u.new_port;
4242
4243 nxt_assert(app_joint != NULL);
4244 nxt_assert(port != NULL);
4245 nxt_assert(port->type == NXT_PROCESS_APP);
4246 nxt_assert(port->id == 0);
4247
4248 app = app_joint->app;
4249
4250 nxt_router_app_joint_use(task, app_joint, -1);
4251
4252 if (nxt_slow_path(app == NULL)) {
4253 nxt_debug(task, "new port ready for released app, send QUIT");
4254
4255 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4256
4257 return;
4258 }
4259
4349 port = msg->u.new_port;
4350
4351 nxt_assert(app_joint != NULL);
4352 nxt_assert(port != NULL);
4353 nxt_assert(port->type == NXT_PROCESS_APP);
4354 nxt_assert(port->id == 0);
4355
4356 app = app_joint->app;
4357
4358 nxt_router_app_joint_use(task, app_joint, -1);
4359
4360 if (nxt_slow_path(app == NULL)) {
4361 nxt_debug(task, "new port ready for released app, send QUIT");
4362
4363 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4364
4365 return;
4366 }
4367
4260 port->app = app;
4261 port->main_app_port = port;
4262
4263 nxt_thread_mutex_lock(&app->mutex);
4264
4265 nxt_assert(app->pending_processes != 0);
4266
4267 app->pending_processes--;
4368 nxt_thread_mutex_lock(&app->mutex);
4369
4370 nxt_assert(app->pending_processes != 0);
4371
4372 app->pending_processes--;
4373
4374 if (nxt_slow_path(app->generation != app_joint_rpc->generation)) {
4375 nxt_debug(task, "new port ready for restarted app, send QUIT");
4376
4377 start_process = !task->thread->engine->shutdown
4378 && nxt_router_app_can_start(app)
4379 && nxt_router_app_need_start(app);
4380
4381 if (start_process) {
4382 app->pending_processes++;
4383 }
4384
4385 nxt_thread_mutex_unlock(&app->mutex);
4386
4387 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4388
4389 if (start_process) {
4390 nxt_router_start_app_process(task, app);
4391 }
4392
4393 return;
4394 }
4395
4396 port->app = app;
4397 port->main_app_port = port;
4398
4268 app->processes++;
4269 nxt_port_hash_add(&app->port_hash, port);
4270 app->port_hash_count++;
4271
4272 nxt_thread_mutex_unlock(&app->mutex);
4273
4274 nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
4275 &app->name, port->pid, app->processes, app->pending_processes);
4276
4277 nxt_router_app_shared_port_send(task, port);
4278
4279 nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT);
4280}
4281
4282
4283static nxt_int_t
4284nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port)
4285{
4286 nxt_buf_t *b;
4287 nxt_port_t *port;
4288 nxt_port_msg_new_port_t *msg;
4289
4290 b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
4291 sizeof(nxt_port_data_t));
4292 if (nxt_slow_path(b == NULL)) {
4293 return NXT_ERROR;
4294 }
4295
4296 port = app_port->app->shared_port;
4297
4298 nxt_debug(task, "send port %FD to process %PI",
4299 port->pair[0], app_port->pid);
4300
4301 b->mem.free += sizeof(nxt_port_msg_new_port_t);
4302 msg = (nxt_port_msg_new_port_t *) b->mem.pos;
4303
4304 msg->id = port->id;
4305 msg->pid = port->pid;
4306 msg->max_size = port->max_size;
4307 msg->max_share = port->max_share;
4308 msg->type = port->type;
4309
4310 return nxt_port_socket_write2(task, app_port,
4311 NXT_PORT_MSG_NEW_PORT,
4312 port->pair[0], port->queue_fd,
4313 0, 0, b);
4314}
4315
4316
4317static void
4318nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4319 void *data)
4320{
4399 app->processes++;
4400 nxt_port_hash_add(&app->port_hash, port);
4401 app->port_hash_count++;
4402
4403 nxt_thread_mutex_unlock(&app->mutex);
4404
4405 nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d",
4406 &app->name, port->pid, app->processes, app->pending_processes);
4407
4408 nxt_router_app_shared_port_send(task, port);
4409
4410 nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT);
4411}
4412
4413
4414static nxt_int_t
4415nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port)
4416{
4417 nxt_buf_t *b;
4418 nxt_port_t *port;
4419 nxt_port_msg_new_port_t *msg;
4420
4421 b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
4422 sizeof(nxt_port_data_t));
4423 if (nxt_slow_path(b == NULL)) {
4424 return NXT_ERROR;
4425 }
4426
4427 port = app_port->app->shared_port;
4428
4429 nxt_debug(task, "send port %FD to process %PI",
4430 port->pair[0], app_port->pid);
4431
4432 b->mem.free += sizeof(nxt_port_msg_new_port_t);
4433 msg = (nxt_port_msg_new_port_t *) b->mem.pos;
4434
4435 msg->id = port->id;
4436 msg->pid = port->pid;
4437 msg->max_size = port->max_size;
4438 msg->max_share = port->max_share;
4439 msg->type = port->type;
4440
4441 return nxt_port_socket_write2(task, app_port,
4442 NXT_PORT_MSG_NEW_PORT,
4443 port->pair[0], port->queue_fd,
4444 0, 0, b);
4445}
4446
4447
4448static void
4449nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
4450 void *data)
4451{
4321 nxt_app_t *app;
4322 nxt_app_joint_t *app_joint;
4323 nxt_queue_link_t *link;
4324 nxt_http_request_t *r;
4452 nxt_app_t *app;
4453 nxt_app_joint_t *app_joint;
4454 nxt_queue_link_t *link;
4455 nxt_http_request_t *r;
4456 nxt_app_joint_rpc_t *app_joint_rpc;
4325
4457
4326 app_joint = data;
4458 nxt_assert(data != NULL);
4327
4459
4460 app_joint_rpc = data;
4461 app_joint = app_joint_rpc->app_joint;
4462
4328 nxt_assert(app_joint != NULL);
4329
4330 app = app_joint->app;
4331
4332 nxt_router_app_joint_use(task, app_joint, -1);
4333
4334 if (nxt_slow_path(app == NULL)) {
4335 nxt_debug(task, "start error for released app");
4336
4337 return;
4338 }
4339
4340 nxt_debug(task, "app '%V' %p start error", &app->name, app);
4341
4342 link = NULL;
4343
4344 nxt_thread_mutex_lock(&app->mutex);
4345
4346 nxt_assert(app->pending_processes != 0);
4347
4348 app->pending_processes--;
4349
4350 if (app->processes == 0 && !nxt_queue_is_empty(&app->ack_waiting_req)) {
4351 link = nxt_queue_first(&app->ack_waiting_req);
4352
4353 nxt_queue_remove(link);
4354 link->next = NULL;
4355 }
4356
4357 nxt_thread_mutex_unlock(&app->mutex);
4358
4359 while (link != NULL) {
4360 r = nxt_container_of(link, nxt_http_request_t, app_link);
4361
4362 nxt_event_engine_post(r->engine, &r->err_work);
4363
4364 link = NULL;
4365
4366 nxt_thread_mutex_lock(&app->mutex);
4367
4368 if (app->processes == 0 && app->pending_processes == 0
4369 && !nxt_queue_is_empty(&app->ack_waiting_req))
4370 {
4371 link = nxt_queue_first(&app->ack_waiting_req);
4372
4373 nxt_queue_remove(link);
4374 link->next = NULL;
4375 }
4376
4377 nxt_thread_mutex_unlock(&app->mutex);
4378 }
4379}
4380
4381
4382
4383nxt_inline nxt_port_t *
4384nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
4385{
4386 nxt_port_t *port;
4387
4388 port = NULL;
4389
4390 nxt_thread_mutex_lock(&app->mutex);
4391
4392 nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
4393
4394 /* Caller is responsible to decrease port use count. */
4395 nxt_queue_chk_remove(&port->app_link);
4396
4397 if (nxt_queue_chk_remove(&port->idle_link)) {
4398 app->idle_processes--;
4399
4400 nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit",
4401 &app->name, port->pid, port->id,
4402 (port->idle_start ? "idle_ports" : "spare_ports"));
4403 }
4404
4405 nxt_port_hash_remove(&app->port_hash, port);
4406 app->port_hash_count--;
4407
4408 port->app = NULL;
4409 app->processes--;
4410
4411 break;
4412
4413 } nxt_queue_loop;
4414
4415 nxt_thread_mutex_unlock(&app->mutex);
4416
4417 return port;
4418}
4419
4420
4421static void
4422nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
4423{
4424 int c;
4425
4426 c = nxt_atomic_fetch_add(&app->use_count, i);
4427
4428 if (i < 0 && c == -i) {
4429
4430 if (task->thread->engine != app->engine) {
4431 nxt_event_engine_post(app->engine, &app->joint->free_app_work);
4432
4433 } else {
4434 nxt_router_free_app(task, app->joint, NULL);
4435 }
4436 }
4437}
4438
4439
4440static void
4441nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
4442{
4443 nxt_debug(task, "app '%V' %p unlink", &app->name, app);
4444
4445 nxt_queue_remove(&app->link);
4446
4447 nxt_router_app_use(task, app, -1);
4448}
4449
4450
4451static void
4452nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
4453 nxt_apr_action_t action)
4454{
4455 int inc_use;
4456 uint32_t got_response, dec_requests;
4457 nxt_app_t *app;
4458 nxt_bool_t port_unchained, send_quit, adjust_idle_timer;
4459 nxt_port_t *main_app_port;
4460
4461 nxt_assert(port != NULL);
4462 nxt_assert(port->app != NULL);
4463
4464 app = port->app;
4465
4466 inc_use = 0;
4467 got_response = 0;
4468 dec_requests = 0;
4469
4470 switch (action) {
4471 case NXT_APR_NEW_PORT:
4472 break;
4473 case NXT_APR_REQUEST_FAILED:
4474 dec_requests = 1;
4475 inc_use = -1;
4476 break;
4477 case NXT_APR_GOT_RESPONSE:
4478 got_response = 1;
4479 inc_use = -1;
4480 break;
4481 case NXT_APR_UPGRADE:
4482 got_response = 1;
4483 break;
4484 case NXT_APR_CLOSE:
4485 inc_use = -1;
4486 break;
4487 }
4488
4489 nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name,
4490 port->pid, port->id,
4491 (int) inc_use, (int) got_response);
4492
4463 nxt_assert(app_joint != NULL);
4464
4465 app = app_joint->app;
4466
4467 nxt_router_app_joint_use(task, app_joint, -1);
4468
4469 if (nxt_slow_path(app == NULL)) {
4470 nxt_debug(task, "start error for released app");
4471
4472 return;
4473 }
4474
4475 nxt_debug(task, "app '%V' %p start error", &app->name, app);
4476
4477 link = NULL;
4478
4479 nxt_thread_mutex_lock(&app->mutex);
4480
4481 nxt_assert(app->pending_processes != 0);
4482
4483 app->pending_processes--;
4484
4485 if (app->processes == 0 && !nxt_queue_is_empty(&app->ack_waiting_req)) {
4486 link = nxt_queue_first(&app->ack_waiting_req);
4487
4488 nxt_queue_remove(link);
4489 link->next = NULL;
4490 }
4491
4492 nxt_thread_mutex_unlock(&app->mutex);
4493
4494 while (link != NULL) {
4495 r = nxt_container_of(link, nxt_http_request_t, app_link);
4496
4497 nxt_event_engine_post(r->engine, &r->err_work);
4498
4499 link = NULL;
4500
4501 nxt_thread_mutex_lock(&app->mutex);
4502
4503 if (app->processes == 0 && app->pending_processes == 0
4504 && !nxt_queue_is_empty(&app->ack_waiting_req))
4505 {
4506 link = nxt_queue_first(&app->ack_waiting_req);
4507
4508 nxt_queue_remove(link);
4509 link->next = NULL;
4510 }
4511
4512 nxt_thread_mutex_unlock(&app->mutex);
4513 }
4514}
4515
4516
4517
4518nxt_inline nxt_port_t *
4519nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
4520{
4521 nxt_port_t *port;
4522
4523 port = NULL;
4524
4525 nxt_thread_mutex_lock(&app->mutex);
4526
4527 nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
4528
4529 /* Caller is responsible to decrease port use count. */
4530 nxt_queue_chk_remove(&port->app_link);
4531
4532 if (nxt_queue_chk_remove(&port->idle_link)) {
4533 app->idle_processes--;
4534
4535 nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit",
4536 &app->name, port->pid, port->id,
4537 (port->idle_start ? "idle_ports" : "spare_ports"));
4538 }
4539
4540 nxt_port_hash_remove(&app->port_hash, port);
4541 app->port_hash_count--;
4542
4543 port->app = NULL;
4544 app->processes--;
4545
4546 break;
4547
4548 } nxt_queue_loop;
4549
4550 nxt_thread_mutex_unlock(&app->mutex);
4551
4552 return port;
4553}
4554
4555
4556static void
4557nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
4558{
4559 int c;
4560
4561 c = nxt_atomic_fetch_add(&app->use_count, i);
4562
4563 if (i < 0 && c == -i) {
4564
4565 if (task->thread->engine != app->engine) {
4566 nxt_event_engine_post(app->engine, &app->joint->free_app_work);
4567
4568 } else {
4569 nxt_router_free_app(task, app->joint, NULL);
4570 }
4571 }
4572}
4573
4574
4575static void
4576nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
4577{
4578 nxt_debug(task, "app '%V' %p unlink", &app->name, app);
4579
4580 nxt_queue_remove(&app->link);
4581
4582 nxt_router_app_use(task, app, -1);
4583}
4584
4585
4586static void
4587nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
4588 nxt_apr_action_t action)
4589{
4590 int inc_use;
4591 uint32_t got_response, dec_requests;
4592 nxt_app_t *app;
4593 nxt_bool_t port_unchained, send_quit, adjust_idle_timer;
4594 nxt_port_t *main_app_port;
4595
4596 nxt_assert(port != NULL);
4597 nxt_assert(port->app != NULL);
4598
4599 app = port->app;
4600
4601 inc_use = 0;
4602 got_response = 0;
4603 dec_requests = 0;
4604
4605 switch (action) {
4606 case NXT_APR_NEW_PORT:
4607 break;
4608 case NXT_APR_REQUEST_FAILED:
4609 dec_requests = 1;
4610 inc_use = -1;
4611 break;
4612 case NXT_APR_GOT_RESPONSE:
4613 got_response = 1;
4614 inc_use = -1;
4615 break;
4616 case NXT_APR_UPGRADE:
4617 got_response = 1;
4618 break;
4619 case NXT_APR_CLOSE:
4620 inc_use = -1;
4621 break;
4622 }
4623
4624 nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name,
4625 port->pid, port->id,
4626 (int) inc_use, (int) got_response);
4627
4493 if (port == app->shared_port) {
4628 if (port->id == NXT_SHARED_PORT_ID) {
4494 nxt_thread_mutex_lock(&app->mutex);
4495
4496 app->active_requests -= got_response + dec_requests;
4497
4498 nxt_thread_mutex_unlock(&app->mutex);
4499
4500 goto adjust_use;
4501 }
4502
4503 main_app_port = port->main_app_port;
4504
4505 nxt_thread_mutex_lock(&app->mutex);
4506
4507 main_app_port->app_responses += got_response;
4508 main_app_port->active_requests -= got_response + dec_requests;
4509 app->active_requests -= got_response + dec_requests;
4510
4511 if (main_app_port->pair[1] != -1
4512 && (app->max_requests == 0
4513 || main_app_port->app_responses < app->max_requests))
4514 {
4515 if (main_app_port->app_link.next == NULL) {
4516 nxt_queue_insert_tail(&app->ports, &main_app_port->app_link);
4517
4518 nxt_port_inc_use(main_app_port);
4519 }
4520 }
4521
4522 send_quit = (app->max_requests > 0
4523 && main_app_port->app_responses >= app->max_requests);
4524
4525 if (send_quit) {
4526 port_unchained = nxt_queue_chk_remove(&main_app_port->app_link);
4527
4528 nxt_port_hash_remove(&app->port_hash, main_app_port);
4529 app->port_hash_count--;
4530
4531 main_app_port->app = NULL;
4532 app->processes--;
4533
4534 } else {
4535 port_unchained = 0;
4536 }
4537
4538 adjust_idle_timer = 0;
4539
4540 if (main_app_port->pair[1] != -1 && !send_quit
4541 && main_app_port->active_requests == 0
4542 && main_app_port->active_websockets == 0
4543 && main_app_port->idle_link.next == NULL)
4544 {
4545 if (app->idle_processes == app->spare_processes
4546 && app->adjust_idle_work.data == NULL)
4547 {
4548 adjust_idle_timer = 1;
4549 app->adjust_idle_work.data = app;
4550 app->adjust_idle_work.next = NULL;
4551 }
4552
4553 if (app->idle_processes < app->spare_processes) {
4554 nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link);
4555
4556 nxt_debug(task, "app '%V' move port %PI:%d to spare_ports",
4557 &app->name, main_app_port->pid, main_app_port->id);
4558 } else {
4559 nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link);
4560
4561 main_app_port->idle_start = task->thread->engine->timers.now;
4562
4563 nxt_debug(task, "app '%V' move port %PI:%d to idle_ports",
4564 &app->name, main_app_port->pid, main_app_port->id);
4565 }
4566
4567 app->idle_processes++;
4568 }
4569
4570 nxt_thread_mutex_unlock(&app->mutex);
4571
4572 if (adjust_idle_timer) {
4573 nxt_router_app_use(task, app, 1);
4574 nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4575 }
4576
4577 /* ? */
4578 if (main_app_port->pair[1] == -1) {
4579 nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4580 &app->name, app, main_app_port, main_app_port->pid);
4581
4582 goto adjust_use;
4583 }
4584
4585 if (send_quit) {
4586 nxt_debug(task, "app '%V' %p send QUIT to port", &app->name, app);
4587
4588 nxt_port_socket_write(task, main_app_port, NXT_PORT_MSG_QUIT, -1, 0, 0,
4589 NULL);
4590
4591 if (port_unchained) {
4592 nxt_port_use(task, main_app_port, -1);
4593 }
4594
4595 goto adjust_use;
4596 }
4597
4598 nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4599 &app->name, app);
4600
4601adjust_use:
4602
4603 nxt_port_use(task, port, inc_use);
4604}
4605
4606
4607void
4608nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4609{
4610 nxt_app_t *app;
4611 nxt_bool_t unchain, start_process;
4612 nxt_port_t *idle_port;
4613 nxt_queue_link_t *idle_lnk;
4614
4615 app = port->app;
4616
4617 nxt_assert(app != NULL);
4618
4619 nxt_thread_mutex_lock(&app->mutex);
4620
4621 nxt_port_hash_remove(&app->port_hash, port);
4622 app->port_hash_count--;
4623
4624 if (port->id != 0) {
4625 nxt_thread_mutex_unlock(&app->mutex);
4626
4627 nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name,
4628 port->pid, port->id);
4629
4630 return;
4631 }
4632
4633 unchain = nxt_queue_chk_remove(&port->app_link);
4634
4635 if (nxt_queue_chk_remove(&port->idle_link)) {
4636 app->idle_processes--;
4637
4638 nxt_debug(task, "app '%V' move port %PI:%d out of %s before close",
4639 &app->name, port->pid, port->id,
4640 (port->idle_start ? "idle_ports" : "spare_ports"));
4641
4642 if (port->idle_start == 0
4643 && app->idle_processes >= app->spare_processes)
4644 {
4645 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4646
4647 idle_lnk = nxt_queue_last(&app->idle_ports);
4648 idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4649 nxt_queue_remove(idle_lnk);
4650
4651 nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4652
4653 idle_port->idle_start = 0;
4654
4655 nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
4656 "to spare_ports",
4657 &app->name, idle_port->pid, idle_port->id);
4658 }
4659 }
4660
4661 app->processes--;
4662
4663 start_process = !task->thread->engine->shutdown
4664 && nxt_router_app_can_start(app)
4665 && nxt_router_app_need_start(app);
4666
4667 if (start_process) {
4668 app->pending_processes++;
4669 }
4670
4671 nxt_thread_mutex_unlock(&app->mutex);
4672
4673 nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4674
4675 if (unchain) {
4676 nxt_port_use(task, port, -1);
4677 }
4678
4679 if (start_process) {
4680 nxt_router_start_app_process(task, app);
4681 }
4682}
4683
4684
4685static void
4686nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4687{
4688 nxt_app_t *app;
4689 nxt_bool_t queued;
4690 nxt_port_t *port;
4691 nxt_msec_t timeout, threshold;
4692 nxt_queue_link_t *lnk;
4693 nxt_event_engine_t *engine;
4694
4695 app = obj;
4696 queued = (data == app);
4697
4698 nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4699 &app->name, queued);
4700
4701 engine = task->thread->engine;
4702
4703 nxt_assert(app->engine == engine);
4704
4705 threshold = engine->timers.now + app->joint->idle_timer.bias;
4706 timeout = 0;
4707
4708 nxt_thread_mutex_lock(&app->mutex);
4709
4710 if (queued) {
4711 app->adjust_idle_work.data = NULL;
4712 }
4713
4714 nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d",
4715 &app->name,
4716 (int) app->idle_processes, (int) app->spare_processes);
4717
4718 while (app->idle_processes > app->spare_processes) {
4719
4720 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4721
4722 lnk = nxt_queue_first(&app->idle_ports);
4723 port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4724
4725 timeout = port->idle_start + app->idle_timeout;
4726
4727 nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M",
4728 &app->name, port->pid,
4729 port->idle_start, timeout, threshold);
4730
4731 if (timeout > threshold) {
4732 break;
4733 }
4734
4735 nxt_queue_remove(lnk);
4736 lnk->next = NULL;
4737
4738 nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)",
4739 &app->name, port->pid, port->id);
4740
4741 nxt_queue_chk_remove(&port->app_link);
4742
4743 nxt_port_hash_remove(&app->port_hash, port);
4744 app->port_hash_count--;
4745
4746 app->idle_processes--;
4747 app->processes--;
4748 port->app = NULL;
4749
4750 nxt_thread_mutex_unlock(&app->mutex);
4751
4752 nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4753 &app->name, port->pid);
4754
4755 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4756
4757 nxt_port_use(task, port, -1);
4758
4759 nxt_thread_mutex_lock(&app->mutex);
4760 }
4761
4762 nxt_thread_mutex_unlock(&app->mutex);
4763
4764 if (timeout > threshold) {
4765 nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4766
4767 } else {
4768 nxt_timer_disable(engine, &app->joint->idle_timer);
4769 }
4770
4771 if (queued) {
4772 nxt_router_app_use(task, app, -1);
4773 }
4774}
4775
4776
4777static void
4778nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4779{
4780 nxt_timer_t *timer;
4781 nxt_app_joint_t *app_joint;
4782
4783 timer = obj;
4784 app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4785
4786 if (nxt_fast_path(app_joint->app != NULL)) {
4787 nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4788 }
4789}
4790
4791
4792static void
4793nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4794{
4795 nxt_timer_t *timer;
4796 nxt_app_joint_t *app_joint;
4797
4798 timer = obj;
4799 app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4800
4801 nxt_router_app_joint_use(task, app_joint, -1);
4802}
4803
4804
4805static void
4806nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4807{
4808 nxt_app_t *app;
4809 nxt_port_t *port;
4810 nxt_app_joint_t *app_joint;
4811
4812 app_joint = obj;
4813 app = app_joint->app;
4814
4815 for ( ;; ) {
4816 port = nxt_router_app_get_port_for_quit(task, app);
4817 if (port == NULL) {
4818 break;
4819 }
4820
4821 nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4822
4823 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4824
4825 nxt_port_use(task, port, -1);
4826 }
4827
4828 nxt_thread_mutex_lock(&app->mutex);
4829
4830 for ( ;; ) {
4831 port = nxt_port_hash_retrieve(&app->port_hash);
4832 if (port == NULL) {
4833 break;
4834 }
4835
4836 app->port_hash_count--;
4837
4838 port->app = NULL;
4839
4840 nxt_port_close(task, port);
4841
4842 nxt_port_use(task, port, -1);
4843 }
4844
4845 nxt_thread_mutex_unlock(&app->mutex);
4846
4847 nxt_assert(app->processes == 0);
4848 nxt_assert(app->active_requests == 0);
4849 nxt_assert(app->port_hash_count == 0);
4850 nxt_assert(app->idle_processes == 0);
4851 nxt_assert(nxt_queue_is_empty(&app->ports));
4852 nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4853 nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4854
4855 nxt_port_mmaps_destroy(&app->outgoing, 1);
4856
4857 nxt_thread_mutex_destroy(&app->outgoing.mutex);
4858
4859 if (app->shared_port != NULL) {
4860 app->shared_port->app = NULL;
4861 nxt_port_close(task, app->shared_port);
4862 nxt_port_use(task, app->shared_port, -1);
4629 nxt_thread_mutex_lock(&app->mutex);
4630
4631 app->active_requests -= got_response + dec_requests;
4632
4633 nxt_thread_mutex_unlock(&app->mutex);
4634
4635 goto adjust_use;
4636 }
4637
4638 main_app_port = port->main_app_port;
4639
4640 nxt_thread_mutex_lock(&app->mutex);
4641
4642 main_app_port->app_responses += got_response;
4643 main_app_port->active_requests -= got_response + dec_requests;
4644 app->active_requests -= got_response + dec_requests;
4645
4646 if (main_app_port->pair[1] != -1
4647 && (app->max_requests == 0
4648 || main_app_port->app_responses < app->max_requests))
4649 {
4650 if (main_app_port->app_link.next == NULL) {
4651 nxt_queue_insert_tail(&app->ports, &main_app_port->app_link);
4652
4653 nxt_port_inc_use(main_app_port);
4654 }
4655 }
4656
4657 send_quit = (app->max_requests > 0
4658 && main_app_port->app_responses >= app->max_requests);
4659
4660 if (send_quit) {
4661 port_unchained = nxt_queue_chk_remove(&main_app_port->app_link);
4662
4663 nxt_port_hash_remove(&app->port_hash, main_app_port);
4664 app->port_hash_count--;
4665
4666 main_app_port->app = NULL;
4667 app->processes--;
4668
4669 } else {
4670 port_unchained = 0;
4671 }
4672
4673 adjust_idle_timer = 0;
4674
4675 if (main_app_port->pair[1] != -1 && !send_quit
4676 && main_app_port->active_requests == 0
4677 && main_app_port->active_websockets == 0
4678 && main_app_port->idle_link.next == NULL)
4679 {
4680 if (app->idle_processes == app->spare_processes
4681 && app->adjust_idle_work.data == NULL)
4682 {
4683 adjust_idle_timer = 1;
4684 app->adjust_idle_work.data = app;
4685 app->adjust_idle_work.next = NULL;
4686 }
4687
4688 if (app->idle_processes < app->spare_processes) {
4689 nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link);
4690
4691 nxt_debug(task, "app '%V' move port %PI:%d to spare_ports",
4692 &app->name, main_app_port->pid, main_app_port->id);
4693 } else {
4694 nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link);
4695
4696 main_app_port->idle_start = task->thread->engine->timers.now;
4697
4698 nxt_debug(task, "app '%V' move port %PI:%d to idle_ports",
4699 &app->name, main_app_port->pid, main_app_port->id);
4700 }
4701
4702 app->idle_processes++;
4703 }
4704
4705 nxt_thread_mutex_unlock(&app->mutex);
4706
4707 if (adjust_idle_timer) {
4708 nxt_router_app_use(task, app, 1);
4709 nxt_event_engine_post(app->engine, &app->adjust_idle_work);
4710 }
4711
4712 /* ? */
4713 if (main_app_port->pair[1] == -1) {
4714 nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)",
4715 &app->name, app, main_app_port, main_app_port->pid);
4716
4717 goto adjust_use;
4718 }
4719
4720 if (send_quit) {
4721 nxt_debug(task, "app '%V' %p send QUIT to port", &app->name, app);
4722
4723 nxt_port_socket_write(task, main_app_port, NXT_PORT_MSG_QUIT, -1, 0, 0,
4724 NULL);
4725
4726 if (port_unchained) {
4727 nxt_port_use(task, main_app_port, -1);
4728 }
4729
4730 goto adjust_use;
4731 }
4732
4733 nxt_debug(task, "app '%V' %p requests queue is empty, keep the port",
4734 &app->name, app);
4735
4736adjust_use:
4737
4738 nxt_port_use(task, port, inc_use);
4739}
4740
4741
4742void
4743nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port)
4744{
4745 nxt_app_t *app;
4746 nxt_bool_t unchain, start_process;
4747 nxt_port_t *idle_port;
4748 nxt_queue_link_t *idle_lnk;
4749
4750 app = port->app;
4751
4752 nxt_assert(app != NULL);
4753
4754 nxt_thread_mutex_lock(&app->mutex);
4755
4756 nxt_port_hash_remove(&app->port_hash, port);
4757 app->port_hash_count--;
4758
4759 if (port->id != 0) {
4760 nxt_thread_mutex_unlock(&app->mutex);
4761
4762 nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name,
4763 port->pid, port->id);
4764
4765 return;
4766 }
4767
4768 unchain = nxt_queue_chk_remove(&port->app_link);
4769
4770 if (nxt_queue_chk_remove(&port->idle_link)) {
4771 app->idle_processes--;
4772
4773 nxt_debug(task, "app '%V' move port %PI:%d out of %s before close",
4774 &app->name, port->pid, port->id,
4775 (port->idle_start ? "idle_ports" : "spare_ports"));
4776
4777 if (port->idle_start == 0
4778 && app->idle_processes >= app->spare_processes)
4779 {
4780 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4781
4782 idle_lnk = nxt_queue_last(&app->idle_ports);
4783 idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link);
4784 nxt_queue_remove(idle_lnk);
4785
4786 nxt_queue_insert_tail(&app->spare_ports, idle_lnk);
4787
4788 idle_port->idle_start = 0;
4789
4790 nxt_debug(task, "app '%V' move port %PI:%d from idle_ports "
4791 "to spare_ports",
4792 &app->name, idle_port->pid, idle_port->id);
4793 }
4794 }
4795
4796 app->processes--;
4797
4798 start_process = !task->thread->engine->shutdown
4799 && nxt_router_app_can_start(app)
4800 && nxt_router_app_need_start(app);
4801
4802 if (start_process) {
4803 app->pending_processes++;
4804 }
4805
4806 nxt_thread_mutex_unlock(&app->mutex);
4807
4808 nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid);
4809
4810 if (unchain) {
4811 nxt_port_use(task, port, -1);
4812 }
4813
4814 if (start_process) {
4815 nxt_router_start_app_process(task, app);
4816 }
4817}
4818
4819
4820static void
4821nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data)
4822{
4823 nxt_app_t *app;
4824 nxt_bool_t queued;
4825 nxt_port_t *port;
4826 nxt_msec_t timeout, threshold;
4827 nxt_queue_link_t *lnk;
4828 nxt_event_engine_t *engine;
4829
4830 app = obj;
4831 queued = (data == app);
4832
4833 nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b",
4834 &app->name, queued);
4835
4836 engine = task->thread->engine;
4837
4838 nxt_assert(app->engine == engine);
4839
4840 threshold = engine->timers.now + app->joint->idle_timer.bias;
4841 timeout = 0;
4842
4843 nxt_thread_mutex_lock(&app->mutex);
4844
4845 if (queued) {
4846 app->adjust_idle_work.data = NULL;
4847 }
4848
4849 nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d",
4850 &app->name,
4851 (int) app->idle_processes, (int) app->spare_processes);
4852
4853 while (app->idle_processes > app->spare_processes) {
4854
4855 nxt_assert(!nxt_queue_is_empty(&app->idle_ports));
4856
4857 lnk = nxt_queue_first(&app->idle_ports);
4858 port = nxt_queue_link_data(lnk, nxt_port_t, idle_link);
4859
4860 timeout = port->idle_start + app->idle_timeout;
4861
4862 nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M",
4863 &app->name, port->pid,
4864 port->idle_start, timeout, threshold);
4865
4866 if (timeout > threshold) {
4867 break;
4868 }
4869
4870 nxt_queue_remove(lnk);
4871 lnk->next = NULL;
4872
4873 nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)",
4874 &app->name, port->pid, port->id);
4875
4876 nxt_queue_chk_remove(&port->app_link);
4877
4878 nxt_port_hash_remove(&app->port_hash, port);
4879 app->port_hash_count--;
4880
4881 app->idle_processes--;
4882 app->processes--;
4883 port->app = NULL;
4884
4885 nxt_thread_mutex_unlock(&app->mutex);
4886
4887 nxt_debug(task, "app '%V' send QUIT to idle port %PI",
4888 &app->name, port->pid);
4889
4890 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4891
4892 nxt_port_use(task, port, -1);
4893
4894 nxt_thread_mutex_lock(&app->mutex);
4895 }
4896
4897 nxt_thread_mutex_unlock(&app->mutex);
4898
4899 if (timeout > threshold) {
4900 nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold);
4901
4902 } else {
4903 nxt_timer_disable(engine, &app->joint->idle_timer);
4904 }
4905
4906 if (queued) {
4907 nxt_router_app_use(task, app, -1);
4908 }
4909}
4910
4911
4912static void
4913nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data)
4914{
4915 nxt_timer_t *timer;
4916 nxt_app_joint_t *app_joint;
4917
4918 timer = obj;
4919 app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4920
4921 if (nxt_fast_path(app_joint->app != NULL)) {
4922 nxt_router_adjust_idle_timer(task, app_joint->app, NULL);
4923 }
4924}
4925
4926
4927static void
4928nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data)
4929{
4930 nxt_timer_t *timer;
4931 nxt_app_joint_t *app_joint;
4932
4933 timer = obj;
4934 app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer);
4935
4936 nxt_router_app_joint_use(task, app_joint, -1);
4937}
4938
4939
4940static void
4941nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
4942{
4943 nxt_app_t *app;
4944 nxt_port_t *port;
4945 nxt_app_joint_t *app_joint;
4946
4947 app_joint = obj;
4948 app = app_joint->app;
4949
4950 for ( ;; ) {
4951 port = nxt_router_app_get_port_for_quit(task, app);
4952 if (port == NULL) {
4953 break;
4954 }
4955
4956 nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid);
4957
4958 nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
4959
4960 nxt_port_use(task, port, -1);
4961 }
4962
4963 nxt_thread_mutex_lock(&app->mutex);
4964
4965 for ( ;; ) {
4966 port = nxt_port_hash_retrieve(&app->port_hash);
4967 if (port == NULL) {
4968 break;
4969 }
4970
4971 app->port_hash_count--;
4972
4973 port->app = NULL;
4974
4975 nxt_port_close(task, port);
4976
4977 nxt_port_use(task, port, -1);
4978 }
4979
4980 nxt_thread_mutex_unlock(&app->mutex);
4981
4982 nxt_assert(app->processes == 0);
4983 nxt_assert(app->active_requests == 0);
4984 nxt_assert(app->port_hash_count == 0);
4985 nxt_assert(app->idle_processes == 0);
4986 nxt_assert(nxt_queue_is_empty(&app->ports));
4987 nxt_assert(nxt_queue_is_empty(&app->spare_ports));
4988 nxt_assert(nxt_queue_is_empty(&app->idle_ports));
4989
4990 nxt_port_mmaps_destroy(&app->outgoing, 1);
4991
4992 nxt_thread_mutex_destroy(&app->outgoing.mutex);
4993
4994 if (app->shared_port != NULL) {
4995 app->shared_port->app = NULL;
4996 nxt_port_close(task, app->shared_port);
4997 nxt_port_use(task, app->shared_port, -1);
4998
4999 app->shared_port = NULL;
4863 }
4864
4865 nxt_thread_mutex_destroy(&app->mutex);
4866 nxt_mp_destroy(app->mem_pool);
4867
4868 app_joint->app = NULL;
4869
4870 if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
4871 app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
4872 nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
4873
4874 } else {
4875 nxt_router_app_joint_use(task, app_joint, -1);
4876 }
4877}
4878
4879
4880static void
4881nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
4882 nxt_request_rpc_data_t *req_rpc_data)
4883{
4884 nxt_bool_t start_process;
4885 nxt_port_t *port;
4886 nxt_http_request_t *r;
4887
4888 start_process = 0;
4889
4890 nxt_thread_mutex_lock(&app->mutex);
4891
4892 port = app->shared_port;
4893 nxt_port_inc_use(port);
4894
4895 app->active_requests++;
4896
4897 if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
4898 app->pending_processes++;
4899 start_process = 1;
4900 }
4901
4902 r = req_rpc_data->request;
4903
4904 /*
4905 * Put request into application-wide list to be able to cancel request
4906 * if something goes wrong with application processes.
4907 */
4908 nxt_queue_insert_tail(&app->ack_waiting_req, &r->app_link);
4909
4910 nxt_thread_mutex_unlock(&app->mutex);
4911
4912 /*
4913 * Retain request memory pool while request is linked in ack_waiting_req
4914 * to guarantee request structure memory is accessble.
4915 */
4916 nxt_mp_retain(r->mem_pool);
4917
4918 req_rpc_data->app_port = port;
4919 req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED;
4920
4921 if (start_process) {
4922 nxt_router_start_app_process(task, app);
4923 }
4924}
4925
4926
4927void
4928nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
4929 nxt_http_action_t *action)
4930{
4931 nxt_event_engine_t *engine;
4932 nxt_http_app_conf_t *conf;
4933 nxt_request_rpc_data_t *req_rpc_data;
4934
4935 conf = action->u.conf;
4936 engine = task->thread->engine;
4937
4938 r->app_target = conf->target;
4939
4940 req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
4941 nxt_router_response_ready_handler,
4942 nxt_router_response_error_handler,
4943 sizeof(nxt_request_rpc_data_t));
4944 if (nxt_slow_path(req_rpc_data == NULL)) {
4945 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
4946 return;
4947 }
4948
4949 /*
4950 * At this point we have request req_rpc_data allocated and registered
4951 * in port handlers. Need to fixup request memory pool. Counterpart
4952 * release will be called via following call chain:
4953 * nxt_request_rpc_data_unlink() ->
4954 * nxt_router_http_request_release_post() ->
4955 * nxt_router_http_request_release()
4956 */
4957 nxt_mp_retain(r->mem_pool);
4958
4959 r->timer.task = &engine->task;
4960 r->timer.work_queue = &engine->fast_work_queue;
4961 r->timer.log = engine->task.log;
4962 r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
4963
4964 r->engine = engine;
4965 r->err_work.handler = nxt_router_http_request_error;
4966 r->err_work.task = task;
4967 r->err_work.obj = r;
4968
4969 req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
4970 req_rpc_data->app = conf->app;
4971 req_rpc_data->msg_info.body_fd = -1;
4972 req_rpc_data->rpc_cancel = 1;
4973
4974 nxt_router_app_use(task, conf->app, 1);
4975
4976 req_rpc_data->request = r;
4977 r->req_rpc_data = req_rpc_data;
4978
4979 if (r->last != NULL) {
4980 r->last->completion_handler = nxt_router_http_request_done;
4981 }
4982
4983 nxt_router_app_port_get(task, conf->app, req_rpc_data);
4984 nxt_router_app_prepare_request(task, req_rpc_data);
4985}
4986
4987
4988static void
4989nxt_router_http_request_error(nxt_task_t *task, void *obj, void *data)
4990{
4991 nxt_http_request_t *r;
4992
4993 r = obj;
4994
4995 nxt_debug(task, "router http request error (rpc_data %p)", r->req_rpc_data);
4996
4997 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
4998
4999 if (r->req_rpc_data != NULL) {
5000 nxt_request_rpc_data_unlink(task, r->req_rpc_data);
5001 }
5002
5003 nxt_mp_release(r->mem_pool);
5004}
5005
5006
5007static void
5008nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data)
5009{
5010 nxt_http_request_t *r;
5011
5012 r = data;
5013
5014 nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data);
5015
5016 if (r->req_rpc_data != NULL) {
5017 nxt_request_rpc_data_unlink(task, r->req_rpc_data);
5018 }
5019
5020 nxt_http_request_close_handler(task, r, r->proto.any);
5021}
5022
5023
5024static void
5025nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
5026{
5027}
5028
5029
5030static void
5031nxt_router_app_prepare_request(nxt_task_t *task,
5032 nxt_request_rpc_data_t *req_rpc_data)
5033{
5034 nxt_app_t *app;
5035 nxt_buf_t *buf, *body;
5036 nxt_int_t res;
5037 nxt_port_t *port, *reply_port;
5038
5039 int notify;
5040 struct {
5041 nxt_port_msg_t pm;
5042 nxt_port_mmap_msg_t mm;
5043 } msg;
5044
5045
5046 app = req_rpc_data->app;
5047
5048 nxt_assert(app != NULL);
5049
5050 port = req_rpc_data->app_port;
5051
5052 nxt_assert(port != NULL);
5053 nxt_assert(port->queue != NULL);
5054
5055 reply_port = task->thread->engine->port;
5056
5057 buf = nxt_router_prepare_msg(task, req_rpc_data->request, app,
5058 nxt_app_msg_prefix[app->type]);
5059 if (nxt_slow_path(buf == NULL)) {
5060 nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message",
5061 req_rpc_data->stream, &app->name);
5062
5063 nxt_http_request_error(task, req_rpc_data->request,
5064 NXT_HTTP_INTERNAL_SERVER_ERROR);
5065
5066 return;
5067 }
5068
5069 nxt_debug(task, "about to send %O bytes buffer to app process port %d",
5070 nxt_buf_used_size(buf),
5071 port->socket.fd);
5072
5073 req_rpc_data->msg_info.buf = buf;
5074
5075 body = req_rpc_data->request->body;
5076
5077 if (body != NULL && nxt_buf_is_file(body)) {
5078 req_rpc_data->msg_info.body_fd = body->file->fd;
5079
5080 body->file->fd = -1;
5081
5082 } else {
5083 req_rpc_data->msg_info.body_fd = -1;
5084 }
5085
5086 msg.pm.stream = req_rpc_data->stream;
5087 msg.pm.pid = reply_port->pid;
5088 msg.pm.reply_port = reply_port->id;
5089 msg.pm.type = NXT_PORT_MSG_REQ_HEADERS;
5090 msg.pm.last = 0;
5091 msg.pm.mmap = 1;
5092 msg.pm.nf = 0;
5093 msg.pm.mf = 0;
5094 msg.pm.tracking = 0;
5095
5096 nxt_port_mmap_handler_t *mmap_handler = buf->parent;
5097 nxt_port_mmap_header_t *hdr = mmap_handler->hdr;
5098
5099 msg.mm.mmap_id = hdr->id;
5100 msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos);
5101 msg.mm.size = nxt_buf_used_size(buf);
5102
5103 res = nxt_app_queue_send(port->queue, &msg, sizeof(msg),
5104 req_rpc_data->stream, &notify,
5105 &req_rpc_data->msg_info.tracking_cookie);
5106 if (nxt_fast_path(res == NXT_OK)) {
5107 if (notify != 0) {
5108 (void) nxt_port_socket_write(task, port,
5109 NXT_PORT_MSG_READ_QUEUE,
5110 -1, req_rpc_data->stream,
5111 reply_port->id, NULL);
5112
5113 } else {
5114 nxt_debug(task, "queue is not empty");
5115 }
5116
5117 buf->is_port_mmap_sent = 1;
5118 buf->mem.pos = buf->mem.free;
5119
5120 } else {
5121 nxt_alert(task, "stream #%uD, app '%V': failed to send app message",
5122 req_rpc_data->stream, &app->name);
5123
5124 nxt_http_request_error(task, req_rpc_data->request,
5125 NXT_HTTP_INTERNAL_SERVER_ERROR);
5126 }
5127}
5128
5129
5130struct nxt_fields_iter_s {
5131 nxt_list_part_t *part;
5132 nxt_http_field_t *field;
5133};
5134
5135typedef struct nxt_fields_iter_s nxt_fields_iter_t;
5136
5137
5138static nxt_http_field_t *
5139nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
5140{
5141 if (part == NULL) {
5142 return NULL;
5143 }
5144
5145 while (part->nelts == 0) {
5146 part = part->next;
5147 if (part == NULL) {
5148 return NULL;
5149 }
5150 }
5151
5152 i->part = part;
5153 i->field = nxt_list_data(i->part);
5154
5155 return i->field;
5156}
5157
5158
5159static nxt_http_field_t *
5160nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
5161{
5162 return nxt_fields_part_first(nxt_list_part(fields), i);
5163}
5164
5165
5166static nxt_http_field_t *
5167nxt_fields_next(nxt_fields_iter_t *i)
5168{
5169 nxt_http_field_t *end = nxt_list_data(i->part);
5170
5171 end += i->part->nelts;
5172 i->field++;
5173
5174 if (i->field < end) {
5175 return i->field;
5176 }
5177
5178 return nxt_fields_part_first(i->part->next, i);
5179}
5180
5181
5182static nxt_buf_t *
5183nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
5184 nxt_app_t *app, const nxt_str_t *prefix)
5185{
5186 void *target_pos, *query_pos;
5187 u_char *pos, *end, *p, c;
5188 size_t fields_count, req_size, size, free_size;
5189 size_t copy_size;
5190 nxt_off_t content_length;
5191 nxt_buf_t *b, *buf, *out, **tail;
5192 nxt_http_field_t *field, *dup;
5193 nxt_unit_field_t *dst_field;
5194 nxt_fields_iter_t iter, dup_iter;
5195 nxt_unit_request_t *req;
5196
5197 req_size = sizeof(nxt_unit_request_t)
5198 + r->method->length + 1
5199 + r->version.length + 1
5200 + r->remote->length + 1
5201 + r->local->length + 1
5202 + r->server_name.length + 1
5203 + r->target.length + 1
5204 + (r->path->start != r->target.start ? r->path->length + 1 : 0);
5205
5206 content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
5207 fields_count = 0;
5208
5209 nxt_list_each(field, r->fields) {
5210 fields_count++;
5211
5212 req_size += field->name_length + prefix->length + 1
5213 + field->value_length + 1;
5214 } nxt_list_loop;
5215
5216 req_size += fields_count * sizeof(nxt_unit_field_t);
5217
5218 if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
5219 nxt_alert(task, "headers to big to fit in shared memory (%d)",
5220 (int) req_size);
5221
5222 return NULL;
5223 }
5224
5225 out = nxt_port_mmap_get_buf(task, &app->outgoing,
5226 nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
5227 if (nxt_slow_path(out == NULL)) {
5228 return NULL;
5229 }
5230
5231 req = (nxt_unit_request_t *) out->mem.free;
5232 out->mem.free += req_size;
5233
5234 req->app_target = r->app_target;
5235
5236 req->content_length = content_length;
5237
5238 p = (u_char *) (req->fields + fields_count);
5239
5240 nxt_debug(task, "fields_count=%d", (int) fields_count);
5241
5242 req->method_length = r->method->length;
5243 nxt_unit_sptr_set(&req->method, p);
5244 p = nxt_cpymem(p, r->method->start, r->method->length);
5245 *p++ = '\0';
5246
5247 req->version_length = r->version.length;
5248 nxt_unit_sptr_set(&req->version, p);
5249 p = nxt_cpymem(p, r->version.start, r->version.length);
5250 *p++ = '\0';
5251
5252 req->remote_length = r->remote->address_length;
5253 nxt_unit_sptr_set(&req->remote, p);
5254 p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
5255 r->remote->address_length);
5256 *p++ = '\0';
5257
5258 req->local_length = r->local->address_length;
5259 nxt_unit_sptr_set(&req->local, p);
5260 p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
5261 *p++ = '\0';
5262
5263 req->tls = (r->tls != NULL);
5264 req->websocket_handshake = r->websocket_handshake;
5265
5266 req->server_name_length = r->server_name.length;
5267 nxt_unit_sptr_set(&req->server_name, p);
5268 p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
5269 *p++ = '\0';
5270
5271 target_pos = p;
5272 req->target_length = (uint32_t) r->target.length;
5273 nxt_unit_sptr_set(&req->target, p);
5274 p = nxt_cpymem(p, r->target.start, r->target.length);
5275 *p++ = '\0';
5276
5277 req->path_length = (uint32_t) r->path->length;
5278 if (r->path->start == r->target.start) {
5279 nxt_unit_sptr_set(&req->path, target_pos);
5280
5281 } else {
5282 nxt_unit_sptr_set(&req->path, p);
5283 p = nxt_cpymem(p, r->path->start, r->path->length);
5284 *p++ = '\0';
5285 }
5286
5287 req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
5288 if (r->args != NULL && r->args->start != NULL) {
5289 query_pos = nxt_pointer_to(target_pos,
5290 r->args->start - r->target.start);
5291
5292 nxt_unit_sptr_set(&req->query, query_pos);
5293
5294 } else {
5295 req->query.offset = 0;
5296 }
5297
5298 req->content_length_field = NXT_UNIT_NONE_FIELD;
5299 req->content_type_field = NXT_UNIT_NONE_FIELD;
5300 req->cookie_field = NXT_UNIT_NONE_FIELD;
5301 req->authorization_field = NXT_UNIT_NONE_FIELD;
5302
5303 dst_field = req->fields;
5304
5305 for (field = nxt_fields_first(r->fields, &iter);
5306 field != NULL;
5307 field = nxt_fields_next(&iter))
5308 {
5309 if (field->skip) {
5310 continue;
5311 }
5312
5313 dst_field->hash = field->hash;
5314 dst_field->skip = 0;
5315 dst_field->name_length = field->name_length + prefix->length;
5316 dst_field->value_length = field->value_length;
5317
5318 if (field == r->content_length) {
5319 req->content_length_field = dst_field - req->fields;
5320
5321 } else if (field == r->content_type) {
5322 req->content_type_field = dst_field - req->fields;
5323
5324 } else if (field == r->cookie) {
5325 req->cookie_field = dst_field - req->fields;
5326
5327 } else if (field == r->authorization) {
5328 req->authorization_field = dst_field - req->fields;
5329 }
5330
5331 nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
5332 (int) field->hash, (int) field->skip,
5333 (int) field->name_length, field->name,
5334 (int) field->value_length, field->value);
5335
5336 if (prefix->length != 0) {
5337 nxt_unit_sptr_set(&dst_field->name, p);
5338 p = nxt_cpymem(p, prefix->start, prefix->length);
5339
5340 end = field->name + field->name_length;
5341 for (pos = field->name; pos < end; pos++) {
5342 c = *pos;
5343
5344 if (c >= 'a' && c <= 'z') {
5345 *p++ = (c & ~0x20);
5346 continue;
5347 }
5348
5349 if (c == '-') {
5350 *p++ = '_';
5351 continue;
5352 }
5353
5354 *p++ = c;
5355 }
5356
5357 } else {
5358 nxt_unit_sptr_set(&dst_field->name, p);
5359 p = nxt_cpymem(p, field->name, field->name_length);
5360 }
5361
5362 *p++ = '\0';
5363
5364 nxt_unit_sptr_set(&dst_field->value, p);
5365 p = nxt_cpymem(p, field->value, field->value_length);
5366
5367 if (prefix->length != 0) {
5368 dup_iter = iter;
5369
5370 for (dup = nxt_fields_next(&dup_iter);
5371 dup != NULL;
5372 dup = nxt_fields_next(&dup_iter))
5373 {
5374 if (dup->name_length != field->name_length
5375 || dup->skip
5376 || dup->hash != field->hash
5377 || nxt_memcasecmp(dup->name, field->name, dup->name_length))
5378 {
5379 continue;
5380 }
5381
5382 p = nxt_cpymem(p, ", ", 2);
5383 p = nxt_cpymem(p, dup->value, dup->value_length);
5384
5385 dst_field->value_length += 2 + dup->value_length;
5386
5387 dup->skip = 1;
5388 }
5389 }
5390
5391 *p++ = '\0';
5392
5393 dst_field++;
5394 }
5395
5396 req->fields_count = (uint32_t) (dst_field - req->fields);
5397
5398 nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5399
5400 buf = out;
5401 tail = &buf->next;
5402
5403 for (b = r->body; b != NULL; b = b->next) {
5404 size = nxt_buf_mem_used_size(&b->mem);
5405 pos = b->mem.pos;
5406
5407 while (size > 0) {
5408 if (buf == NULL) {
5409 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5410
5411 buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size);
5412 if (nxt_slow_path(buf == NULL)) {
5413 while (out != NULL) {
5414 buf = out->next;
5415 out->next = NULL;
5416 out->completion_handler(task, out, out->parent);
5417 out = buf;
5418 }
5419 return NULL;
5420 }
5421
5422 *tail = buf;
5423 tail = &buf->next;
5424
5425 } else {
5426 free_size = nxt_buf_mem_free_size(&buf->mem);
5427 if (free_size < size
5428 && nxt_port_mmap_increase_buf(task, buf, size, 1)
5429 == NXT_OK)
5430 {
5431 free_size = nxt_buf_mem_free_size(&buf->mem);
5432 }
5433 }
5434
5435 if (free_size > 0) {
5436 copy_size = nxt_min(free_size, size);
5437
5438 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5439
5440 size -= copy_size;
5441 pos += copy_size;
5442
5443 if (size == 0) {
5444 break;
5445 }
5446 }
5447
5448 buf = NULL;
5449 }
5450 }
5451
5452 return out;
5453}
5454
5455
5456static void
5457nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5458{
5459 nxt_timer_t *timer;
5460 nxt_http_request_t *r;
5461 nxt_request_rpc_data_t *req_rpc_data;
5462
5463 timer = obj;
5464
5465 nxt_debug(task, "router app timeout");
5466
5467 r = nxt_timer_data(timer, nxt_http_request_t, timer);
5468 req_rpc_data = r->timer_data;
5469
5470 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5471
5472 nxt_request_rpc_data_unlink(task, req_rpc_data);
5473}
5474
5475
5476static void
5477nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r)
5478{
5479 r->timer.handler = nxt_router_http_request_release;
5480 nxt_timer_add(task->thread->engine, &r->timer, 0);
5481}
5482
5483
5484static void
5485nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
5486{
5487 nxt_http_request_t *r;
5488
5489 nxt_debug(task, "http request pool release");
5490
5491 r = nxt_timer_data(obj, nxt_http_request_t, timer);
5492
5493 nxt_mp_release(r->mem_pool);
5494}
5495
5496
5497static void
5498nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5499{
5500 size_t mi;
5501 uint32_t i;
5502 nxt_bool_t ack;
5503 nxt_process_t *process;
5504 nxt_free_map_t *m;
5505 nxt_port_mmap_handler_t *mmap_handler;
5506
5507 nxt_debug(task, "oosm in %PI", msg->port_msg.pid);
5508
5509 process = nxt_runtime_process_find(task->thread->runtime,
5510 msg->port_msg.pid);
5511 if (nxt_slow_path(process == NULL)) {
5512 return;
5513 }
5514
5515 ack = 0;
5516
5517 /*
5518 * To mitigate possible racing condition (when OOSM message received
5519 * after some of the memory was already freed), need to try to find
5520 * first free segment in shared memory and send ACK if found.
5521 */
5522
5523 nxt_thread_mutex_lock(&process->incoming.mutex);
5524
5525 for (i = 0; i < process->incoming.size; i++) {
5526 mmap_handler = process->incoming.elts[i].mmap_handler;
5527
5528 if (nxt_slow_path(mmap_handler == NULL)) {
5529 continue;
5530 }
5531
5532 m = mmap_handler->hdr->free_map;
5533
5534 for (mi = 0; mi < MAX_FREE_IDX; mi++) {
5535 if (m[mi] != 0) {
5536 ack = 1;
5537
5538 nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA",
5539 i, mi, m[mi]);
5540
5541 break;
5542 }
5543 }
5544 }
5545
5546 nxt_thread_mutex_unlock(&process->incoming.mutex);
5547
5548 if (ack) {
5549 nxt_process_broadcast_shm_ack(task, process);
5550 }
5551}
5552
5553
5554static void
5555nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5556{
5557 nxt_fd_t fd;
5558 nxt_port_t *port;
5559 nxt_runtime_t *rt;
5560 nxt_port_mmaps_t *mmaps;
5561 nxt_port_msg_get_mmap_t *get_mmap_msg;
5562 nxt_port_mmap_handler_t *mmap_handler;
5563
5564 rt = task->thread->runtime;
5565
5566 port = nxt_runtime_port_find(rt, msg->port_msg.pid,
5567 msg->port_msg.reply_port);
5568 if (nxt_slow_path(port == NULL)) {
5569 nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found",
5570 msg->port_msg.pid, msg->port_msg.reply_port);
5571
5572 return;
5573 }
5574
5575 if (nxt_slow_path(nxt_buf_used_size(msg->buf)
5576 < (int) sizeof(nxt_port_msg_get_mmap_t)))
5577 {
5578 nxt_alert(task, "get_mmap_handler: message buffer too small (%d)",
5579 (int) nxt_buf_used_size(msg->buf));
5580
5581 return;
5582 }
5583
5584 get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos;
5585
5586 nxt_assert(port->type == NXT_PROCESS_APP);
5587
5588 if (nxt_slow_path(port->app == NULL)) {
5589 nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d",
5590 port->pid, port->id);
5591
5592 // FIXME
5593 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
5594 -1, msg->port_msg.stream, 0, NULL);
5595
5596 return;
5597 }
5598
5599 mmaps = &port->app->outgoing;
5600 nxt_thread_mutex_lock(&mmaps->mutex);
5601
5602 if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) {
5603 nxt_thread_mutex_unlock(&mmaps->mutex);
5604
5605 nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)",
5606 (int) get_mmap_msg->id);
5607
5608 // FIXME
5609 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
5610 -1, msg->port_msg.stream, 0, NULL);
5611 return;
5612 }
5613
5614 mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler;
5615
5616 fd = mmap_handler->fd;
5617
5618 nxt_thread_mutex_unlock(&mmaps->mutex);
5619
5620 nxt_debug(task, "get mmap %PI:%d found",
5621 msg->port_msg.pid, (int) get_mmap_msg->id);
5622
5623 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL);
5624}
5625
5626
5627static void
5628nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5629{
5630 nxt_port_t *port, *reply_port;
5631 nxt_runtime_t *rt;
5632 nxt_port_msg_get_port_t *get_port_msg;
5633
5634 rt = task->thread->runtime;
5635
5636 reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid,
5637 msg->port_msg.reply_port);
5638 if (nxt_slow_path(reply_port == NULL)) {
5639 nxt_alert(task, "get_port_handler: reply_port %PI:%d not found",
5640 msg->port_msg.pid, msg->port_msg.reply_port);
5641
5642 return;
5643 }
5644
5645 if (nxt_slow_path(nxt_buf_used_size(msg->buf)
5646 < (int) sizeof(nxt_port_msg_get_port_t)))
5647 {
5648 nxt_alert(task, "get_port_handler: message buffer too small (%d)",
5649 (int) nxt_buf_used_size(msg->buf));
5650
5651 return;
5652 }
5653
5654 get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos;
5655
5656 port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id);
5657 if (nxt_slow_path(port == NULL)) {
5658 nxt_alert(task, "get_port_handler: port %PI:%d not found",
5659 get_port_msg->pid, get_port_msg->id);
5660
5661 return;
5662 }
5663
5664 nxt_debug(task, "get port %PI:%d found", get_port_msg->pid,
5665 get_port_msg->id);
5666
5667 (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream);
5668}
5000 }
5001
5002 nxt_thread_mutex_destroy(&app->mutex);
5003 nxt_mp_destroy(app->mem_pool);
5004
5005 app_joint->app = NULL;
5006
5007 if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) {
5008 app_joint->idle_timer.handler = nxt_router_app_joint_release_handler;
5009 nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0);
5010
5011 } else {
5012 nxt_router_app_joint_use(task, app_joint, -1);
5013 }
5014}
5015
5016
5017static void
5018nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
5019 nxt_request_rpc_data_t *req_rpc_data)
5020{
5021 nxt_bool_t start_process;
5022 nxt_port_t *port;
5023 nxt_http_request_t *r;
5024
5025 start_process = 0;
5026
5027 nxt_thread_mutex_lock(&app->mutex);
5028
5029 port = app->shared_port;
5030 nxt_port_inc_use(port);
5031
5032 app->active_requests++;
5033
5034 if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) {
5035 app->pending_processes++;
5036 start_process = 1;
5037 }
5038
5039 r = req_rpc_data->request;
5040
5041 /*
5042 * Put request into application-wide list to be able to cancel request
5043 * if something goes wrong with application processes.
5044 */
5045 nxt_queue_insert_tail(&app->ack_waiting_req, &r->app_link);
5046
5047 nxt_thread_mutex_unlock(&app->mutex);
5048
5049 /*
5050 * Retain request memory pool while request is linked in ack_waiting_req
5051 * to guarantee request structure memory is accessble.
5052 */
5053 nxt_mp_retain(r->mem_pool);
5054
5055 req_rpc_data->app_port = port;
5056 req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED;
5057
5058 if (start_process) {
5059 nxt_router_start_app_process(task, app);
5060 }
5061}
5062
5063
5064void
5065nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
5066 nxt_http_action_t *action)
5067{
5068 nxt_event_engine_t *engine;
5069 nxt_http_app_conf_t *conf;
5070 nxt_request_rpc_data_t *req_rpc_data;
5071
5072 conf = action->u.conf;
5073 engine = task->thread->engine;
5074
5075 r->app_target = conf->target;
5076
5077 req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
5078 nxt_router_response_ready_handler,
5079 nxt_router_response_error_handler,
5080 sizeof(nxt_request_rpc_data_t));
5081 if (nxt_slow_path(req_rpc_data == NULL)) {
5082 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
5083 return;
5084 }
5085
5086 /*
5087 * At this point we have request req_rpc_data allocated and registered
5088 * in port handlers. Need to fixup request memory pool. Counterpart
5089 * release will be called via following call chain:
5090 * nxt_request_rpc_data_unlink() ->
5091 * nxt_router_http_request_release_post() ->
5092 * nxt_router_http_request_release()
5093 */
5094 nxt_mp_retain(r->mem_pool);
5095
5096 r->timer.task = &engine->task;
5097 r->timer.work_queue = &engine->fast_work_queue;
5098 r->timer.log = engine->task.log;
5099 r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
5100
5101 r->engine = engine;
5102 r->err_work.handler = nxt_router_http_request_error;
5103 r->err_work.task = task;
5104 r->err_work.obj = r;
5105
5106 req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
5107 req_rpc_data->app = conf->app;
5108 req_rpc_data->msg_info.body_fd = -1;
5109 req_rpc_data->rpc_cancel = 1;
5110
5111 nxt_router_app_use(task, conf->app, 1);
5112
5113 req_rpc_data->request = r;
5114 r->req_rpc_data = req_rpc_data;
5115
5116 if (r->last != NULL) {
5117 r->last->completion_handler = nxt_router_http_request_done;
5118 }
5119
5120 nxt_router_app_port_get(task, conf->app, req_rpc_data);
5121 nxt_router_app_prepare_request(task, req_rpc_data);
5122}
5123
5124
5125static void
5126nxt_router_http_request_error(nxt_task_t *task, void *obj, void *data)
5127{
5128 nxt_http_request_t *r;
5129
5130 r = obj;
5131
5132 nxt_debug(task, "router http request error (rpc_data %p)", r->req_rpc_data);
5133
5134 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5135
5136 if (r->req_rpc_data != NULL) {
5137 nxt_request_rpc_data_unlink(task, r->req_rpc_data);
5138 }
5139
5140 nxt_mp_release(r->mem_pool);
5141}
5142
5143
5144static void
5145nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data)
5146{
5147 nxt_http_request_t *r;
5148
5149 r = data;
5150
5151 nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data);
5152
5153 if (r->req_rpc_data != NULL) {
5154 nxt_request_rpc_data_unlink(task, r->req_rpc_data);
5155 }
5156
5157 nxt_http_request_close_handler(task, r, r->proto.any);
5158}
5159
5160
5161static void
5162nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
5163{
5164}
5165
5166
5167static void
5168nxt_router_app_prepare_request(nxt_task_t *task,
5169 nxt_request_rpc_data_t *req_rpc_data)
5170{
5171 nxt_app_t *app;
5172 nxt_buf_t *buf, *body;
5173 nxt_int_t res;
5174 nxt_port_t *port, *reply_port;
5175
5176 int notify;
5177 struct {
5178 nxt_port_msg_t pm;
5179 nxt_port_mmap_msg_t mm;
5180 } msg;
5181
5182
5183 app = req_rpc_data->app;
5184
5185 nxt_assert(app != NULL);
5186
5187 port = req_rpc_data->app_port;
5188
5189 nxt_assert(port != NULL);
5190 nxt_assert(port->queue != NULL);
5191
5192 reply_port = task->thread->engine->port;
5193
5194 buf = nxt_router_prepare_msg(task, req_rpc_data->request, app,
5195 nxt_app_msg_prefix[app->type]);
5196 if (nxt_slow_path(buf == NULL)) {
5197 nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message",
5198 req_rpc_data->stream, &app->name);
5199
5200 nxt_http_request_error(task, req_rpc_data->request,
5201 NXT_HTTP_INTERNAL_SERVER_ERROR);
5202
5203 return;
5204 }
5205
5206 nxt_debug(task, "about to send %O bytes buffer to app process port %d",
5207 nxt_buf_used_size(buf),
5208 port->socket.fd);
5209
5210 req_rpc_data->msg_info.buf = buf;
5211
5212 body = req_rpc_data->request->body;
5213
5214 if (body != NULL && nxt_buf_is_file(body)) {
5215 req_rpc_data->msg_info.body_fd = body->file->fd;
5216
5217 body->file->fd = -1;
5218
5219 } else {
5220 req_rpc_data->msg_info.body_fd = -1;
5221 }
5222
5223 msg.pm.stream = req_rpc_data->stream;
5224 msg.pm.pid = reply_port->pid;
5225 msg.pm.reply_port = reply_port->id;
5226 msg.pm.type = NXT_PORT_MSG_REQ_HEADERS;
5227 msg.pm.last = 0;
5228 msg.pm.mmap = 1;
5229 msg.pm.nf = 0;
5230 msg.pm.mf = 0;
5231 msg.pm.tracking = 0;
5232
5233 nxt_port_mmap_handler_t *mmap_handler = buf->parent;
5234 nxt_port_mmap_header_t *hdr = mmap_handler->hdr;
5235
5236 msg.mm.mmap_id = hdr->id;
5237 msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos);
5238 msg.mm.size = nxt_buf_used_size(buf);
5239
5240 res = nxt_app_queue_send(port->queue, &msg, sizeof(msg),
5241 req_rpc_data->stream, &notify,
5242 &req_rpc_data->msg_info.tracking_cookie);
5243 if (nxt_fast_path(res == NXT_OK)) {
5244 if (notify != 0) {
5245 (void) nxt_port_socket_write(task, port,
5246 NXT_PORT_MSG_READ_QUEUE,
5247 -1, req_rpc_data->stream,
5248 reply_port->id, NULL);
5249
5250 } else {
5251 nxt_debug(task, "queue is not empty");
5252 }
5253
5254 buf->is_port_mmap_sent = 1;
5255 buf->mem.pos = buf->mem.free;
5256
5257 } else {
5258 nxt_alert(task, "stream #%uD, app '%V': failed to send app message",
5259 req_rpc_data->stream, &app->name);
5260
5261 nxt_http_request_error(task, req_rpc_data->request,
5262 NXT_HTTP_INTERNAL_SERVER_ERROR);
5263 }
5264}
5265
5266
5267struct nxt_fields_iter_s {
5268 nxt_list_part_t *part;
5269 nxt_http_field_t *field;
5270};
5271
5272typedef struct nxt_fields_iter_s nxt_fields_iter_t;
5273
5274
5275static nxt_http_field_t *
5276nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
5277{
5278 if (part == NULL) {
5279 return NULL;
5280 }
5281
5282 while (part->nelts == 0) {
5283 part = part->next;
5284 if (part == NULL) {
5285 return NULL;
5286 }
5287 }
5288
5289 i->part = part;
5290 i->field = nxt_list_data(i->part);
5291
5292 return i->field;
5293}
5294
5295
5296static nxt_http_field_t *
5297nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
5298{
5299 return nxt_fields_part_first(nxt_list_part(fields), i);
5300}
5301
5302
5303static nxt_http_field_t *
5304nxt_fields_next(nxt_fields_iter_t *i)
5305{
5306 nxt_http_field_t *end = nxt_list_data(i->part);
5307
5308 end += i->part->nelts;
5309 i->field++;
5310
5311 if (i->field < end) {
5312 return i->field;
5313 }
5314
5315 return nxt_fields_part_first(i->part->next, i);
5316}
5317
5318
5319static nxt_buf_t *
5320nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
5321 nxt_app_t *app, const nxt_str_t *prefix)
5322{
5323 void *target_pos, *query_pos;
5324 u_char *pos, *end, *p, c;
5325 size_t fields_count, req_size, size, free_size;
5326 size_t copy_size;
5327 nxt_off_t content_length;
5328 nxt_buf_t *b, *buf, *out, **tail;
5329 nxt_http_field_t *field, *dup;
5330 nxt_unit_field_t *dst_field;
5331 nxt_fields_iter_t iter, dup_iter;
5332 nxt_unit_request_t *req;
5333
5334 req_size = sizeof(nxt_unit_request_t)
5335 + r->method->length + 1
5336 + r->version.length + 1
5337 + r->remote->length + 1
5338 + r->local->length + 1
5339 + r->server_name.length + 1
5340 + r->target.length + 1
5341 + (r->path->start != r->target.start ? r->path->length + 1 : 0);
5342
5343 content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
5344 fields_count = 0;
5345
5346 nxt_list_each(field, r->fields) {
5347 fields_count++;
5348
5349 req_size += field->name_length + prefix->length + 1
5350 + field->value_length + 1;
5351 } nxt_list_loop;
5352
5353 req_size += fields_count * sizeof(nxt_unit_field_t);
5354
5355 if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
5356 nxt_alert(task, "headers to big to fit in shared memory (%d)",
5357 (int) req_size);
5358
5359 return NULL;
5360 }
5361
5362 out = nxt_port_mmap_get_buf(task, &app->outgoing,
5363 nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
5364 if (nxt_slow_path(out == NULL)) {
5365 return NULL;
5366 }
5367
5368 req = (nxt_unit_request_t *) out->mem.free;
5369 out->mem.free += req_size;
5370
5371 req->app_target = r->app_target;
5372
5373 req->content_length = content_length;
5374
5375 p = (u_char *) (req->fields + fields_count);
5376
5377 nxt_debug(task, "fields_count=%d", (int) fields_count);
5378
5379 req->method_length = r->method->length;
5380 nxt_unit_sptr_set(&req->method, p);
5381 p = nxt_cpymem(p, r->method->start, r->method->length);
5382 *p++ = '\0';
5383
5384 req->version_length = r->version.length;
5385 nxt_unit_sptr_set(&req->version, p);
5386 p = nxt_cpymem(p, r->version.start, r->version.length);
5387 *p++ = '\0';
5388
5389 req->remote_length = r->remote->address_length;
5390 nxt_unit_sptr_set(&req->remote, p);
5391 p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
5392 r->remote->address_length);
5393 *p++ = '\0';
5394
5395 req->local_length = r->local->address_length;
5396 nxt_unit_sptr_set(&req->local, p);
5397 p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
5398 *p++ = '\0';
5399
5400 req->tls = (r->tls != NULL);
5401 req->websocket_handshake = r->websocket_handshake;
5402
5403 req->server_name_length = r->server_name.length;
5404 nxt_unit_sptr_set(&req->server_name, p);
5405 p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
5406 *p++ = '\0';
5407
5408 target_pos = p;
5409 req->target_length = (uint32_t) r->target.length;
5410 nxt_unit_sptr_set(&req->target, p);
5411 p = nxt_cpymem(p, r->target.start, r->target.length);
5412 *p++ = '\0';
5413
5414 req->path_length = (uint32_t) r->path->length;
5415 if (r->path->start == r->target.start) {
5416 nxt_unit_sptr_set(&req->path, target_pos);
5417
5418 } else {
5419 nxt_unit_sptr_set(&req->path, p);
5420 p = nxt_cpymem(p, r->path->start, r->path->length);
5421 *p++ = '\0';
5422 }
5423
5424 req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
5425 if (r->args != NULL && r->args->start != NULL) {
5426 query_pos = nxt_pointer_to(target_pos,
5427 r->args->start - r->target.start);
5428
5429 nxt_unit_sptr_set(&req->query, query_pos);
5430
5431 } else {
5432 req->query.offset = 0;
5433 }
5434
5435 req->content_length_field = NXT_UNIT_NONE_FIELD;
5436 req->content_type_field = NXT_UNIT_NONE_FIELD;
5437 req->cookie_field = NXT_UNIT_NONE_FIELD;
5438 req->authorization_field = NXT_UNIT_NONE_FIELD;
5439
5440 dst_field = req->fields;
5441
5442 for (field = nxt_fields_first(r->fields, &iter);
5443 field != NULL;
5444 field = nxt_fields_next(&iter))
5445 {
5446 if (field->skip) {
5447 continue;
5448 }
5449
5450 dst_field->hash = field->hash;
5451 dst_field->skip = 0;
5452 dst_field->name_length = field->name_length + prefix->length;
5453 dst_field->value_length = field->value_length;
5454
5455 if (field == r->content_length) {
5456 req->content_length_field = dst_field - req->fields;
5457
5458 } else if (field == r->content_type) {
5459 req->content_type_field = dst_field - req->fields;
5460
5461 } else if (field == r->cookie) {
5462 req->cookie_field = dst_field - req->fields;
5463
5464 } else if (field == r->authorization) {
5465 req->authorization_field = dst_field - req->fields;
5466 }
5467
5468 nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
5469 (int) field->hash, (int) field->skip,
5470 (int) field->name_length, field->name,
5471 (int) field->value_length, field->value);
5472
5473 if (prefix->length != 0) {
5474 nxt_unit_sptr_set(&dst_field->name, p);
5475 p = nxt_cpymem(p, prefix->start, prefix->length);
5476
5477 end = field->name + field->name_length;
5478 for (pos = field->name; pos < end; pos++) {
5479 c = *pos;
5480
5481 if (c >= 'a' && c <= 'z') {
5482 *p++ = (c & ~0x20);
5483 continue;
5484 }
5485
5486 if (c == '-') {
5487 *p++ = '_';
5488 continue;
5489 }
5490
5491 *p++ = c;
5492 }
5493
5494 } else {
5495 nxt_unit_sptr_set(&dst_field->name, p);
5496 p = nxt_cpymem(p, field->name, field->name_length);
5497 }
5498
5499 *p++ = '\0';
5500
5501 nxt_unit_sptr_set(&dst_field->value, p);
5502 p = nxt_cpymem(p, field->value, field->value_length);
5503
5504 if (prefix->length != 0) {
5505 dup_iter = iter;
5506
5507 for (dup = nxt_fields_next(&dup_iter);
5508 dup != NULL;
5509 dup = nxt_fields_next(&dup_iter))
5510 {
5511 if (dup->name_length != field->name_length
5512 || dup->skip
5513 || dup->hash != field->hash
5514 || nxt_memcasecmp(dup->name, field->name, dup->name_length))
5515 {
5516 continue;
5517 }
5518
5519 p = nxt_cpymem(p, ", ", 2);
5520 p = nxt_cpymem(p, dup->value, dup->value_length);
5521
5522 dst_field->value_length += 2 + dup->value_length;
5523
5524 dup->skip = 1;
5525 }
5526 }
5527
5528 *p++ = '\0';
5529
5530 dst_field++;
5531 }
5532
5533 req->fields_count = (uint32_t) (dst_field - req->fields);
5534
5535 nxt_unit_sptr_set(&req->preread_content, out->mem.free);
5536
5537 buf = out;
5538 tail = &buf->next;
5539
5540 for (b = r->body; b != NULL; b = b->next) {
5541 size = nxt_buf_mem_used_size(&b->mem);
5542 pos = b->mem.pos;
5543
5544 while (size > 0) {
5545 if (buf == NULL) {
5546 free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
5547
5548 buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size);
5549 if (nxt_slow_path(buf == NULL)) {
5550 while (out != NULL) {
5551 buf = out->next;
5552 out->next = NULL;
5553 out->completion_handler(task, out, out->parent);
5554 out = buf;
5555 }
5556 return NULL;
5557 }
5558
5559 *tail = buf;
5560 tail = &buf->next;
5561
5562 } else {
5563 free_size = nxt_buf_mem_free_size(&buf->mem);
5564 if (free_size < size
5565 && nxt_port_mmap_increase_buf(task, buf, size, 1)
5566 == NXT_OK)
5567 {
5568 free_size = nxt_buf_mem_free_size(&buf->mem);
5569 }
5570 }
5571
5572 if (free_size > 0) {
5573 copy_size = nxt_min(free_size, size);
5574
5575 buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
5576
5577 size -= copy_size;
5578 pos += copy_size;
5579
5580 if (size == 0) {
5581 break;
5582 }
5583 }
5584
5585 buf = NULL;
5586 }
5587 }
5588
5589 return out;
5590}
5591
5592
5593static void
5594nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
5595{
5596 nxt_timer_t *timer;
5597 nxt_http_request_t *r;
5598 nxt_request_rpc_data_t *req_rpc_data;
5599
5600 timer = obj;
5601
5602 nxt_debug(task, "router app timeout");
5603
5604 r = nxt_timer_data(timer, nxt_http_request_t, timer);
5605 req_rpc_data = r->timer_data;
5606
5607 nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
5608
5609 nxt_request_rpc_data_unlink(task, req_rpc_data);
5610}
5611
5612
5613static void
5614nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r)
5615{
5616 r->timer.handler = nxt_router_http_request_release;
5617 nxt_timer_add(task->thread->engine, &r->timer, 0);
5618}
5619
5620
5621static void
5622nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
5623{
5624 nxt_http_request_t *r;
5625
5626 nxt_debug(task, "http request pool release");
5627
5628 r = nxt_timer_data(obj, nxt_http_request_t, timer);
5629
5630 nxt_mp_release(r->mem_pool);
5631}
5632
5633
5634static void
5635nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5636{
5637 size_t mi;
5638 uint32_t i;
5639 nxt_bool_t ack;
5640 nxt_process_t *process;
5641 nxt_free_map_t *m;
5642 nxt_port_mmap_handler_t *mmap_handler;
5643
5644 nxt_debug(task, "oosm in %PI", msg->port_msg.pid);
5645
5646 process = nxt_runtime_process_find(task->thread->runtime,
5647 msg->port_msg.pid);
5648 if (nxt_slow_path(process == NULL)) {
5649 return;
5650 }
5651
5652 ack = 0;
5653
5654 /*
5655 * To mitigate possible racing condition (when OOSM message received
5656 * after some of the memory was already freed), need to try to find
5657 * first free segment in shared memory and send ACK if found.
5658 */
5659
5660 nxt_thread_mutex_lock(&process->incoming.mutex);
5661
5662 for (i = 0; i < process->incoming.size; i++) {
5663 mmap_handler = process->incoming.elts[i].mmap_handler;
5664
5665 if (nxt_slow_path(mmap_handler == NULL)) {
5666 continue;
5667 }
5668
5669 m = mmap_handler->hdr->free_map;
5670
5671 for (mi = 0; mi < MAX_FREE_IDX; mi++) {
5672 if (m[mi] != 0) {
5673 ack = 1;
5674
5675 nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA",
5676 i, mi, m[mi]);
5677
5678 break;
5679 }
5680 }
5681 }
5682
5683 nxt_thread_mutex_unlock(&process->incoming.mutex);
5684
5685 if (ack) {
5686 nxt_process_broadcast_shm_ack(task, process);
5687 }
5688}
5689
5690
5691static void
5692nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5693{
5694 nxt_fd_t fd;
5695 nxt_port_t *port;
5696 nxt_runtime_t *rt;
5697 nxt_port_mmaps_t *mmaps;
5698 nxt_port_msg_get_mmap_t *get_mmap_msg;
5699 nxt_port_mmap_handler_t *mmap_handler;
5700
5701 rt = task->thread->runtime;
5702
5703 port = nxt_runtime_port_find(rt, msg->port_msg.pid,
5704 msg->port_msg.reply_port);
5705 if (nxt_slow_path(port == NULL)) {
5706 nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found",
5707 msg->port_msg.pid, msg->port_msg.reply_port);
5708
5709 return;
5710 }
5711
5712 if (nxt_slow_path(nxt_buf_used_size(msg->buf)
5713 < (int) sizeof(nxt_port_msg_get_mmap_t)))
5714 {
5715 nxt_alert(task, "get_mmap_handler: message buffer too small (%d)",
5716 (int) nxt_buf_used_size(msg->buf));
5717
5718 return;
5719 }
5720
5721 get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos;
5722
5723 nxt_assert(port->type == NXT_PROCESS_APP);
5724
5725 if (nxt_slow_path(port->app == NULL)) {
5726 nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d",
5727 port->pid, port->id);
5728
5729 // FIXME
5730 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
5731 -1, msg->port_msg.stream, 0, NULL);
5732
5733 return;
5734 }
5735
5736 mmaps = &port->app->outgoing;
5737 nxt_thread_mutex_lock(&mmaps->mutex);
5738
5739 if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) {
5740 nxt_thread_mutex_unlock(&mmaps->mutex);
5741
5742 nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)",
5743 (int) get_mmap_msg->id);
5744
5745 // FIXME
5746 nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
5747 -1, msg->port_msg.stream, 0, NULL);
5748 return;
5749 }
5750
5751 mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler;
5752
5753 fd = mmap_handler->fd;
5754
5755 nxt_thread_mutex_unlock(&mmaps->mutex);
5756
5757 nxt_debug(task, "get mmap %PI:%d found",
5758 msg->port_msg.pid, (int) get_mmap_msg->id);
5759
5760 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL);
5761}
5762
5763
5764static void
5765nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5766{
5767 nxt_port_t *port, *reply_port;
5768 nxt_runtime_t *rt;
5769 nxt_port_msg_get_port_t *get_port_msg;
5770
5771 rt = task->thread->runtime;
5772
5773 reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid,
5774 msg->port_msg.reply_port);
5775 if (nxt_slow_path(reply_port == NULL)) {
5776 nxt_alert(task, "get_port_handler: reply_port %PI:%d not found",
5777 msg->port_msg.pid, msg->port_msg.reply_port);
5778
5779 return;
5780 }
5781
5782 if (nxt_slow_path(nxt_buf_used_size(msg->buf)
5783 < (int) sizeof(nxt_port_msg_get_port_t)))
5784 {
5785 nxt_alert(task, "get_port_handler: message buffer too small (%d)",
5786 (int) nxt_buf_used_size(msg->buf));
5787
5788 return;
5789 }
5790
5791 get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos;
5792
5793 port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id);
5794 if (nxt_slow_path(port == NULL)) {
5795 nxt_alert(task, "get_port_handler: port %PI:%d not found",
5796 get_port_msg->pid, get_port_msg->id);
5797
5798 return;
5799 }
5800
5801 nxt_debug(task, "get port %PI:%d found", get_port_msg->pid,
5802 get_port_msg->id);
5803
5804 (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream);
5805}