xref: /unit/src/nxt_controller.c (revision 1526)
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 
421488St.nateldemoura@f5.com static nxt_int_t nxt_controller_prefork(nxt_task_t *task,
431488St.nateldemoura@f5.com     nxt_process_t *process, nxt_mp_t *mp);
441488St.nateldemoura@f5.com static nxt_int_t nxt_controller_start(nxt_task_t *task,
451488St.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);
511488St.nateldemoura@f5.com static void nxt_controller_remove_pid_handler(nxt_task_t *task,
521488St.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);
57*1526Smax.romanov@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp,
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);
921488St.nateldemoura@f5.com static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
931488St.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 
1251488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
1261488St.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,
1321488St.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 
1381488St.nateldemoura@f5.com const nxt_process_init_t  nxt_controller_process = {
1391488St.nateldemoura@f5.com     .name           = "controller",
1401488St.nateldemoura@f5.com     .type           = NXT_PROCESS_CONTROLLER,
1411488St.nateldemoura@f5.com     .prefork        = nxt_controller_prefork,
1421488St.nateldemoura@f5.com     .restart        = 1,
1431488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
1441488St.nateldemoura@f5.com     .start          = nxt_controller_start,
1451488St.nateldemoura@f5.com     .port_handlers  = &nxt_controller_process_port_handlers,
1461488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1471488St.nateldemoura@f5.com };
1481488St.nateldemoura@f5.com 
1491488St.nateldemoura@f5.com 
1501488St.nateldemoura@f5.com static nxt_int_t
1511488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
1521488St.nateldemoura@f5.com {
1531488St.nateldemoura@f5.com     ssize_t                n;
1541488St.nateldemoura@f5.com     nxt_int_t              ret;
1551488St.nateldemoura@f5.com     nxt_str_t              *conf;
1561488St.nateldemoura@f5.com     nxt_file_t             file;
1571488St.nateldemoura@f5.com     nxt_runtime_t          *rt;
1581488St.nateldemoura@f5.com     nxt_file_info_t        fi;
1591488St.nateldemoura@f5.com     nxt_controller_init_t  ctrl_init;
1601488St.nateldemoura@f5.com 
1611488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "controller started");
1621488St.nateldemoura@f5.com 
1631488St.nateldemoura@f5.com     rt = task->thread->runtime;
1641488St.nateldemoura@f5.com 
1651488St.nateldemoura@f5.com     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
1661488St.nateldemoura@f5.com 
1671488St.nateldemoura@f5.com     conf = &ctrl_init.conf;
1681488St.nateldemoura@f5.com 
1691488St.nateldemoura@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
1701488St.nateldemoura@f5.com 
1711488St.nateldemoura@f5.com     file.name = (nxt_file_name_t *) rt->conf;
1721488St.nateldemoura@f5.com 
1731488St.nateldemoura@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
1741488St.nateldemoura@f5.com 
1751488St.nateldemoura@f5.com     if (ret == NXT_OK) {
1761488St.nateldemoura@f5.com         ret = nxt_file_info(&file, &fi);
1771488St.nateldemoura@f5.com 
1781488St.nateldemoura@f5.com         if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
1791488St.nateldemoura@f5.com             conf->length = nxt_file_size(&fi);
1801488St.nateldemoura@f5.com             conf->start = nxt_mp_alloc(mp, conf->length);
1811488St.nateldemoura@f5.com             if (nxt_slow_path(conf->start == NULL)) {
1821488St.nateldemoura@f5.com                 nxt_file_close(task, &file);
1831488St.nateldemoura@f5.com                 return NXT_ERROR;
1841488St.nateldemoura@f5.com             }
1851488St.nateldemoura@f5.com 
1861488St.nateldemoura@f5.com             n = nxt_file_read(&file, conf->start, conf->length, 0);
1871488St.nateldemoura@f5.com 
1881488St.nateldemoura@f5.com             if (nxt_slow_path(n != (ssize_t) conf->length)) {
1891488St.nateldemoura@f5.com                 conf->start = NULL;
1901488St.nateldemoura@f5.com                 conf->length = 0;
1911488St.nateldemoura@f5.com 
1921488St.nateldemoura@f5.com                 nxt_alert(task, "failed to restore previous configuration: "
1931488St.nateldemoura@f5.com                           "cannot read the file");
1941488St.nateldemoura@f5.com             }
1951488St.nateldemoura@f5.com         }
1961488St.nateldemoura@f5.com 
1971488St.nateldemoura@f5.com         nxt_file_close(task, &file);
1981488St.nateldemoura@f5.com     }
1991488St.nateldemoura@f5.com 
2001488St.nateldemoura@f5.com #if (NXT_TLS)
2011488St.nateldemoura@f5.com     ctrl_init.certs = nxt_cert_store_load(task, mp);
2021488St.nateldemoura@f5.com 
2031488St.nateldemoura@f5.com     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
2041488St.nateldemoura@f5.com #endif
2051488St.nateldemoura@f5.com 
2061488St.nateldemoura@f5.com     process->data.controller = ctrl_init;
2071488St.nateldemoura@f5.com 
2081488St.nateldemoura@f5.com     return NXT_OK;
2091488St.nateldemoura@f5.com }
2101488St.nateldemoura@f5.com 
2111488St.nateldemoura@f5.com 
2121488St.nateldemoura@f5.com #if (NXT_TLS)
2131488St.nateldemoura@f5.com 
2141488St.nateldemoura@f5.com static void
2151488St.nateldemoura@f5.com nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
2161488St.nateldemoura@f5.com {
2171488St.nateldemoura@f5.com     pid_t          main_pid;
2181488St.nateldemoura@f5.com     nxt_array_t    *certs;
2191488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
2201488St.nateldemoura@f5.com 
2211488St.nateldemoura@f5.com     certs = obj;
2221488St.nateldemoura@f5.com     rt = data;
2231488St.nateldemoura@f5.com 
2241488St.nateldemoura@f5.com     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2251488St.nateldemoura@f5.com 
2261488St.nateldemoura@f5.com     if (nxt_pid == main_pid && certs != NULL) {
2271488St.nateldemoura@f5.com         nxt_cert_store_release(certs);
2281488St.nateldemoura@f5.com     }
2291488St.nateldemoura@f5.com }
2301488St.nateldemoura@f5.com 
2311488St.nateldemoura@f5.com #endif
2321488St.nateldemoura@f5.com 
2331488St.nateldemoura@f5.com 
2341488St.nateldemoura@f5.com static nxt_int_t
2351488St.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 
2541488St.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) {
347*1526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, 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 
3981488St.nateldemoura@f5.com static void
3991488St.nateldemoura@f5.com nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
4001488St.nateldemoura@f5.com {
4011488St.nateldemoura@f5.com     nxt_pid_t      pid;
4021488St.nateldemoura@f5.com     nxt_process_t  *process;
4031488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
4041488St.nateldemoura@f5.com 
4051488St.nateldemoura@f5.com     rt = task->thread->runtime;
4061488St.nateldemoura@f5.com 
4071488St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
4081488St.nateldemoura@f5.com 
4091488St.nateldemoura@f5.com     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
4101488St.nateldemoura@f5.com 
4111488St.nateldemoura@f5.com     process = nxt_runtime_process_find(rt, pid);
4121488St.nateldemoura@f5.com     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
4131488St.nateldemoura@f5.com         nxt_controller_router_ready = 0;
4141488St.nateldemoura@f5.com     }
4151488St.nateldemoura@f5.com 
4161488St.nateldemoura@f5.com     nxt_port_remove_pid_handler(task, msg);
4171488St.nateldemoura@f5.com }
4181488St.nateldemoura@f5.com 
4191488St.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
500*1526Smax.romanov@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
501249Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *data)
502249Svbart@nginx.com {
503*1526Smax.romanov@nginx.com     void           *mem;
504*1526Smax.romanov@nginx.com     u_char         *end;
505249Svbart@nginx.com     size_t         size;
506249Svbart@nginx.com     uint32_t       stream;
507*1526Smax.romanov@nginx.com     nxt_fd_t       fd;
508249Svbart@nginx.com     nxt_int_t      rc;
509249Svbart@nginx.com     nxt_buf_t      *b;
510249Svbart@nginx.com     nxt_port_t     *router_port, *controller_port;
511249Svbart@nginx.com     nxt_runtime_t  *rt;
512249Svbart@nginx.com 
513249Svbart@nginx.com     rt = task->thread->runtime;
514249Svbart@nginx.com 
515249Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
516249Svbart@nginx.com 
5171470Smax.romanov@nginx.com     nxt_assert(router_port != NULL);
5181470Smax.romanov@nginx.com     nxt_assert(nxt_controller_router_ready);
519249Svbart@nginx.com 
520249Svbart@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
521249Svbart@nginx.com 
522249Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
523249Svbart@nginx.com 
524*1526Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
525379Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
526379Smax.romanov@nginx.com         return NXT_ERROR;
527379Smax.romanov@nginx.com     }
528249Svbart@nginx.com 
529*1526Smax.romanov@nginx.com     fd = nxt_shm_open(task, size);
530*1526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
531*1526Smax.romanov@nginx.com         return NXT_ERROR;
532*1526Smax.romanov@nginx.com     }
533*1526Smax.romanov@nginx.com 
534*1526Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
535*1526Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
536*1526Smax.romanov@nginx.com         goto fail;
537*1526Smax.romanov@nginx.com     }
538*1526Smax.romanov@nginx.com 
539*1526Smax.romanov@nginx.com     end = nxt_conf_json_print(mem, conf, NULL);
540*1526Smax.romanov@nginx.com 
541*1526Smax.romanov@nginx.com     nxt_mem_munmap(mem, size);
542*1526Smax.romanov@nginx.com 
543*1526Smax.romanov@nginx.com     size = end - (u_char *) mem;
544*1526Smax.romanov@nginx.com 
545*1526Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
546249Svbart@nginx.com 
547249Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
548249Svbart@nginx.com                                            handler, handler,
549249Svbart@nginx.com                                            router_port->pid, data);
550645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
551*1526Smax.romanov@nginx.com         goto fail;
552645Svbart@nginx.com     }
553645Svbart@nginx.com 
554*1526Smax.romanov@nginx.com     rc = nxt_port_socket_write(task, router_port,
555*1526Smax.romanov@nginx.com                                NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
556*1526Smax.romanov@nginx.com                                fd, stream, controller_port->id, b);
557249Svbart@nginx.com 
558249Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
559249Svbart@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
560*1526Smax.romanov@nginx.com 
561*1526Smax.romanov@nginx.com         goto fail;
562249Svbart@nginx.com     }
563249Svbart@nginx.com 
564249Svbart@nginx.com     return NXT_OK;
565*1526Smax.romanov@nginx.com 
566*1526Smax.romanov@nginx.com fail:
567*1526Smax.romanov@nginx.com 
568*1526Smax.romanov@nginx.com     nxt_fd_close(fd);
569*1526Smax.romanov@nginx.com 
570*1526Smax.romanov@nginx.com     return NXT_ERROR;
571249Svbart@nginx.com }
572249Svbart@nginx.com 
573249Svbart@nginx.com 
57420Sigor@sysoev.ru nxt_int_t
57520Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
57620Sigor@sysoev.ru {
57720Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
57820Sigor@sysoev.ru 
57965Sigor@sysoev.ru     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
58020Sigor@sysoev.ru     if (ls == NULL) {
58120Sigor@sysoev.ru         return NXT_ERROR;
58220Sigor@sysoev.ru     }
58320Sigor@sysoev.ru 
5841448Svbart@nginx.com     ls->sockaddr = rt->controller_listen;
58520Sigor@sysoev.ru 
586359Sigor@sysoev.ru     nxt_listen_socket_remote_size(ls);
58720Sigor@sysoev.ru 
58820Sigor@sysoev.ru     ls->socket = -1;
58920Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
59020Sigor@sysoev.ru     ls->read_after_accept = 1;
59120Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
59220Sigor@sysoev.ru 
59320Sigor@sysoev.ru #if 0
59420Sigor@sysoev.ru     /* STUB */
59565Sigor@sysoev.ru     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
59620Sigor@sysoev.ru     if (wq == NULL) {
59720Sigor@sysoev.ru         return NXT_ERROR;
59820Sigor@sysoev.ru     }
59920Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
60020Sigor@sysoev.ru     /**/
60120Sigor@sysoev.ru 
60220Sigor@sysoev.ru     ls->work_queue = wq;
60320Sigor@sysoev.ru #endif
60420Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
60520Sigor@sysoev.ru 
6061451Svbart@nginx.com     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
60720Sigor@sysoev.ru         return NXT_ERROR;
60820Sigor@sysoev.ru     }
60920Sigor@sysoev.ru 
61020Sigor@sysoev.ru     rt->controller_socket = ls;
61120Sigor@sysoev.ru 
61220Sigor@sysoev.ru     return NXT_OK;
61320Sigor@sysoev.ru }
61420Sigor@sysoev.ru 
61520Sigor@sysoev.ru 
61620Sigor@sysoev.ru static void
61720Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
61820Sigor@sysoev.ru {
61927Svbart@nginx.com     nxt_buf_t                 *b;
62062Sigor@sysoev.ru     nxt_conn_t                *c;
62127Svbart@nginx.com     nxt_event_engine_t        *engine;
62227Svbart@nginx.com     nxt_controller_request_t  *r;
62320Sigor@sysoev.ru 
62420Sigor@sysoev.ru     c = obj;
62520Sigor@sysoev.ru 
62620Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
62720Sigor@sysoev.ru 
62865Sigor@sysoev.ru     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
62927Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
63027Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
63127Svbart@nginx.com         return;
63227Svbart@nginx.com     }
63327Svbart@nginx.com 
634140Svbart@nginx.com     r->conn = c;
635140Svbart@nginx.com 
63660Svbart@nginx.com     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
63760Svbart@nginx.com                       != NXT_OK))
63860Svbart@nginx.com     {
63960Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
64060Svbart@nginx.com         return;
64160Svbart@nginx.com     }
64227Svbart@nginx.com 
6431167Svbart@nginx.com     r->parser.encoded_slashes = 1;
6441167Svbart@nginx.com 
64520Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
64620Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
64720Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
64820Sigor@sysoev.ru         return;
64920Sigor@sysoev.ru     }
65020Sigor@sysoev.ru 
65120Sigor@sysoev.ru     c->read = b;
65227Svbart@nginx.com     c->socket.data = r;
65320Sigor@sysoev.ru     c->socket.read_ready = 1;
65420Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
65520Sigor@sysoev.ru 
65620Sigor@sysoev.ru     engine = task->thread->engine;
65720Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
65827Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
65920Sigor@sysoev.ru 
66062Sigor@sysoev.ru     nxt_conn_read(engine, c);
66120Sigor@sysoev.ru }
66220Sigor@sysoev.ru 
66320Sigor@sysoev.ru 
66420Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
66520Sigor@sysoev.ru     nxt_aligned(64) =
66620Sigor@sysoev.ru {
66756Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_read,
66856Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
66956Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
67020Sigor@sysoev.ru 
67156Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
67256Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
67356Sigor@sysoev.ru     .timer_data = 60 * 1000,
67420Sigor@sysoev.ru };
67520Sigor@sysoev.ru 
67620Sigor@sysoev.ru 
67720Sigor@sysoev.ru static void
67820Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
67920Sigor@sysoev.ru {
68027Svbart@nginx.com     size_t                    preread;
68127Svbart@nginx.com     nxt_buf_t                 *b;
68227Svbart@nginx.com     nxt_int_t                 rc;
68362Sigor@sysoev.ru     nxt_conn_t                *c;
68427Svbart@nginx.com     nxt_controller_request_t  *r;
68520Sigor@sysoev.ru 
68620Sigor@sysoev.ru     c = obj;
68727Svbart@nginx.com     r = data;
68820Sigor@sysoev.ru 
68920Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
69020Sigor@sysoev.ru 
69127Svbart@nginx.com     nxt_queue_remove(&c->link);
69227Svbart@nginx.com     nxt_queue_self(&c->link);
69327Svbart@nginx.com 
69427Svbart@nginx.com     b = c->read;
69527Svbart@nginx.com 
69627Svbart@nginx.com     rc = nxt_http_parse_request(&r->parser, &b->mem);
697