xref: /unit/src/nxt_controller.c (revision 1488)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
820Sigor@sysoev.ru #include <nxt_main.h>
920Sigor@sysoev.ru #include <nxt_runtime.h>
10240Sigor@sysoev.ru #include <nxt_main_process.h>
1129Svbart@nginx.com #include <nxt_conf.h>
12774Svbart@nginx.com #include <nxt_cert.h>
1320Sigor@sysoev.ru 
1420Sigor@sysoev.ru 
1527Svbart@nginx.com typedef struct {
16106Svbart@nginx.com     nxt_conf_value_t  *root;
17106Svbart@nginx.com     nxt_mp_t          *pool;
1844Svbart@nginx.com } nxt_controller_conf_t;
1944Svbart@nginx.com 
2044Svbart@nginx.com 
2144Svbart@nginx.com typedef struct {
2227Svbart@nginx.com     nxt_http_request_parse_t  parser;
2327Svbart@nginx.com     size_t                    length;
2444Svbart@nginx.com     nxt_controller_conf_t     conf;
25140Svbart@nginx.com     nxt_conn_t                *conn;
26140Svbart@nginx.com     nxt_queue_link_t          link;
2727Svbart@nginx.com } nxt_controller_request_t;
2827Svbart@nginx.com 
2927Svbart@nginx.com 
3044Svbart@nginx.com typedef struct {
31208Svbart@nginx.com     nxt_uint_t        status;
32106Svbart@nginx.com     nxt_conf_value_t  *conf;
33208Svbart@nginx.com 
34208Svbart@nginx.com     u_char            *title;
35357Svbart@nginx.com     nxt_str_t         detail;
36208Svbart@nginx.com     ssize_t           offset;
37208Svbart@nginx.com     nxt_uint_t        line;
38208Svbart@nginx.com     nxt_uint_t        column;
3944Svbart@nginx.com } nxt_controller_response_t;
4044Svbart@nginx.com 
4144Svbart@nginx.com 
42*1488St.nateldemoura@f5.com static nxt_int_t nxt_controller_prefork(nxt_task_t *task,
43*1488St.nateldemoura@f5.com     nxt_process_t *process, nxt_mp_t *mp);
44*1488St.nateldemoura@f5.com static nxt_int_t nxt_controller_start(nxt_task_t *task,
45*1488St.nateldemoura@f5.com     nxt_process_data_t *data);
46248Svbart@nginx.com static void nxt_controller_process_new_port_handler(nxt_task_t *task,
47248Svbart@nginx.com     nxt_port_recv_msg_t *msg);
48662Smax.romanov@nginx.com static void nxt_controller_send_current_conf(nxt_task_t *task);
49662Smax.romanov@nginx.com static void nxt_controller_router_ready_handler(nxt_task_t *task,
50662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
51*1488St.nateldemoura@f5.com static void nxt_controller_remove_pid_handler(nxt_task_t *task,
52*1488St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg);
53249Svbart@nginx.com static nxt_int_t nxt_controller_conf_default(void);
54249Svbart@nginx.com static void nxt_controller_conf_init_handler(nxt_task_t *task,
55249Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
561469Smax.romanov@nginx.com static void nxt_controller_flush_requests(nxt_task_t *task);
57249Svbart@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task,
58249Svbart@nginx.com     nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data);
59248Svbart@nginx.com 
6020Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
6120Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
6262Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c,
6320Sigor@sysoev.ru     uintptr_t data);
6420Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
6520Sigor@sysoev.ru     void *data);
6620Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
6720Sigor@sysoev.ru     void *data);
6827Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
6927Svbart@nginx.com     void *data);
7027Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
7127Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
7227Svbart@nginx.com     void *data);
7327Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
7427Svbart@nginx.com     void *data);
7520Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
7620Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
7720Sigor@sysoev.ru 
7827Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx,
79417Svbart@nginx.com     nxt_http_field_t *field, uintptr_t data);
8027Svbart@nginx.com 
8127Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task,
82140Svbart@nginx.com     nxt_controller_request_t *req);
83774Svbart@nginx.com static void nxt_controller_process_config(nxt_task_t *task,
84774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
851470Smax.romanov@nginx.com static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task);
86774Svbart@nginx.com #if (NXT_TLS)
87774Svbart@nginx.com static void nxt_controller_process_cert(nxt_task_t *task,
88774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
89774Svbart@nginx.com static void nxt_controller_process_cert_save(nxt_task_t *task,
90774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
91774Svbart@nginx.com static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
92*1488St.nateldemoura@f5.com static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
93*1488St.nateldemoura@f5.com     void *data);
94774Svbart@nginx.com #endif
95238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task,
96238Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
97314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task,
98314Svbart@nginx.com     nxt_conf_value_t *conf);
99140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task,
100140Svbart@nginx.com     nxt_controller_request_t *req, nxt_controller_response_t *resp);
101208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
102208Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
10327Svbart@nginx.com 
10427Svbart@nginx.com 
105417Svbart@nginx.com static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
10627Svbart@nginx.com     { nxt_string("Content-Length"),
10727Svbart@nginx.com       &nxt_controller_request_content_length, 0 },
10827Svbart@nginx.com };
10927Svbart@nginx.com 
110417Svbart@nginx.com static nxt_lvlhsh_t            nxt_controller_fields_hash;
11127Svbart@nginx.com 
112314Svbart@nginx.com static nxt_uint_t              nxt_controller_listening;
113662Smax.romanov@nginx.com static nxt_uint_t              nxt_controller_router_ready;
114238Svbart@nginx.com static nxt_controller_conf_t   nxt_controller_conf;
115238Svbart@nginx.com static nxt_queue_t             nxt_controller_waiting_requests;
1161469Smax.romanov@nginx.com static nxt_bool_t              nxt_controller_waiting_init_conf;
11727Svbart@nginx.com 
11820Sigor@sysoev.ru 
11920Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
12027Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
12127Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
12220Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
12320Sigor@sysoev.ru 
12420Sigor@sysoev.ru 
125*1488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
126*1488St.nateldemoura@f5.com     .quit           = nxt_signal_quit_handler,
127662Smax.romanov@nginx.com     .new_port       = nxt_controller_process_new_port_handler,
128662Smax.romanov@nginx.com     .change_file    = nxt_port_change_log_file_handler,
129662Smax.romanov@nginx.com     .mmap           = nxt_port_mmap_handler,
130662Smax.romanov@nginx.com     .process_ready  = nxt_controller_router_ready_handler,
131662Smax.romanov@nginx.com     .data           = nxt_port_data_handler,
132*1488St.nateldemoura@f5.com     .remove_pid     = nxt_controller_remove_pid_handler,
133662Smax.romanov@nginx.com     .rpc_ready      = nxt_port_rpc_handler,
134662Smax.romanov@nginx.com     .rpc_error      = nxt_port_rpc_handler,
135248Svbart@nginx.com };
136248Svbart@nginx.com 
137248Svbart@nginx.com 
138*1488St.nateldemoura@f5.com const nxt_process_init_t  nxt_controller_process = {
139*1488St.nateldemoura@f5.com     .name           = "controller",
140*1488St.nateldemoura@f5.com     .type           = NXT_PROCESS_CONTROLLER,
141*1488St.nateldemoura@f5.com     .prefork        = nxt_controller_prefork,
142*1488St.nateldemoura@f5.com     .restart        = 1,
143*1488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
144*1488St.nateldemoura@f5.com     .start          = nxt_controller_start,
145*1488St.nateldemoura@f5.com     .port_handlers  = &nxt_controller_process_port_handlers,
146*1488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
147*1488St.nateldemoura@f5.com };
148*1488St.nateldemoura@f5.com 
149*1488St.nateldemoura@f5.com 
150*1488St.nateldemoura@f5.com static nxt_int_t
151*1488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
152*1488St.nateldemoura@f5.com {
153*1488St.nateldemoura@f5.com     ssize_t                n;
154*1488St.nateldemoura@f5.com     nxt_int_t              ret;
155*1488St.nateldemoura@f5.com     nxt_str_t              *conf;
156*1488St.nateldemoura@f5.com     nxt_file_t             file;
157*1488St.nateldemoura@f5.com     nxt_runtime_t          *rt;
158*1488St.nateldemoura@f5.com     nxt_file_info_t        fi;
159*1488St.nateldemoura@f5.com     nxt_controller_init_t  ctrl_init;
160*1488St.nateldemoura@f5.com 
161*1488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "controller started");
162*1488St.nateldemoura@f5.com 
163*1488St.nateldemoura@f5.com     rt = task->thread->runtime;
164*1488St.nateldemoura@f5.com 
165*1488St.nateldemoura@f5.com     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
166*1488St.nateldemoura@f5.com 
167*1488St.nateldemoura@f5.com     conf = &ctrl_init.conf;
168*1488St.nateldemoura@f5.com 
169*1488St.nateldemoura@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
170*1488St.nateldemoura@f5.com 
171*1488St.nateldemoura@f5.com     file.name = (nxt_file_name_t *) rt->conf;
172*1488St.nateldemoura@f5.com 
173*1488St.nateldemoura@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
174*1488St.nateldemoura@f5.com 
175*1488St.nateldemoura@f5.com     if (ret == NXT_OK) {
176*1488St.nateldemoura@f5.com         ret = nxt_file_info(&file, &fi);
177*1488St.nateldemoura@f5.com 
178*1488St.nateldemoura@f5.com         if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
179*1488St.nateldemoura@f5.com             conf->length = nxt_file_size(&fi);
180*1488St.nateldemoura@f5.com             conf->start = nxt_mp_alloc(mp, conf->length);
181*1488St.nateldemoura@f5.com             if (nxt_slow_path(conf->start == NULL)) {
182*1488St.nateldemoura@f5.com                 nxt_file_close(task, &file);
183*1488St.nateldemoura@f5.com                 return NXT_ERROR;
184*1488St.nateldemoura@f5.com             }
185*1488St.nateldemoura@f5.com 
186*1488St.nateldemoura@f5.com             n = nxt_file_read(&file, conf->start, conf->length, 0);
187*1488St.nateldemoura@f5.com 
188*1488St.nateldemoura@f5.com             if (nxt_slow_path(n != (ssize_t) conf->length)) {
189*1488St.nateldemoura@f5.com                 conf->start = NULL;
190*1488St.nateldemoura@f5.com                 conf->length = 0;
191*1488St.nateldemoura@f5.com 
192*1488St.nateldemoura@f5.com                 nxt_alert(task, "failed to restore previous configuration: "
193*1488St.nateldemoura@f5.com                           "cannot read the file");
194*1488St.nateldemoura@f5.com             }
195*1488St.nateldemoura@f5.com         }
196*1488St.nateldemoura@f5.com 
197*1488St.nateldemoura@f5.com         nxt_file_close(task, &file);
198*1488St.nateldemoura@f5.com     }
199*1488St.nateldemoura@f5.com 
200*1488St.nateldemoura@f5.com #if (NXT_TLS)
201*1488St.nateldemoura@f5.com     ctrl_init.certs = nxt_cert_store_load(task, mp);
202*1488St.nateldemoura@f5.com 
203*1488St.nateldemoura@f5.com     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
204*1488St.nateldemoura@f5.com #endif
205*1488St.nateldemoura@f5.com 
206*1488St.nateldemoura@f5.com     process->data.controller = ctrl_init;
207*1488St.nateldemoura@f5.com 
208*1488St.nateldemoura@f5.com     return NXT_OK;
209*1488St.nateldemoura@f5.com }
210*1488St.nateldemoura@f5.com 
211*1488St.nateldemoura@f5.com 
212*1488St.nateldemoura@f5.com #if (NXT_TLS)
213*1488St.nateldemoura@f5.com 
214*1488St.nateldemoura@f5.com static void
215*1488St.nateldemoura@f5.com nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
216*1488St.nateldemoura@f5.com {
217*1488St.nateldemoura@f5.com     pid_t          main_pid;
218*1488St.nateldemoura@f5.com     nxt_array_t    *certs;
219*1488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
220*1488St.nateldemoura@f5.com 
221*1488St.nateldemoura@f5.com     certs = obj;
222*1488St.nateldemoura@f5.com     rt = data;
223*1488St.nateldemoura@f5.com 
224*1488St.nateldemoura@f5.com     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
225*1488St.nateldemoura@f5.com 
226*1488St.nateldemoura@f5.com     if (nxt_pid == main_pid && certs != NULL) {
227*1488St.nateldemoura@f5.com         nxt_cert_store_release(certs);
228*1488St.nateldemoura@f5.com     }
229*1488St.nateldemoura@f5.com }
230*1488St.nateldemoura@f5.com 
231*1488St.nateldemoura@f5.com #endif
232*1488St.nateldemoura@f5.com 
233*1488St.nateldemoura@f5.com 
234*1488St.nateldemoura@f5.com static nxt_int_t
235*1488St.nateldemoura@f5.com nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
23620Sigor@sysoev.ru {
237417Svbart@nginx.com     nxt_mp_t               *mp;
238417Svbart@nginx.com     nxt_int_t              ret;
239417Svbart@nginx.com     nxt_str_t              *json;
240417Svbart@nginx.com     nxt_conf_value_t       *conf;
241417Svbart@nginx.com     nxt_conf_validation_t  vldt;
242774Svbart@nginx.com     nxt_controller_init_t  *init;
24327Svbart@nginx.com 
2441459Smax.romanov@nginx.com     ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
245417Svbart@nginx.com                                nxt_controller_request_fields,
246417Svbart@nginx.com                                nxt_nitems(nxt_controller_request_fields));
247417Svbart@nginx.com 
248417Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
24927Svbart@nginx.com         return NXT_ERROR;
25027Svbart@nginx.com     }
25127Svbart@nginx.com 
252248Svbart@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
25327Svbart@nginx.com 
254*1488St.nateldemoura@f5.com     init = &data->controller;
255774Svbart@nginx.com 
256774Svbart@nginx.com #if (NXT_TLS)
257774Svbart@nginx.com     if (init->certs != NULL) {
258774Svbart@nginx.com         nxt_cert_info_init(task, init->certs);
259774Svbart@nginx.com         nxt_cert_store_release(init->certs);
260774Svbart@nginx.com     }
261774Svbart@nginx.com #endif
262774Svbart@nginx.com 
263774Svbart@nginx.com     json = &init->conf;
264774Svbart@nginx.com 
265774Svbart@nginx.com     if (json->start == NULL) {
266314Svbart@nginx.com         return NXT_OK;
267314Svbart@nginx.com     }
268314Svbart@nginx.com 
269314Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
270314Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
271314Svbart@nginx.com         return NXT_ERROR;
272314Svbart@nginx.com     }
273314Svbart@nginx.com 
274314Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, json);
275314Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
276564Svbart@nginx.com         nxt_alert(task, "failed to restore previous configuration: "
277564Svbart@nginx.com                   "file is corrupted or not enough memory");
278314Svbart@nginx.com 
279314Svbart@nginx.com         nxt_mp_destroy(mp);
280314Svbart@nginx.com         return NXT_OK;
281314Svbart@nginx.com     }
282314Svbart@nginx.com 
283357Svbart@nginx.com     nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
284314Svbart@nginx.com 
285357Svbart@nginx.com     vldt.pool = nxt_mp_create(1024, 128, 256, 32);
286357Svbart@nginx.com     if (nxt_slow_path(vldt.pool == NULL)) {
2871013Smax.romanov@nginx.com         nxt_mp_destroy(mp);
288357Svbart@nginx.com         return NXT_ERROR;
289314Svbart@nginx.com     }
290314Svbart@nginx.com 
291357Svbart@nginx.com     vldt.conf = conf;
292357Svbart@nginx.com 
293357Svbart@nginx.com     ret = nxt_conf_validate(&vldt);
294357Svbart@nginx.com 
295357Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
296357Svbart@nginx.com 
297357Svbart@nginx.com         if (ret == NXT_DECLINED) {
298564Svbart@nginx.com             nxt_alert(task, "the previous configuration is invalid: %V",
299564Svbart@nginx.com                       &vldt.error);
300357Svbart@nginx.com 
301357Svbart@nginx.com             nxt_mp_destroy(vldt.pool);
302357Svbart@nginx.com             nxt_mp_destroy(mp);
303357Svbart@nginx.com 
304357Svbart@nginx.com             return NXT_OK;
305357Svbart@nginx.com         }
306357Svbart@nginx.com 
307357Svbart@nginx.com         /* ret == NXT_ERROR */
308357Svbart@nginx.com 
309357Svbart@nginx.com         return NXT_ERROR;
310357Svbart@nginx.com     }
311357Svbart@nginx.com 
312357Svbart@nginx.com     nxt_mp_destroy(vldt.pool);
313314Svbart@nginx.com 
314314Svbart@nginx.com     nxt_controller_conf.root = conf;
315314Svbart@nginx.com     nxt_controller_conf.pool = mp;
316314Svbart@nginx.com 
317248Svbart@nginx.com     return NXT_OK;
318248Svbart@nginx.com }
319248Svbart@nginx.com 
320248Svbart@nginx.com 
321248Svbart@nginx.com static void
322248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task,
323248Svbart@nginx.com     nxt_port_recv_msg_t *msg)
324248Svbart@nginx.com {
325662Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
326662Smax.romanov@nginx.com 
327662Smax.romanov@nginx.com     if (msg->u.new_port->type != NXT_PROCESS_ROUTER
328662Smax.romanov@nginx.com         || !nxt_controller_router_ready)
329662Smax.romanov@nginx.com     {
330662Smax.romanov@nginx.com         return;
331662Smax.romanov@nginx.com     }
332662Smax.romanov@nginx.com 
333662Smax.romanov@nginx.com     nxt_controller_send_current_conf(task);
334662Smax.romanov@nginx.com }
335662Smax.romanov@nginx.com 
336662Smax.romanov@nginx.com 
337662Smax.romanov@nginx.com static void
338662Smax.romanov@nginx.com nxt_controller_send_current_conf(nxt_task_t *task)
339662Smax.romanov@nginx.com {
340249Svbart@nginx.com     nxt_int_t         rc;
341248Svbart@nginx.com     nxt_runtime_t     *rt;
342248Svbart@nginx.com     nxt_conf_value_t  *conf;
343248Svbart@nginx.com 
344249Svbart@nginx.com     conf = nxt_controller_conf.root;
345249Svbart@nginx.com 
346249Svbart@nginx.com     if (conf != NULL) {
347249Svbart@nginx.com         rc = nxt_controller_conf_send(task, conf,
348249Svbart@nginx.com                                       nxt_controller_conf_init_handler, NULL);
34944Svbart@nginx.com 
350249Svbart@nginx.com         if (nxt_fast_path(rc == NXT_OK)) {
3511469Smax.romanov@nginx.com             nxt_controller_waiting_init_conf = 1;
3521469Smax.romanov@nginx.com 
353249Svbart@nginx.com             return;
354249Svbart@nginx.com         }
355249Svbart@nginx.com 
356249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
357249Svbart@nginx.com 
358249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
359249Svbart@nginx.com             nxt_abort();
360249Svbart@nginx.com         }
36144Svbart@nginx.com     }
36244Svbart@nginx.com 
363249Svbart@nginx.com     if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
364248Svbart@nginx.com         nxt_abort();
36544Svbart@nginx.com     }
36644Svbart@nginx.com 
367248Svbart@nginx.com     rt = task->thread->runtime;
368140Svbart@nginx.com 
369248Svbart@nginx.com     if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
370248Svbart@nginx.com         nxt_abort();
371248Svbart@nginx.com     }
372314Svbart@nginx.com 
373314Svbart@nginx.com     nxt_controller_listening = 1;
3741470Smax.romanov@nginx.com 
3751470Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
37620Sigor@sysoev.ru }
37720Sigor@sysoev.ru 
37820Sigor@sysoev.ru 
379662Smax.romanov@nginx.com static void
380662Smax.romanov@nginx.com nxt_controller_router_ready_handler(nxt_task_t *task,
381662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg)
382662Smax.romanov@nginx.com {
383662Smax.romanov@nginx.com     nxt_port_t     *router_port;
384662Smax.romanov@nginx.com     nxt_runtime_t  *rt;
385662Smax.romanov@nginx.com 
386662Smax.romanov@nginx.com     rt = task->thread->runtime;
387662Smax.romanov@nginx.com 
388662Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
389662Smax.romanov@nginx.com 
390662Smax.romanov@nginx.com     nxt_controller_router_ready = 1;
391662Smax.romanov@nginx.com 
392662Smax.romanov@nginx.com     if (router_port != NULL) {
393662Smax.romanov@nginx.com         nxt_controller_send_current_conf(task);
394662Smax.romanov@nginx.com     }
395662Smax.romanov@nginx.com }
396662Smax.romanov@nginx.com 
397662Smax.romanov@nginx.com 
398*1488St.nateldemoura@f5.com static void
399*1488St.nateldemoura@f5.com nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
400*1488St.nateldemoura@f5.com {
401*1488St.nateldemoura@f5.com     nxt_pid_t      pid;
402*1488St.nateldemoura@f5.com     nxt_process_t  *process;
403*1488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
404*1488St.nateldemoura@f5.com 
405*1488St.nateldemoura@f5.com     rt = task->thread->runtime;
406*1488St.nateldemoura@f5.com 
407*1488St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
408*1488St.nateldemoura@f5.com 
409*1488St.nateldemoura@f5.com     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
410*1488St.nateldemoura@f5.com 
411*1488St.nateldemoura@f5.com     process = nxt_runtime_process_find(rt, pid);
412*1488St.nateldemoura@f5.com     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
413*1488St.nateldemoura@f5.com         nxt_controller_router_ready = 0;
414*1488St.nateldemoura@f5.com     }
415*1488St.nateldemoura@f5.com 
416*1488St.nateldemoura@f5.com     nxt_port_remove_pid_handler(task, msg);
417*1488St.nateldemoura@f5.com }
418*1488St.nateldemoura@f5.com 
419*1488St.nateldemoura@f5.com 
420249Svbart@nginx.com static nxt_int_t
421249Svbart@nginx.com nxt_controller_conf_default(void)
422249Svbart@nginx.com {
423249Svbart@nginx.com     nxt_mp_t          *mp;
424249Svbart@nginx.com     nxt_conf_value_t  *conf;
425249Svbart@nginx.com 
426249Svbart@nginx.com     static const nxt_str_t json
427249Svbart@nginx.com         = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
428249Svbart@nginx.com 
429249Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
430249Svbart@nginx.com 
431249Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
432249Svbart@nginx.com         return NXT_ERROR;
433249Svbart@nginx.com     }
434249Svbart@nginx.com 
435249Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, &json);
436249Svbart@nginx.com 
437249Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
438249Svbart@nginx.com         return NXT_ERROR;
439249Svbart@nginx.com     }
440249Svbart@nginx.com 
441249Svbart@nginx.com     nxt_controller_conf.root = conf;
442249Svbart@nginx.com     nxt_controller_conf.pool = mp;
443249Svbart@nginx.com 
444249Svbart@nginx.com     return NXT_OK;
445249Svbart@nginx.com }
446249Svbart@nginx.com 
447249Svbart@nginx.com 
448249Svbart@nginx.com static void
449249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
450249Svbart@nginx.com     void *data)
451249Svbart@nginx.com {
452314Svbart@nginx.com     nxt_runtime_t  *rt;
453314Svbart@nginx.com 
4541469Smax.romanov@nginx.com     nxt_controller_waiting_init_conf = 0;
4551469Smax.romanov@nginx.com 
456249Svbart@nginx.com     if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
457564Svbart@nginx.com         nxt_alert(task, "failed to apply previous configuration");
458314Svbart@nginx.com 
459249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
460249Svbart@nginx.com 
461249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
462249Svbart@nginx.com             nxt_abort();
463249Svbart@nginx.com         }
464249Svbart@nginx.com     }
465314Svbart@nginx.com 
466314Svbart@nginx.com     if (nxt_controller_listening == 0) {
467314Svbart@nginx.com         rt = task->thread->runtime;
468314Svbart@nginx.com 
469314Svbart@nginx.com         if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
470314Svbart@nginx.com                           == NULL))
471314Svbart@nginx.com         {
472314Svbart@nginx.com             nxt_abort();
473314Svbart@nginx.com         }
474314Svbart@nginx.com 
475314Svbart@nginx.com         nxt_controller_listening = 1;
476314Svbart@nginx.com     }
4771469Smax.romanov@nginx.com 
4781469Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
4791469Smax.romanov@nginx.com }
4801469Smax.romanov@nginx.com 
4811469Smax.romanov@nginx.com 
4821469Smax.romanov@nginx.com static void
4831469Smax.romanov@nginx.com nxt_controller_flush_requests(nxt_task_t *task)
4841469Smax.romanov@nginx.com {
4851469Smax.romanov@nginx.com     nxt_queue_t               queue;
4861469Smax.romanov@nginx.com     nxt_controller_request_t  *req;
4871469Smax.romanov@nginx.com 
4881469Smax.romanov@nginx.com     nxt_queue_init(&queue);
4891469Smax.romanov@nginx.com     nxt_queue_add(&queue, &nxt_controller_waiting_requests);
4901469Smax.romanov@nginx.com 
4911469Smax.romanov@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
4921469Smax.romanov@nginx.com 
4931469Smax.romanov@nginx.com     nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
4941469Smax.romanov@nginx.com         nxt_controller_process_request(task, req);
4951469Smax.romanov@nginx.com     } nxt_queue_loop;
496249Svbart@nginx.com }
497249Svbart@nginx.com 
498249Svbart@nginx.com 
499249Svbart@nginx.com static nxt_int_t
500249Svbart@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_conf_value_t *conf,
501249Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *data)
502249Svbart@nginx.com {
503249Svbart@nginx.com     size_t         size;
504249Svbart@nginx.com     uint32_t       stream;
505249Svbart@nginx.com     nxt_int_t      rc;
506249Svbart@nginx.com     nxt_buf_t      *b;
507249Svbart@nginx.com     nxt_port_t     *router_port, *controller_port;
508249Svbart@nginx.com     nxt_runtime_t  *rt;
509249Svbart@nginx.com 
510249Svbart@nginx.com     rt = task->thread->runtime;
511249Svbart@nginx.com 
512249Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
513249Svbart@nginx.com 
5141470Smax.romanov@nginx.com     nxt_assert(router_port != NULL);
5151470Smax.romanov@nginx.com     nxt_assert(nxt_controller_router_ready);
516249Svbart@nginx.com 
517249Svbart@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
518249Svbart@nginx.com 
519249Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
520249Svbart@nginx.com 
521249Svbart@nginx.com     b = nxt_port_mmap_get_buf(task, router_port, size);
522379Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
523379Smax.romanov@nginx.com         return NXT_ERROR;
524379Smax.romanov@nginx.com     }
525249Svbart@nginx.com 
526249Svbart@nginx.com     b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL);
527249Svbart@nginx.com 
528249Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
529249Svbart@nginx.com                                            handler, handler,
530249Svbart@nginx.com                                            router_port->pid, data);
531249Svbart@nginx.com 
532645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
533645Svbart@nginx.com         return NXT_ERROR;
534645Svbart@nginx.com     }
535645Svbart@nginx.com 
536249Svbart@nginx.com     rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_DATA_LAST, -1,
537249Svbart@nginx.com                                stream, controller_port->id, b);
538249Svbart@nginx.com 
539249Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
540249Svbart@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
541249Svbart@nginx.com         return NXT_ERROR;
542249Svbart@nginx.com     }
543249Svbart@nginx.com 
544249Svbart@nginx.com     return NXT_OK;
545249Svbart@nginx.com }
546249Svbart@nginx.com 
547249Svbart@nginx.com 
54820Sigor@sysoev.ru nxt_int_t
54920Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
55020Sigor@sysoev.ru {
55120Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
55220Sigor@sysoev.ru 
55365Sigor@sysoev.ru     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
55420Sigor@sysoev.ru     if (ls == NULL) {
55520Sigor@sysoev.ru         return NXT_ERROR;
55620Sigor@sysoev.ru     }
55720Sigor@sysoev.ru 
5581448Svbart@nginx.com     ls->sockaddr = rt->controller_listen;
55920Sigor@sysoev.ru 
560359Sigor@sysoev.ru     nxt_listen_socket_remote_size(ls);
56120Sigor@sysoev.ru 
56220Sigor@sysoev.ru     ls->socket = -1;
56320Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
56420Sigor@sysoev.ru     ls->read_after_accept = 1;
56520Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
56620Sigor@sysoev.ru 
56720Sigor@sysoev.ru #if 0
56820Sigor@sysoev.ru     /* STUB */
56965Sigor@sysoev.ru     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
57020Sigor@sysoev.ru     if (wq == NULL) {
57120Sigor@sysoev.ru         return NXT_ERROR;
57220Sigor@sysoev.ru     }
57320Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
57420Sigor@sysoev.ru     /**/
57520Sigor@sysoev.ru 
57620Sigor@sysoev.ru     ls->work_queue = wq;
57720Sigor@sysoev.ru #endif
57820Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
57920Sigor@sysoev.ru 
5801451Svbart@nginx.com     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
58120Sigor@sysoev.ru         return NXT_ERROR;
58220Sigor@sysoev.ru     }
58320Sigor@sysoev.ru 
58420Sigor@sysoev.ru     rt->controller_socket = ls;
58520Sigor@sysoev.ru 
58620Sigor@sysoev.ru     return NXT_OK;
58720Sigor@sysoev.ru }
58820Sigor@sysoev.ru 
58920Sigor@sysoev.ru 
59020Sigor@sysoev.ru static void
59120Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
59220Sigor@sysoev.ru {
59327Svbart@nginx.com     nxt_buf_t                 *b;
59462Sigor@sysoev.ru     nxt_conn_t                *c;
59527Svbart@nginx.com     nxt_event_engine_t        *engine;
59627Svbart@nginx.com     nxt_controller_request_t  *r;
59720Sigor@sysoev.ru 
59820Sigor@sysoev.ru     c = obj;
59920Sigor@sysoev.ru 
60020Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
60120Sigor@sysoev.ru 
60265Sigor@sysoev.ru     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
60327Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
60427Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
60527Svbart@nginx.com         return;
60627Svbart@nginx.com     }
60727Svbart@nginx.com 
608140Svbart@nginx.com     r->conn = c;
609140Svbart@nginx.com 
61060Svbart@nginx.com     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
61160Svbart@nginx.com                       != NXT_OK))
61260Svbart@nginx.com     {
61360Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
61460Svbart@nginx.com         return;
61560Svbart@nginx.com     }
61627Svbart@nginx.com 
6171167Svbart@nginx.com     r->parser.encoded_slashes = 1;
6181167Svbart@nginx.com 
61920Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
62020Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
62120Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
62220Sigor@sysoev.ru         return;
62320Sigor@sysoev.ru     }
62420Sigor@sysoev.ru 
62520Sigor@sysoev.ru     c->read = b;
62627Svbart@nginx.com     c->socket.data = r;
62720Sigor@sysoev.ru     c->socket.read_ready = 1;
62820Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
62920Sigor@sysoev.ru 
63020Sigor@sysoev.ru     engine = task->thread->engine;
63120Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
63227Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
63320Sigor@sysoev.ru 
63462Sigor@sysoev.ru     nxt_conn_read(engine, c);
63520Sigor@sysoev.ru }
63620Sigor@sysoev.ru 
63720Sigor@sysoev.ru 
63820Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
63920Sigor@sysoev.ru     nxt_aligned(64) =
64020Sigor@sysoev.ru {
64156Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_read,
64256Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
64356Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
64420Sigor@sysoev.ru 
64556Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
64656Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
64756Sigor@sysoev.ru     .timer_data = 60 * 1000,
64820Sigor@sysoev.ru };
64920Sigor@sysoev.ru 
65020Sigor@sysoev.ru 
65120Sigor@sysoev.ru static void
65220Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
65320Sigor@sysoev.ru {
65427Svbart@nginx.com     size_t                    preread;
65527Svbart@nginx.com     nxt_buf_t                 *b;
65627Svbart@nginx.com     nxt_int_t                 rc;
65762Sigor@sysoev.ru     nxt_conn_t                *c;
65827Svbart@nginx.com     nxt_controller_request_t  *r;
65920Sigor@sysoev.ru 
66020Sigor@sysoev.ru     c = obj;
66127Svbart@nginx.com     r = data;
66220Sigor@sysoev.ru 
66320Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
66420Sigor@sysoev.ru 
66527Svbart@nginx.com     nxt_queue_remove(&c->link);
66627Svbart@nginx.com     nxt_queue_self(&c->link);
66727Svbart@nginx.com 
66827Svbart@nginx.com     b = c->read;
66927Svbart@nginx.com 
67027Svbart@nginx.com     rc = nxt_http_parse_request(&r->parser, &b->mem);
67127Svbart@nginx.com 
67227Svbart@nginx.com     if (nxt_slow_path(rc != NXT_DONE)) {
67327Svbart@nginx.com 
67427Svbart@nginx.com         if (rc == NXT_AGAIN) {
67527Svbart@nginx.com             if (nxt_buf_mem_free_size(&b->mem) == 0) {
67627Svbart@nginx.com                 nxt_log(task, NXT_LOG_ERR, "too long request headers");
67727Svbart@nginx.com                 nxt_controller_conn_close(task, c, r);
67827Svbart@nginx.com                 return;
67927Svbart@nginx.com             }
68027Svbart@nginx.com 
68162Sigor@sysoev.ru             nxt_conn_read(task->thread->engine, c);
68227Svbart@nginx.com             return;
68327Svbart@nginx.com         }
68427Svbart@nginx.com 
68527Svbart@nginx.com         /* rc == NXT_ERROR */
68627Svbart@nginx.com 
68727Svbart@nginx.com         nxt_log(task, NXT_LOG_ERR, "parsing error");
68827Svbart@nginx.com 
68927Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
69027Svbart@nginx.com         return;
69127Svbart@nginx.com     }
69227Svbart@nginx.com 
693417Svbart@nginx.com     rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash,
694417Svbart@nginx.com                                  r);
69560Svbart@nginx.com 
69660Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
69760Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
69860Svbart@nginx.com         return;
69960Svbart@nginx.com     }
70060Svbart@nginx.com 
70127Svbart@nginx.com     preread = nxt_buf_mem_used_size(&b->mem);
70227Svbart@nginx.com 
70327Svbart@nginx.com     nxt_debug(task, "controller request header parsing complete, "
704107Svbart@nginx.com                     "body length: %uz, preread: %uz",
70527Svbart@nginx.com                     r->length, preread);
70627Svbart@nginx.com 
70727Svbart@nginx.com     if (preread >= r->length) {
708140Svbart@nginx.com         nxt_controller_process_request(task, r);
709