xref: /unit/src/nxt_controller.c (revision 1926)
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);
571526Smax.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
95*1926Smax.romanov@nginx.com static void nxt_controller_process_control(nxt_task_t *task,
96*1926Smax.romanov@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
97*1926Smax.romanov@nginx.com static void nxt_controller_app_restart_handler(nxt_task_t *task,
98*1926Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
99238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task,
100238Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
101314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task,
102314Svbart@nginx.com     nxt_conf_value_t *conf);
103140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task,
104140Svbart@nginx.com     nxt_controller_request_t *req, nxt_controller_response_t *resp);
105208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
106208Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
10727Svbart@nginx.com 
10827Svbart@nginx.com 
109417Svbart@nginx.com static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
11027Svbart@nginx.com     { nxt_string("Content-Length"),
11127Svbart@nginx.com       &nxt_controller_request_content_length, 0 },
11227Svbart@nginx.com };
11327Svbart@nginx.com 
114417Svbart@nginx.com static nxt_lvlhsh_t            nxt_controller_fields_hash;
11527Svbart@nginx.com 
116314Svbart@nginx.com static nxt_uint_t              nxt_controller_listening;
117662Smax.romanov@nginx.com static nxt_uint_t              nxt_controller_router_ready;
118238Svbart@nginx.com static nxt_controller_conf_t   nxt_controller_conf;
119238Svbart@nginx.com static nxt_queue_t             nxt_controller_waiting_requests;
1201469Smax.romanov@nginx.com static nxt_bool_t              nxt_controller_waiting_init_conf;
12127Svbart@nginx.com 
12220Sigor@sysoev.ru 
12320Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
12427Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
12527Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
12620Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
12720Sigor@sysoev.ru 
12820Sigor@sysoev.ru 
1291488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
1301488St.nateldemoura@f5.com     .quit           = nxt_signal_quit_handler,
131662Smax.romanov@nginx.com     .new_port       = nxt_controller_process_new_port_handler,
132662Smax.romanov@nginx.com     .change_file    = nxt_port_change_log_file_handler,
133662Smax.romanov@nginx.com     .mmap           = nxt_port_mmap_handler,
134662Smax.romanov@nginx.com     .process_ready  = nxt_controller_router_ready_handler,
135662Smax.romanov@nginx.com     .data           = nxt_port_data_handler,
1361488St.nateldemoura@f5.com     .remove_pid     = nxt_controller_remove_pid_handler,
137662Smax.romanov@nginx.com     .rpc_ready      = nxt_port_rpc_handler,
138662Smax.romanov@nginx.com     .rpc_error      = nxt_port_rpc_handler,
139248Svbart@nginx.com };
140248Svbart@nginx.com 
141248Svbart@nginx.com 
1421488St.nateldemoura@f5.com const nxt_process_init_t  nxt_controller_process = {
1431488St.nateldemoura@f5.com     .name           = "controller",
1441488St.nateldemoura@f5.com     .type           = NXT_PROCESS_CONTROLLER,
1451488St.nateldemoura@f5.com     .prefork        = nxt_controller_prefork,
1461488St.nateldemoura@f5.com     .restart        = 1,
1471488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
1481488St.nateldemoura@f5.com     .start          = nxt_controller_start,
1491488St.nateldemoura@f5.com     .port_handlers  = &nxt_controller_process_port_handlers,
1501488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1511488St.nateldemoura@f5.com };
1521488St.nateldemoura@f5.com 
1531488St.nateldemoura@f5.com 
1541488St.nateldemoura@f5.com static nxt_int_t
1551488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
1561488St.nateldemoura@f5.com {
1571488St.nateldemoura@f5.com     ssize_t                n;
1581488St.nateldemoura@f5.com     nxt_int_t              ret;
1591488St.nateldemoura@f5.com     nxt_str_t              *conf;
1601488St.nateldemoura@f5.com     nxt_file_t             file;
1611488St.nateldemoura@f5.com     nxt_runtime_t          *rt;
1621488St.nateldemoura@f5.com     nxt_file_info_t        fi;
1631488St.nateldemoura@f5.com     nxt_controller_init_t  ctrl_init;
1641488St.nateldemoura@f5.com 
1651488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "controller started");
1661488St.nateldemoura@f5.com 
1671488St.nateldemoura@f5.com     rt = task->thread->runtime;
1681488St.nateldemoura@f5.com 
1691488St.nateldemoura@f5.com     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
1701488St.nateldemoura@f5.com 
1711488St.nateldemoura@f5.com     conf = &ctrl_init.conf;
1721488St.nateldemoura@f5.com 
1731488St.nateldemoura@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
1741488St.nateldemoura@f5.com 
1751488St.nateldemoura@f5.com     file.name = (nxt_file_name_t *) rt->conf;
1761488St.nateldemoura@f5.com 
1771488St.nateldemoura@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
1781488St.nateldemoura@f5.com 
1791488St.nateldemoura@f5.com     if (ret == NXT_OK) {
1801488St.nateldemoura@f5.com         ret = nxt_file_info(&file, &fi);
1811488St.nateldemoura@f5.com 
1821488St.nateldemoura@f5.com         if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
1831488St.nateldemoura@f5.com             conf->length = nxt_file_size(&fi);
1841488St.nateldemoura@f5.com             conf->start = nxt_mp_alloc(mp, conf->length);
1851488St.nateldemoura@f5.com             if (nxt_slow_path(conf->start == NULL)) {
1861488St.nateldemoura@f5.com                 nxt_file_close(task, &file);
1871488St.nateldemoura@f5.com                 return NXT_ERROR;
1881488St.nateldemoura@f5.com             }
1891488St.nateldemoura@f5.com 
1901488St.nateldemoura@f5.com             n = nxt_file_read(&file, conf->start, conf->length, 0);
1911488St.nateldemoura@f5.com 
1921488St.nateldemoura@f5.com             if (nxt_slow_path(n != (ssize_t) conf->length)) {
1931488St.nateldemoura@f5.com                 conf->start = NULL;
1941488St.nateldemoura@f5.com                 conf->length = 0;
1951488St.nateldemoura@f5.com 
1961488St.nateldemoura@f5.com                 nxt_alert(task, "failed to restore previous configuration: "
1971488St.nateldemoura@f5.com                           "cannot read the file");
1981488St.nateldemoura@f5.com             }
1991488St.nateldemoura@f5.com         }
2001488St.nateldemoura@f5.com 
2011488St.nateldemoura@f5.com         nxt_file_close(task, &file);
2021488St.nateldemoura@f5.com     }
2031488St.nateldemoura@f5.com 
2041488St.nateldemoura@f5.com #if (NXT_TLS)
2051488St.nateldemoura@f5.com     ctrl_init.certs = nxt_cert_store_load(task, mp);
2061488St.nateldemoura@f5.com 
2071488St.nateldemoura@f5.com     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
2081488St.nateldemoura@f5.com #endif
2091488St.nateldemoura@f5.com 
2101488St.nateldemoura@f5.com     process->data.controller = ctrl_init;
2111488St.nateldemoura@f5.com 
2121488St.nateldemoura@f5.com     return NXT_OK;
2131488St.nateldemoura@f5.com }
2141488St.nateldemoura@f5.com 
2151488St.nateldemoura@f5.com 
2161488St.nateldemoura@f5.com #if (NXT_TLS)
2171488St.nateldemoura@f5.com 
2181488St.nateldemoura@f5.com static void
2191488St.nateldemoura@f5.com nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
2201488St.nateldemoura@f5.com {
2211488St.nateldemoura@f5.com     pid_t          main_pid;
2221488St.nateldemoura@f5.com     nxt_array_t    *certs;
2231488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
2241488St.nateldemoura@f5.com 
2251488St.nateldemoura@f5.com     certs = obj;
2261488St.nateldemoura@f5.com     rt = data;
2271488St.nateldemoura@f5.com 
2281488St.nateldemoura@f5.com     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2291488St.nateldemoura@f5.com 
2301488St.nateldemoura@f5.com     if (nxt_pid == main_pid && certs != NULL) {
2311488St.nateldemoura@f5.com         nxt_cert_store_release(certs);
2321488St.nateldemoura@f5.com     }
2331488St.nateldemoura@f5.com }
2341488St.nateldemoura@f5.com 
2351488St.nateldemoura@f5.com #endif
2361488St.nateldemoura@f5.com 
2371488St.nateldemoura@f5.com 
2381488St.nateldemoura@f5.com static nxt_int_t
2391488St.nateldemoura@f5.com nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
24020Sigor@sysoev.ru {
241417Svbart@nginx.com     nxt_mp_t               *mp;
242417Svbart@nginx.com     nxt_int_t              ret;
243417Svbart@nginx.com     nxt_str_t              *json;
244417Svbart@nginx.com     nxt_conf_value_t       *conf;
245417Svbart@nginx.com     nxt_conf_validation_t  vldt;
246774Svbart@nginx.com     nxt_controller_init_t  *init;
24727Svbart@nginx.com 
2481459Smax.romanov@nginx.com     ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
249417Svbart@nginx.com                                nxt_controller_request_fields,
250417Svbart@nginx.com                                nxt_nitems(nxt_controller_request_fields));
251417Svbart@nginx.com 
252417Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
25327Svbart@nginx.com         return NXT_ERROR;
25427Svbart@nginx.com     }
25527Svbart@nginx.com 
256248Svbart@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
25727Svbart@nginx.com 
2581488St.nateldemoura@f5.com     init = &data->controller;
259774Svbart@nginx.com 
260774Svbart@nginx.com #if (NXT_TLS)
261774Svbart@nginx.com     if (init->certs != NULL) {
262774Svbart@nginx.com         nxt_cert_info_init(task, init->certs);
263774Svbart@nginx.com         nxt_cert_store_release(init->certs);
264774Svbart@nginx.com     }
265774Svbart@nginx.com #endif
266774Svbart@nginx.com 
267774Svbart@nginx.com     json = &init->conf;
268774Svbart@nginx.com 
269774Svbart@nginx.com     if (json->start == NULL) {
270314Svbart@nginx.com         return NXT_OK;
271314Svbart@nginx.com     }
272314Svbart@nginx.com 
273314Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
274314Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
275314Svbart@nginx.com         return NXT_ERROR;
276314Svbart@nginx.com     }
277314Svbart@nginx.com 
278314Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, json);
279314Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
280564Svbart@nginx.com         nxt_alert(task, "failed to restore previous configuration: "
281564Svbart@nginx.com                   "file is corrupted or not enough memory");
282314Svbart@nginx.com 
283314Svbart@nginx.com         nxt_mp_destroy(mp);
284314Svbart@nginx.com         return NXT_OK;
285314Svbart@nginx.com     }
286314Svbart@nginx.com 
287357Svbart@nginx.com     nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
288314Svbart@nginx.com 
289357Svbart@nginx.com     vldt.pool = nxt_mp_create(1024, 128, 256, 32);
290357Svbart@nginx.com     if (nxt_slow_path(vldt.pool == NULL)) {
2911013Smax.romanov@nginx.com         nxt_mp_destroy(mp);
292357Svbart@nginx.com         return NXT_ERROR;
293314Svbart@nginx.com     }
294314Svbart@nginx.com 
295357Svbart@nginx.com     vldt.conf = conf;
296357Svbart@nginx.com 
297357Svbart@nginx.com     ret = nxt_conf_validate(&vldt);
298357Svbart@nginx.com 
299357Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
300357Svbart@nginx.com 
301357Svbart@nginx.com         if (ret == NXT_DECLINED) {
302564Svbart@nginx.com             nxt_alert(task, "the previous configuration is invalid: %V",
303564Svbart@nginx.com                       &vldt.error);
304357Svbart@nginx.com 
305357Svbart@nginx.com             nxt_mp_destroy(vldt.pool);
306357Svbart@nginx.com             nxt_mp_destroy(mp);
307357Svbart@nginx.com 
308357Svbart@nginx.com             return NXT_OK;
309357Svbart@nginx.com         }
310357Svbart@nginx.com 
311357Svbart@nginx.com         /* ret == NXT_ERROR */
312357Svbart@nginx.com 
313357Svbart@nginx.com         return NXT_ERROR;
314357Svbart@nginx.com     }
315357Svbart@nginx.com 
316357Svbart@nginx.com     nxt_mp_destroy(vldt.pool);
317314Svbart@nginx.com 
318314Svbart@nginx.com     nxt_controller_conf.root = conf;
319314Svbart@nginx.com     nxt_controller_conf.pool = mp;
320314Svbart@nginx.com 
321248Svbart@nginx.com     return NXT_OK;
322248Svbart@nginx.com }
323248Svbart@nginx.com 
324248Svbart@nginx.com 
325248Svbart@nginx.com static void
326248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task,
327248Svbart@nginx.com     nxt_port_recv_msg_t *msg)
328248Svbart@nginx.com {
329662Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
330662Smax.romanov@nginx.com 
331662Smax.romanov@nginx.com     if (msg->u.new_port->type != NXT_PROCESS_ROUTER
332662Smax.romanov@nginx.com         || !nxt_controller_router_ready)
333662Smax.romanov@nginx.com     {
334662Smax.romanov@nginx.com         return;
335662Smax.romanov@nginx.com     }
336662Smax.romanov@nginx.com 
337662Smax.romanov@nginx.com     nxt_controller_send_current_conf(task);
338662Smax.romanov@nginx.com }
339662Smax.romanov@nginx.com 
340662Smax.romanov@nginx.com 
341662Smax.romanov@nginx.com static void
342662Smax.romanov@nginx.com nxt_controller_send_current_conf(nxt_task_t *task)
343662Smax.romanov@nginx.com {
344249Svbart@nginx.com     nxt_int_t         rc;
345248Svbart@nginx.com     nxt_runtime_t     *rt;
346248Svbart@nginx.com     nxt_conf_value_t  *conf;
347248Svbart@nginx.com 
348249Svbart@nginx.com     conf = nxt_controller_conf.root;
349249Svbart@nginx.com 
350249Svbart@nginx.com     if (conf != NULL) {
3511526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf,
352249Svbart@nginx.com                                       nxt_controller_conf_init_handler, NULL);
35344Svbart@nginx.com 
354249Svbart@nginx.com         if (nxt_fast_path(rc == NXT_OK)) {
3551469Smax.romanov@nginx.com             nxt_controller_waiting_init_conf = 1;
3561469Smax.romanov@nginx.com 
357249Svbart@nginx.com             return;
358249Svbart@nginx.com         }
359249Svbart@nginx.com 
360249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
361249Svbart@nginx.com 
362249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
363249Svbart@nginx.com             nxt_abort();
364249Svbart@nginx.com         }
36544Svbart@nginx.com     }
36644Svbart@nginx.com 
367249Svbart@nginx.com     if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
368248Svbart@nginx.com         nxt_abort();
36944Svbart@nginx.com     }
37044Svbart@nginx.com 
371248Svbart@nginx.com     rt = task->thread->runtime;
372140Svbart@nginx.com 
373248Svbart@nginx.com     if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
374248Svbart@nginx.com         nxt_abort();
375248Svbart@nginx.com     }
376314Svbart@nginx.com 
377314Svbart@nginx.com     nxt_controller_listening = 1;
3781470Smax.romanov@nginx.com 
3791470Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
38020Sigor@sysoev.ru }
38120Sigor@sysoev.ru 
38220Sigor@sysoev.ru 
383662Smax.romanov@nginx.com static void
384662Smax.romanov@nginx.com nxt_controller_router_ready_handler(nxt_task_t *task,
385662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg)
386662Smax.romanov@nginx.com {
387662Smax.romanov@nginx.com     nxt_port_t     *router_port;
388662Smax.romanov@nginx.com     nxt_runtime_t  *rt;
389662Smax.romanov@nginx.com 
390662Smax.romanov@nginx.com     rt = task->thread->runtime;
391662Smax.romanov@nginx.com 
392662Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
393662Smax.romanov@nginx.com 
394662Smax.romanov@nginx.com     nxt_controller_router_ready = 1;
395662Smax.romanov@nginx.com 
396662Smax.romanov@nginx.com     if (router_port != NULL) {
397662Smax.romanov@nginx.com         nxt_controller_send_current_conf(task);
398662Smax.romanov@nginx.com     }
399662Smax.romanov@nginx.com }
400662Smax.romanov@nginx.com 
401662Smax.romanov@nginx.com 
4021488St.nateldemoura@f5.com static void
4031488St.nateldemoura@f5.com nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
4041488St.nateldemoura@f5.com {
4051488St.nateldemoura@f5.com     nxt_pid_t      pid;
4061488St.nateldemoura@f5.com     nxt_process_t  *process;
4071488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
4081488St.nateldemoura@f5.com 
4091488St.nateldemoura@f5.com     rt = task->thread->runtime;
4101488St.nateldemoura@f5.com 
4111488St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
4121488St.nateldemoura@f5.com 
4131488St.nateldemoura@f5.com     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
4141488St.nateldemoura@f5.com 
4151488St.nateldemoura@f5.com     process = nxt_runtime_process_find(rt, pid);
4161488St.nateldemoura@f5.com     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
4171488St.nateldemoura@f5.com         nxt_controller_router_ready = 0;
4181488St.nateldemoura@f5.com     }
4191488St.nateldemoura@f5.com 
4201488St.nateldemoura@f5.com     nxt_port_remove_pid_handler(task, msg);
4211488St.nateldemoura@f5.com }
4221488St.nateldemoura@f5.com 
4231488St.nateldemoura@f5.com 
424249Svbart@nginx.com static nxt_int_t
425249Svbart@nginx.com nxt_controller_conf_default(void)
426249Svbart@nginx.com {
427249Svbart@nginx.com     nxt_mp_t          *mp;
428249Svbart@nginx.com     nxt_conf_value_t  *conf;
429249Svbart@nginx.com 
430249Svbart@nginx.com     static const nxt_str_t json
431249Svbart@nginx.com         = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
432249Svbart@nginx.com 
433249Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
434249Svbart@nginx.com 
435249Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
436249Svbart@nginx.com         return NXT_ERROR;
437249Svbart@nginx.com     }
438249Svbart@nginx.com 
439249Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, &json);
440249Svbart@nginx.com 
441249Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
442249Svbart@nginx.com         return NXT_ERROR;
443249Svbart@nginx.com     }
444249Svbart@nginx.com 
445249Svbart@nginx.com     nxt_controller_conf.root = conf;
446249Svbart@nginx.com     nxt_controller_conf.pool = mp;
447249Svbart@nginx.com 
448249Svbart@nginx.com     return NXT_OK;
449249Svbart@nginx.com }
450249Svbart@nginx.com 
451249Svbart@nginx.com 
452249Svbart@nginx.com static void
453249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
454249Svbart@nginx.com     void *data)
455249Svbart@nginx.com {
456314Svbart@nginx.com     nxt_runtime_t  *rt;
457314Svbart@nginx.com 
4581469Smax.romanov@nginx.com     nxt_controller_waiting_init_conf = 0;
4591469Smax.romanov@nginx.com 
460249Svbart@nginx.com     if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
461564Svbart@nginx.com         nxt_alert(task, "failed to apply previous configuration");
462314Svbart@nginx.com 
463249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
464249Svbart@nginx.com 
465249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
466249Svbart@nginx.com             nxt_abort();
467249Svbart@nginx.com         }
468249Svbart@nginx.com     }
469314Svbart@nginx.com 
470314Svbart@nginx.com     if (nxt_controller_listening == 0) {
471314Svbart@nginx.com         rt = task->thread->runtime;
472314Svbart@nginx.com 
473314Svbart@nginx.com         if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
474314Svbart@nginx.com                           == NULL))
475314Svbart@nginx.com         {
476314Svbart@nginx.com             nxt_abort();
477314Svbart@nginx.com         }
478314Svbart@nginx.com 
479314Svbart@nginx.com         nxt_controller_listening = 1;
480314Svbart@nginx.com     }
4811469Smax.romanov@nginx.com 
4821469Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
4831469Smax.romanov@nginx.com }
4841469Smax.romanov@nginx.com 
4851469Smax.romanov@nginx.com 
4861469Smax.romanov@nginx.com static void
4871469Smax.romanov@nginx.com nxt_controller_flush_requests(nxt_task_t *task)
4881469Smax.romanov@nginx.com {
4891469Smax.romanov@nginx.com     nxt_queue_t               queue;
4901469Smax.romanov@nginx.com     nxt_controller_request_t  *req;
4911469Smax.romanov@nginx.com 
4921469Smax.romanov@nginx.com     nxt_queue_init(&queue);
4931469Smax.romanov@nginx.com     nxt_queue_add(&queue, &nxt_controller_waiting_requests);
4941469Smax.romanov@nginx.com 
4951469Smax.romanov@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
4961469Smax.romanov@nginx.com 
4971469Smax.romanov@nginx.com     nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
4981469Smax.romanov@nginx.com         nxt_controller_process_request(task, req);
4991469Smax.romanov@nginx.com     } nxt_queue_loop;
500249Svbart@nginx.com }
501249Svbart@nginx.com 
502249Svbart@nginx.com 
503249Svbart@nginx.com static nxt_int_t
5041526Smax.romanov@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
505249Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *data)
506249Svbart@nginx.com {
5071526Smax.romanov@nginx.com     void           *mem;
5081526Smax.romanov@nginx.com     u_char         *end;
509249Svbart@nginx.com     size_t         size;
510249Svbart@nginx.com     uint32_t       stream;
5111526Smax.romanov@nginx.com     nxt_fd_t       fd;
512249Svbart@nginx.com     nxt_int_t      rc;
513249Svbart@nginx.com     nxt_buf_t      *b;
514249Svbart@nginx.com     nxt_port_t     *router_port, *controller_port;
515249Svbart@nginx.com     nxt_runtime_t  *rt;
516249Svbart@nginx.com 
517249Svbart@nginx.com     rt = task->thread->runtime;
518249Svbart@nginx.com 
519249Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
520249Svbart@nginx.com 
5211470Smax.romanov@nginx.com     nxt_assert(router_port != NULL);
5221470Smax.romanov@nginx.com     nxt_assert(nxt_controller_router_ready);
523249Svbart@nginx.com 
524249Svbart@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
525249Svbart@nginx.com 
526249Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
527249Svbart@nginx.com 
5281526Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
529379Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
530379Smax.romanov@nginx.com         return NXT_ERROR;
531379Smax.romanov@nginx.com     }
532249Svbart@nginx.com 
5331526Smax.romanov@nginx.com     fd = nxt_shm_open(task, size);
5341526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
5351526Smax.romanov@nginx.com         return NXT_ERROR;
5361526Smax.romanov@nginx.com     }
5371526Smax.romanov@nginx.com 
5381526Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
5391526Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
5401526Smax.romanov@nginx.com         goto fail;
5411526Smax.romanov@nginx.com     }
5421526Smax.romanov@nginx.com 
5431526Smax.romanov@nginx.com     end = nxt_conf_json_print(mem, conf, NULL);
5441526Smax.romanov@nginx.com 
5451526Smax.romanov@nginx.com     nxt_mem_munmap(mem, size);
5461526Smax.romanov@nginx.com 
5471526Smax.romanov@nginx.com     size = end - (u_char *) mem;
5481526Smax.romanov@nginx.com 
5491526Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
550249Svbart@nginx.com 
551249Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
552249Svbart@nginx.com                                            handler, handler,
553249Svbart@nginx.com                                            router_port->pid, data);
554645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
5551526Smax.romanov@nginx.com         goto fail;
556645Svbart@nginx.com     }
557645Svbart@nginx.com 
5581526Smax.romanov@nginx.com     rc = nxt_port_socket_write(task, router_port,
5591526Smax.romanov@nginx.com                                NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
5601526Smax.romanov@nginx.com                                fd, stream, controller_port->id, b);
561249Svbart@nginx.com 
562249Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
563249Svbart@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
5641526Smax.romanov@nginx.com 
5651526Smax.romanov@nginx.com         goto fail;
566249Svbart@nginx.com     }
567249Svbart@nginx.com 
568249Svbart@nginx.com     return NXT_OK;
5691526Smax.romanov@nginx.com 
5701526Smax.romanov@nginx.com fail:
5711526Smax.romanov@nginx.com 
5721526Smax.romanov@nginx.com     nxt_fd_close(fd);
5731526Smax.romanov@nginx.com 
5741526Smax.romanov@nginx.com     return NXT_ERROR;
575249Svbart@nginx.com }
576249Svbart@nginx.com 
577249Svbart@nginx.com 
57820Sigor@sysoev.ru nxt_int_t
57920Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
58020Sigor@sysoev.ru {
58120Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
58220Sigor@sysoev.ru 
58365Sigor@sysoev.ru     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
58420Sigor@sysoev.ru     if (ls == NULL) {
58520Sigor@sysoev.ru         return NXT_ERROR;
58620Sigor@sysoev.ru     }
58720Sigor@sysoev.ru 
5881448Svbart@nginx.com     ls->sockaddr = rt->controller_listen;
58920Sigor@sysoev.ru 
590359Sigor@sysoev.ru     nxt_listen_socket_remote_size(ls);
59120Sigor@sysoev.ru 
59220Sigor@sysoev.ru     ls->socket = -1;
59320Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
59420Sigor@sysoev.ru     ls->read_after_accept = 1;
59520Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
59620Sigor@sysoev.ru 
59720Sigor@sysoev.ru #if 0
59820Sigor@sysoev.ru     /* STUB */
59965Sigor@sysoev.ru     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
60020Sigor@sysoev.ru     if (wq == NULL) {
60120Sigor@sysoev.ru         return NXT_ERROR;
60220Sigor@sysoev.ru     }
60320Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
60420Sigor@sysoev.ru     /**/
60520Sigor@sysoev.ru 
60620Sigor@sysoev.ru     ls->work_queue = wq;
60720Sigor@sysoev.ru #endif
60820Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
60920Sigor@sysoev.ru 
6101451Svbart@nginx.com     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
61120Sigor@sysoev.ru         return NXT_ERROR;
61220Sigor@sysoev.ru     }
61320Sigor@sysoev.ru 
61420Sigor@sysoev.ru     rt->controller_socket = ls;
61520Sigor@sysoev.ru 
61620Sigor@sysoev.ru     return NXT_OK;
61720Sigor@sysoev.ru }
61820Sigor@sysoev.ru 
61920Sigor@sysoev.ru 
62020Sigor@sysoev.ru static void
62120Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
62220Sigor@sysoev.ru {
62327Svbart@nginx.com     nxt_buf_t                 *b;
62462Sigor@sysoev.ru     nxt_conn_t                *c;
62527Svbart@nginx.com     nxt_event_engine_t        *engine;
62627Svbart@nginx.com     nxt_controller_request_t  *r;
62720Sigor@sysoev.ru 
62820Sigor@sysoev.ru     c = obj;
62920Sigor@sysoev.ru 
63020Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
63120Sigor@sysoev.ru 
63265Sigor@sysoev.ru     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
63327Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
63427Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
63527Svbart@nginx.com         return;
63627Svbart@nginx.com     }
63727Svbart@nginx.com 
638140Svbart@nginx.com     r->conn = c;
639140Svbart@nginx.com 
64060Svbart@nginx.com     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
64160Svbart@nginx.com                       != NXT_OK))
64260Svbart@nginx.com     {
64360Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
64460Svbart@nginx.com         return;
64560Svbart@nginx.com     }
64627Svbart@nginx.com 
6471167Svbart@nginx.com     r->parser.encoded_slashes = 1;
6481167Svbart@nginx.com 
64920Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
65020Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
65120Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
65220Sigor@sysoev.ru         return;
65320Sigor@sysoev.ru     }
65420Sigor@sysoev.ru 
65520Sigor@sysoev.ru     c->read = b;
65627Svbart@nginx.com     c->socket.data = r;
65720Sigor@sysoev.ru     c->socket.read_ready = 1;
65820Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
65920Sigor@sysoev.ru 
66020Sigor@sysoev.ru     engine = task->thread->engine;
66120Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
66227Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
66320Sigor@sysoev.ru 
66462Sigor@sysoev.ru     nxt_conn_read(engine, c);
66520Sigor@sysoev.ru }
66620Sigor@sysoev.ru 
66720Sigor@sysoev.ru 
66820Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
66920Sigor@sysoev.ru     nxt_aligned(64) =
67020Sigor@sysoev.ru {
67156Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_read,
67256Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
67356Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
67420Sigor@sysoev.ru 
67556Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
67656Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
67756Sigor@sysoev.ru     .timer_data = 60 * 1000,
67820Sigor@sysoev.ru };
67920Sigor@sysoev.ru 
68020Sigor@sysoev.ru 
68120Sigor@sysoev.ru static void
68220Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
68320Sigor@sysoev.ru {
68427Svbart@nginx.com     size_t                    preread;
68527Svbart@nginx.com     nxt_buf_t                 *b;
68627Svbart@nginx.com     nxt_int_t                 rc;
68762Sigor@sysoev.ru     nxt_conn_t                *c;
68827Svbart@nginx.com     nxt_controller_request_t  *r;
68920Sigor@sysoev.ru 
69020Sigor@sysoev.ru     c = obj;
69127Svbart@nginx.com     r = data;
69220Sigor@sysoev.ru 
69320Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
69420Sigor@sysoev.ru 
69527Svbart@nginx.com     nxt_queue_remove(&c-