xref: /unit/src/nxt_controller.c (revision 1969)
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);
44*1969Sz.hong@f5.com static nxt_int_t nxt_controller_file_read(nxt_task_t *task, const char *name,
45*1969Sz.hong@f5.com     nxt_str_t *str, nxt_mp_t *mp);
461488St.nateldemoura@f5.com static nxt_int_t nxt_controller_start(nxt_task_t *task,
471488St.nateldemoura@f5.com     nxt_process_data_t *data);
48248Svbart@nginx.com static void nxt_controller_process_new_port_handler(nxt_task_t *task,
49248Svbart@nginx.com     nxt_port_recv_msg_t *msg);
50662Smax.romanov@nginx.com static void nxt_controller_send_current_conf(nxt_task_t *task);
51662Smax.romanov@nginx.com static void nxt_controller_router_ready_handler(nxt_task_t *task,
52662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
531488St.nateldemoura@f5.com static void nxt_controller_remove_pid_handler(nxt_task_t *task,
541488St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg);
55249Svbart@nginx.com static nxt_int_t nxt_controller_conf_default(void);
56249Svbart@nginx.com static void nxt_controller_conf_init_handler(nxt_task_t *task,
57249Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
581469Smax.romanov@nginx.com static void nxt_controller_flush_requests(nxt_task_t *task);
591526Smax.romanov@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp,
60249Svbart@nginx.com     nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data);
61248Svbart@nginx.com 
6220Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
6320Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
6462Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c,
6520Sigor@sysoev.ru     uintptr_t data);
6620Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
6720Sigor@sysoev.ru     void *data);
6820Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
6920Sigor@sysoev.ru     void *data);
7027Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
7127Svbart@nginx.com     void *data);
7227Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
7327Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
7427Svbart@nginx.com     void *data);
7527Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
7627Svbart@nginx.com     void *data);
7720Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
7820Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
7920Sigor@sysoev.ru 
8027Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx,
81417Svbart@nginx.com     nxt_http_field_t *field, uintptr_t data);
8227Svbart@nginx.com 
8327Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task,
84140Svbart@nginx.com     nxt_controller_request_t *req);
85774Svbart@nginx.com static void nxt_controller_process_config(nxt_task_t *task,
86774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
871470Smax.romanov@nginx.com static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task);
88774Svbart@nginx.com #if (NXT_TLS)
89774Svbart@nginx.com static void nxt_controller_process_cert(nxt_task_t *task,
90774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
91774Svbart@nginx.com static void nxt_controller_process_cert_save(nxt_task_t *task,
92774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
93774Svbart@nginx.com static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
941488St.nateldemoura@f5.com static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
951488St.nateldemoura@f5.com     void *data);
96774Svbart@nginx.com #endif
971926Smax.romanov@nginx.com static void nxt_controller_process_control(nxt_task_t *task,
981926Smax.romanov@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
991926Smax.romanov@nginx.com static void nxt_controller_app_restart_handler(nxt_task_t *task,
1001926Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
101238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task,
102238Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
103314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task,
104314Svbart@nginx.com     nxt_conf_value_t *conf);
105140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task,
106140Svbart@nginx.com     nxt_controller_request_t *req, nxt_controller_response_t *resp);
107208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
108208Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
10927Svbart@nginx.com 
11027Svbart@nginx.com 
111417Svbart@nginx.com static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
11227Svbart@nginx.com     { nxt_string("Content-Length"),
11327Svbart@nginx.com       &nxt_controller_request_content_length, 0 },
11427Svbart@nginx.com };
11527Svbart@nginx.com 
116417Svbart@nginx.com static nxt_lvlhsh_t            nxt_controller_fields_hash;
11727Svbart@nginx.com 
118314Svbart@nginx.com static nxt_uint_t              nxt_controller_listening;
119662Smax.romanov@nginx.com static nxt_uint_t              nxt_controller_router_ready;
120238Svbart@nginx.com static nxt_controller_conf_t   nxt_controller_conf;
121238Svbart@nginx.com static nxt_queue_t             nxt_controller_waiting_requests;
1221469Smax.romanov@nginx.com static nxt_bool_t              nxt_controller_waiting_init_conf;
12327Svbart@nginx.com 
12420Sigor@sysoev.ru 
12520Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
12627Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
12727Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
12820Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
12920Sigor@sysoev.ru 
13020Sigor@sysoev.ru 
1311488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
1321488St.nateldemoura@f5.com     .quit           = nxt_signal_quit_handler,
133662Smax.romanov@nginx.com     .new_port       = nxt_controller_process_new_port_handler,
134662Smax.romanov@nginx.com     .change_file    = nxt_port_change_log_file_handler,
135662Smax.romanov@nginx.com     .mmap           = nxt_port_mmap_handler,
136662Smax.romanov@nginx.com     .process_ready  = nxt_controller_router_ready_handler,
137662Smax.romanov@nginx.com     .data           = nxt_port_data_handler,
1381488St.nateldemoura@f5.com     .remove_pid     = nxt_controller_remove_pid_handler,
139662Smax.romanov@nginx.com     .rpc_ready      = nxt_port_rpc_handler,
140662Smax.romanov@nginx.com     .rpc_error      = nxt_port_rpc_handler,
141248Svbart@nginx.com };
142248Svbart@nginx.com 
143248Svbart@nginx.com 
1441488St.nateldemoura@f5.com const nxt_process_init_t  nxt_controller_process = {
1451488St.nateldemoura@f5.com     .name           = "controller",
1461488St.nateldemoura@f5.com     .type           = NXT_PROCESS_CONTROLLER,
1471488St.nateldemoura@f5.com     .prefork        = nxt_controller_prefork,
1481488St.nateldemoura@f5.com     .restart        = 1,
1491488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
1501488St.nateldemoura@f5.com     .start          = nxt_controller_start,
1511488St.nateldemoura@f5.com     .port_handlers  = &nxt_controller_process_port_handlers,
1521488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1531488St.nateldemoura@f5.com };
1541488St.nateldemoura@f5.com 
1551488St.nateldemoura@f5.com 
1561488St.nateldemoura@f5.com static nxt_int_t
1571488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
1581488St.nateldemoura@f5.com {
159*1969Sz.hong@f5.com     nxt_str_t              ver;
160*1969Sz.hong@f5.com     nxt_int_t              ret, num;
1611488St.nateldemoura@f5.com     nxt_runtime_t          *rt;
1621488St.nateldemoura@f5.com     nxt_controller_init_t  ctrl_init;
1631488St.nateldemoura@f5.com 
1641488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "controller started");
1651488St.nateldemoura@f5.com 
1661488St.nateldemoura@f5.com     rt = task->thread->runtime;
1671488St.nateldemoura@f5.com 
1681488St.nateldemoura@f5.com     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
1691488St.nateldemoura@f5.com 
170*1969Sz.hong@f5.com     /*
171*1969Sz.hong@f5.com      * Since configuration version has only been introduced in 1.26,
172*1969Sz.hong@f5.com      * set the default version to 1.25.
173*1969Sz.hong@f5.com     */
174*1969Sz.hong@f5.com     nxt_conf_ver = 12500;
175*1969Sz.hong@f5.com 
176*1969Sz.hong@f5.com     ret = nxt_controller_file_read(task, rt->conf, &ctrl_init.conf, mp);
177*1969Sz.hong@f5.com     if (nxt_slow_path(ret == NXT_ERROR)) {
178*1969Sz.hong@f5.com         return NXT_ERROR;
179*1969Sz.hong@f5.com     }
1801488St.nateldemoura@f5.com 
1811488St.nateldemoura@f5.com     if (ret == NXT_OK) {
182*1969Sz.hong@f5.com         ret = nxt_controller_file_read(task, rt->ver, &ver, mp);
183*1969Sz.hong@f5.com         if (nxt_slow_path(ret == NXT_ERROR)) {
184*1969Sz.hong@f5.com             return NXT_ERROR;
185*1969Sz.hong@f5.com         }
186*1969Sz.hong@f5.com 
187*1969Sz.hong@f5.com         if (ret == NXT_OK) {
188*1969Sz.hong@f5.com             num = nxt_int_parse(ver.start, ver.length);
189*1969Sz.hong@f5.com 
190*1969Sz.hong@f5.com             if (nxt_slow_path(num < 0)) {
1911488St.nateldemoura@f5.com                 nxt_alert(task, "failed to restore previous configuration: "
192*1969Sz.hong@f5.com                           "invalid version string \"%V\"", &ver);
193*1969Sz.hong@f5.com 
194*1969Sz.hong@f5.com                 nxt_str_null(&ctrl_init.conf);
195*1969Sz.hong@f5.com 
196*1969Sz.hong@f5.com             } else {
197*1969Sz.hong@f5.com                 nxt_conf_ver = num;
1981488St.nateldemoura@f5.com             }
1991488St.nateldemoura@f5.com         }
2001488St.nateldemoura@f5.com     }
2011488St.nateldemoura@f5.com 
2021488St.nateldemoura@f5.com #if (NXT_TLS)
2031488St.nateldemoura@f5.com     ctrl_init.certs = nxt_cert_store_load(task, mp);
2041488St.nateldemoura@f5.com 
2051488St.nateldemoura@f5.com     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
2061488St.nateldemoura@f5.com #endif
2071488St.nateldemoura@f5.com 
2081488St.nateldemoura@f5.com     process->data.controller = ctrl_init;
2091488St.nateldemoura@f5.com 
2101488St.nateldemoura@f5.com     return NXT_OK;
2111488St.nateldemoura@f5.com }
2121488St.nateldemoura@f5.com 
2131488St.nateldemoura@f5.com 
214*1969Sz.hong@f5.com static nxt_int_t
215*1969Sz.hong@f5.com nxt_controller_file_read(nxt_task_t *task, const char *name, nxt_str_t *str,
216*1969Sz.hong@f5.com     nxt_mp_t *mp)
217*1969Sz.hong@f5.com {
218*1969Sz.hong@f5.com     ssize_t          n;
219*1969Sz.hong@f5.com     nxt_int_t        ret;
220*1969Sz.hong@f5.com     nxt_file_t       file;
221*1969Sz.hong@f5.com     nxt_file_info_t  fi;
222*1969Sz.hong@f5.com 
223*1969Sz.hong@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
224*1969Sz.hong@f5.com 
225*1969Sz.hong@f5.com     file.name = (nxt_file_name_t *) name;
226*1969Sz.hong@f5.com 
227*1969Sz.hong@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
228*1969Sz.hong@f5.com 
229*1969Sz.hong@f5.com     if (ret == NXT_OK) {
230*1969Sz.hong@f5.com         ret = nxt_file_info(&file, &fi);
231*1969Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
232*1969Sz.hong@f5.com             goto fail;
233*1969Sz.hong@f5.com         }
234*1969Sz.hong@f5.com 
235*1969Sz.hong@f5.com         if (nxt_fast_path(nxt_is_file(&fi))) {
236*1969Sz.hong@f5.com             str->length = nxt_file_size(&fi);
237*1969Sz.hong@f5.com             str->start = nxt_mp_nget(mp, str->length);
238*1969Sz.hong@f5.com             if (nxt_slow_path(str->start == NULL)) {
239*1969Sz.hong@f5.com                 goto fail;
240*1969Sz.hong@f5.com             }
241*1969Sz.hong@f5.com 
242*1969Sz.hong@f5.com             n = nxt_file_read(&file, str->start, str->length, 0);
243*1969Sz.hong@f5.com             if (nxt_slow_path(n != (ssize_t) str->length)) {
244*1969Sz.hong@f5.com                 goto fail;
245*1969Sz.hong@f5.com             }
246*1969Sz.hong@f5.com 
247*1969Sz.hong@f5.com             nxt_file_close(task, &file);
248*1969Sz.hong@f5.com 
249*1969Sz.hong@f5.com             return NXT_OK;
250*1969Sz.hong@f5.com         }
251*1969Sz.hong@f5.com 
252*1969Sz.hong@f5.com         nxt_file_close(task, &file);
253*1969Sz.hong@f5.com     }
254*1969Sz.hong@f5.com 
255*1969Sz.hong@f5.com     return NXT_DECLINED;
256*1969Sz.hong@f5.com 
257*1969Sz.hong@f5.com fail:
258*1969Sz.hong@f5.com 
259*1969Sz.hong@f5.com     nxt_file_close(task, &file);
260*1969Sz.hong@f5.com 
261*1969Sz.hong@f5.com     return NXT_ERROR;
262*1969Sz.hong@f5.com }
263*1969Sz.hong@f5.com 
264*1969Sz.hong@f5.com 
2651488St.nateldemoura@f5.com #if (NXT_TLS)
2661488St.nateldemoura@f5.com 
2671488St.nateldemoura@f5.com static void
2681488St.nateldemoura@f5.com nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
2691488St.nateldemoura@f5.com {
2701488St.nateldemoura@f5.com     pid_t          main_pid;
2711488St.nateldemoura@f5.com     nxt_array_t    *certs;
2721488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
2731488St.nateldemoura@f5.com 
2741488St.nateldemoura@f5.com     certs = obj;
2751488St.nateldemoura@f5.com     rt = data;
2761488St.nateldemoura@f5.com 
2771488St.nateldemoura@f5.com     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2781488St.nateldemoura@f5.com 
2791488St.nateldemoura@f5.com     if (nxt_pid == main_pid && certs != NULL) {
2801488St.nateldemoura@f5.com         nxt_cert_store_release(certs);
2811488St.nateldemoura@f5.com     }
2821488St.nateldemoura@f5.com }
2831488St.nateldemoura@f5.com 
2841488St.nateldemoura@f5.com #endif
2851488St.nateldemoura@f5.com 
2861488St.nateldemoura@f5.com 
2871488St.nateldemoura@f5.com static nxt_int_t
2881488St.nateldemoura@f5.com nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
28920Sigor@sysoev.ru {
290417Svbart@nginx.com     nxt_mp_t               *mp;
291417Svbart@nginx.com     nxt_int_t              ret;
292417Svbart@nginx.com     nxt_str_t              *json;
293417Svbart@nginx.com     nxt_conf_value_t       *conf;
294417Svbart@nginx.com     nxt_conf_validation_t  vldt;
295774Svbart@nginx.com     nxt_controller_init_t  *init;
29627Svbart@nginx.com 
2971459Smax.romanov@nginx.com     ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
298417Svbart@nginx.com                                nxt_controller_request_fields,
299417Svbart@nginx.com                                nxt_nitems(nxt_controller_request_fields));
300417Svbart@nginx.com 
301417Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
30227Svbart@nginx.com         return NXT_ERROR;
30327Svbart@nginx.com     }
30427Svbart@nginx.com 
305248Svbart@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
30627Svbart@nginx.com 
3071488St.nateldemoura@f5.com     init = &data->controller;
308774Svbart@nginx.com 
309774Svbart@nginx.com #if (NXT_TLS)
310774Svbart@nginx.com     if (init->certs != NULL) {
311774Svbart@nginx.com         nxt_cert_info_init(task, init->certs);
312774Svbart@nginx.com         nxt_cert_store_release(init->certs);
313774Svbart@nginx.com     }
314774Svbart@nginx.com #endif
315774Svbart@nginx.com 
316774Svbart@nginx.com     json = &init->conf;
317774Svbart@nginx.com 
318774Svbart@nginx.com     if (json->start == NULL) {
319314Svbart@nginx.com         return NXT_OK;
320314Svbart@nginx.com     }
321314Svbart@nginx.com 
322314Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
323314Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
324314Svbart@nginx.com         return NXT_ERROR;
325314Svbart@nginx.com     }
326314Svbart@nginx.com 
327314Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, json);
328314Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
329564Svbart@nginx.com         nxt_alert(task, "failed to restore previous configuration: "
330564Svbart@nginx.com                   "file is corrupted or not enough memory");
331314Svbart@nginx.com 
332314Svbart@nginx.com         nxt_mp_destroy(mp);
333314Svbart@nginx.com         return NXT_OK;
334314Svbart@nginx.com     }
335314Svbart@nginx.com 
336357Svbart@nginx.com     nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
337314Svbart@nginx.com 
338357Svbart@nginx.com     vldt.pool = nxt_mp_create(1024, 128, 256, 32);
339357Svbart@nginx.com     if (nxt_slow_path(vldt.pool == NULL)) {
3401013Smax.romanov@nginx.com         nxt_mp_destroy(mp);
341357Svbart@nginx.com         return NXT_ERROR;
342314Svbart@nginx.com     }
343314Svbart@nginx.com 
344357Svbart@nginx.com     vldt.conf = conf;
345*1969Sz.hong@f5.com     vldt.conf_pool = mp;
346*1969Sz.hong@f5.com     vldt.ver = nxt_conf_ver;
347357Svbart@nginx.com 
348357Svbart@nginx.com     ret = nxt_conf_validate(&vldt);
349357Svbart@nginx.com 
350357Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
351357Svbart@nginx.com 
352357Svbart@nginx.com         if (ret == NXT_DECLINED) {
353564Svbart@nginx.com             nxt_alert(task, "the previous configuration is invalid: %V",
354564Svbart@nginx.com                       &vldt.error);
355357Svbart@nginx.com 
356357Svbart@nginx.com             nxt_mp_destroy(vldt.pool);
357357Svbart@nginx.com             nxt_mp_destroy(mp);
358357Svbart@nginx.com 
359357Svbart@nginx.com             return NXT_OK;
360357Svbart@nginx.com         }
361357Svbart@nginx.com 
362357Svbart@nginx.com         /* ret == NXT_ERROR */
363357Svbart@nginx.com 
364357Svbart@nginx.com         return NXT_ERROR;
365357Svbart@nginx.com     }
366357Svbart@nginx.com 
367357Svbart@nginx.com     nxt_mp_destroy(vldt.pool);
368314Svbart@nginx.com 
369314Svbart@nginx.com     nxt_controller_conf.root = conf;
370314Svbart@nginx.com     nxt_controller_conf.pool = mp;
371314Svbart@nginx.com 
372248Svbart@nginx.com     return NXT_OK;
373248Svbart@nginx.com }
374248Svbart@nginx.com 
375248Svbart@nginx.com 
376248Svbart@nginx.com static void
377248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task,
378248Svbart@nginx.com     nxt_port_recv_msg_t *msg)
379248Svbart@nginx.com {
380662Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
381662Smax.romanov@nginx.com 
382662Smax.romanov@nginx.com     if (msg->u.new_port->type != NXT_PROCESS_ROUTER
383662Smax.romanov@nginx.com         || !nxt_controller_router_ready)
384662Smax.romanov@nginx.com     {
385662Smax.romanov@nginx.com         return;
386662Smax.romanov@nginx.com     }
387662Smax.romanov@nginx.com 
388662Smax.romanov@nginx.com     nxt_controller_send_current_conf(task);
389662Smax.romanov@nginx.com }
390662Smax.romanov@nginx.com 
391662Smax.romanov@nginx.com 
392662Smax.romanov@nginx.com static void
393662Smax.romanov@nginx.com nxt_controller_send_current_conf(nxt_task_t *task)
394662Smax.romanov@nginx.com {
395249Svbart@nginx.com     nxt_int_t         rc;
396248Svbart@nginx.com     nxt_runtime_t     *rt;
397248Svbart@nginx.com     nxt_conf_value_t  *conf;
398248Svbart@nginx.com 
399249Svbart@nginx.com     conf = nxt_controller_conf.root;
400249Svbart@nginx.com 
401249Svbart@nginx.com     if (conf != NULL) {
4021526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf,
403249Svbart@nginx.com                                       nxt_controller_conf_init_handler, NULL);
40444Svbart@nginx.com 
405249Svbart@nginx.com         if (nxt_fast_path(rc == NXT_OK)) {
4061469Smax.romanov@nginx.com             nxt_controller_waiting_init_conf = 1;
4071469Smax.romanov@nginx.com 
408249Svbart@nginx.com             return;
409249Svbart@nginx.com         }
410249Svbart@nginx.com 
411249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
412249Svbart@nginx.com 
413249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
414249Svbart@nginx.com             nxt_abort();
415249Svbart@nginx.com         }
41644Svbart@nginx.com     }
41744Svbart@nginx.com 
418249Svbart@nginx.com     if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
419248Svbart@nginx.com         nxt_abort();
42044Svbart@nginx.com     }
42144Svbart@nginx.com 
422248Svbart@nginx.com     rt = task->thread->runtime;
423140Svbart@nginx.com 
424248Svbart@nginx.com     if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
425248Svbart@nginx.com         nxt_abort();
426248Svbart@nginx.com     }
427314Svbart@nginx.com 
428314Svbart@nginx.com     nxt_controller_listening = 1;
4291470Smax.romanov@nginx.com 
4301470Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
43120Sigor@sysoev.ru }
43220Sigor@sysoev.ru 
43320Sigor@sysoev.ru 
434662Smax.romanov@nginx.com static void
435662Smax.romanov@nginx.com nxt_controller_router_ready_handler(nxt_task_t *task,
436662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg)
437662Smax.romanov@nginx.com {
438662Smax.romanov@nginx.com     nxt_port_t     *router_port;
439662Smax.romanov@nginx.com     nxt_runtime_t  *rt;
440662Smax.romanov@nginx.com 
441662Smax.romanov@nginx.com     rt = task->thread->runtime;
442662Smax.romanov@nginx.com 
443662Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
444662Smax.romanov@nginx.com 
445662Smax.romanov@nginx.com     nxt_controller_router_ready = 1;
446662Smax.romanov@nginx.com 
447662Smax.romanov@nginx.com     if (router_port != NULL) {
448662Smax.romanov@nginx.com         nxt_controller_send_current_conf(task);
449662Smax.romanov@nginx.com     }
450662Smax.romanov@nginx.com }
451662Smax.romanov@nginx.com 
452662Smax.romanov@nginx.com 
4531488St.nateldemoura@f5.com static void
4541488St.nateldemoura@f5.com nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
4551488St.nateldemoura@f5.com {
4561488St.nateldemoura@f5.com     nxt_pid_t      pid;
4571488St.nateldemoura@f5.com     nxt_process_t  *process;
4581488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
4591488St.nateldemoura@f5.com 
4601488St.nateldemoura@f5.com     rt = task->thread->runtime;
4611488St.nateldemoura@f5.com 
4621488St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
4631488St.nateldemoura@f5.com 
4641488St.nateldemoura@f5.com     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
4651488St.nateldemoura@f5.com 
4661488St.nateldemoura@f5.com     process = nxt_runtime_process_find(rt, pid);
4671488St.nateldemoura@f5.com     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
4681488St.nateldemoura@f5.com         nxt_controller_router_ready = 0;
4691488St.nateldemoura@f5.com     }
4701488St.nateldemoura@f5.com 
4711488St.nateldemoura@f5.com     nxt_port_remove_pid_handler(task, msg);
4721488St.nateldemoura@f5.com }
4731488St.nateldemoura@f5.com 
4741488St.nateldemoura@f5.com 
475249Svbart@nginx.com static nxt_int_t
476249Svbart@nginx.com nxt_controller_conf_default(void)
477249Svbart@nginx.com {
478249Svbart@nginx.com     nxt_mp_t          *mp;
479249Svbart@nginx.com     nxt_conf_value_t  *conf;
480249Svbart@nginx.com 
481249Svbart@nginx.com     static const nxt_str_t json
482249Svbart@nginx.com         = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
483249Svbart@nginx.com 
484249Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
485249Svbart@nginx.com 
486249Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
487249Svbart@nginx.com         return NXT_ERROR;
488249Svbart@nginx.com     }
489249Svbart@nginx.com 
490249Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, &json);
491249Svbart@nginx.com 
492249Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
493249Svbart@nginx.com         return NXT_ERROR;
494249Svbart@nginx.com     }
495249Svbart@nginx.com 
496249Svbart@nginx.com     nxt_controller_conf.root = conf;
497249Svbart@nginx.com     nxt_controller_conf.pool = mp;
498249Svbart@nginx.com 
499249Svbart@nginx.com     return NXT_OK;
500249Svbart@nginx.com }
501249Svbart@nginx.com 
502249Svbart@nginx.com 
503249Svbart@nginx.com static void
504249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
505249Svbart@nginx.com     void *data)
506249Svbart@nginx.com {
507314Svbart@nginx.com     nxt_runtime_t  *rt;
508314Svbart@nginx.com 
5091469Smax.romanov@nginx.com     nxt_controller_waiting_init_conf = 0;
5101469Smax.romanov@nginx.com 
511249Svbart@nginx.com     if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
512564Svbart@nginx.com         nxt_alert(task, "failed to apply previous configuration");
513314Svbart@nginx.com 
514249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
515249Svbart@nginx.com 
516249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
517249Svbart@nginx.com             nxt_abort();
518249Svbart@nginx.com         }
519249Svbart@nginx.com     }
520314Svbart@nginx.com 
521314Svbart@nginx.com     if (nxt_controller_listening == 0) {
522314Svbart@nginx.com         rt = task->thread->runtime;
523314Svbart@nginx.com 
524314Svbart@nginx.com         if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
525314Svbart@nginx.com                           == NULL))
526314Svbart@nginx.com         {
527314Svbart@nginx.com             nxt_abort();
528314Svbart@nginx.com         }
529314Svbart@nginx.com 
530314Svbart@nginx.com         nxt_controller_listening = 1;
531314Svbart@nginx.com     }
5321469Smax.romanov@nginx.com 
5331469Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
5341469Smax.romanov@nginx.com }
5351469Smax.romanov@nginx.com 
5361469Smax.romanov@nginx.com 
5371469Smax.romanov@nginx.com static void
5381469Smax.romanov@nginx.com nxt_controller_flush_requests(nxt_task_t *task)
5391469Smax.romanov@nginx.com {
5401469Smax.romanov@nginx.com     nxt_queue_t               queue;
5411469Smax.romanov@nginx.com     nxt_controller_request_t  *req;
5421469Smax.romanov@nginx.com 
5431469Smax.romanov@nginx.com     nxt_queue_init(&queue);
5441469Smax.romanov@nginx.com     nxt_queue_add(&queue, &nxt_controller_waiting_requests);
5451469Smax.romanov@nginx.com 
5461469Smax.romanov@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
5471469Smax.romanov@nginx.com 
5481469Smax.romanov@nginx.com     nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
5491469Smax.romanov@nginx.com         nxt_controller_process_request(task, req);
5501469Smax.romanov@nginx.com     } nxt_queue_loop;
551249Svbart@nginx.com }
552249Svbart@nginx.com 
553249Svbart@nginx.com 
554249Svbart@nginx.com static nxt_int_t
5551526Smax.romanov@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
556249Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *data)
557249Svbart@nginx.com {
5581526Smax.romanov@nginx.com     void           *mem;
5591526Smax.romanov@nginx.com     u_char         *end;
560249Svbart@nginx.com     size_t         size;
561249Svbart@nginx.com     uint32_t       stream;
5621526Smax.romanov@nginx.com     nxt_fd_t       fd;
563249Svbart@nginx.com     nxt_int_t      rc;
564249Svbart@nginx.com     nxt_buf_t      *b;
565249Svbart@nginx.com     nxt_port_t     *router_port, *controller_port;
566249Svbart@nginx.com     nxt_runtime_t  *rt;
567249Svbart@nginx.com 
568249Svbart@nginx.com     rt = task->thread->runtime;
569249Svbart@nginx.com 
570249Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
571249Svbart@nginx.com 
5721470Smax.romanov@nginx.com     nxt_assert(router_port != NULL);
5731470Smax.romanov@nginx.com     nxt_assert(nxt_controller_router_ready);
574249Svbart@nginx.com 
575249Svbart@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
576249Svbart@nginx.com 
577249Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
578249Svbart@nginx.com 
5791526Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
580379Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
581379Smax.romanov@nginx.com         return NXT_ERROR;
582379Smax.romanov@nginx.com     }
583249Svbart@nginx.com 
5841526Smax.romanov@nginx.com     fd = nxt_shm_open(task, size);
5851526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
5861526Smax.romanov@nginx.com         return NXT_ERROR;
5871526Smax.romanov@nginx.com     }
5881526Smax.romanov@nginx.com 
5891526Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
5901526Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
5911526Smax.romanov@nginx.com         goto fail;
5921526Smax.romanov@nginx.com     }
5931526Smax.romanov@nginx.com 
5941526Smax.romanov@nginx.com     end = nxt_conf_json_print(mem, conf, NULL);
5951526Smax.romanov@nginx.com 
5961526Smax.romanov@nginx.com     nxt_mem_munmap(mem, size);
5971526Smax.romanov@nginx.com 
5981526Smax.romanov@nginx.com     size = end - (u_char *) mem;
5991526Smax.romanov@nginx.com 
6001526Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
601249Svbart@nginx.com 
602249Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
603249Svbart@nginx.com                                            handler, handler,
604249Svbart@nginx.com                                            router_port->pid, data);
605645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
6061526Smax.romanov@nginx.com         goto fail;
607645Svbart@nginx.com     }
608645Svbart@nginx.com 
6091526Smax.romanov@nginx.com     rc = nxt_port_socket_write(task, router_port,
6101526Smax.romanov@nginx.com                                NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
6111526Smax.romanov@nginx.com                                fd, stream, controller_port->id, b);
612249Svbart@nginx.com 
613249Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
614249Svbart@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
6151526Smax.romanov@nginx.com 
6161526Smax.romanov@nginx.com         goto fail;
617249Svbart@nginx.com     }
618249Svbart@nginx.com 
619249Svbart@nginx.com     return NXT_OK;
6201526Smax.romanov@nginx.com 
6211526Smax.romanov@nginx.com fail:
6221526Smax.romanov@nginx.com 
6231526Smax.romanov@nginx.com     nxt_fd_close(fd);
6241526Smax.romanov@nginx.com 
6251526Smax.romanov@nginx.com     return NXT_ERROR;
626249Svbart@nginx.com }
627249Svbart@nginx.com 
628249Svbart@nginx.com 
62920Sigor@sysoev.ru nxt_int_t
63020Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
63120Sigor@sysoev.ru {
63220Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
63320Sigor@sysoev.ru 
63465Sigor@sysoev.ru     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
63520Sigor@sysoev.ru     if (ls == NULL) {
63620Sigor@sysoev.ru         return NXT_ERROR;
63720Sigor@sysoev.ru     }
63820Sigor@sysoev.ru 
6391448Svbart@nginx.com     ls->sockaddr = rt->controller_listen;
64020Sigor@sysoev.ru 
641359Sigor@sysoev.ru     nxt_listen_socket_remote_size(ls);
64220Sigor@sysoev.ru 
64320Sigor@sysoev.ru     ls->socket = -1;
64420Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
64520Sigor@sysoev.ru     ls->read_after_accept = 1;
64620Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
64720Sigor@sysoev.ru 
64820Sigor@sysoev.ru #if 0
64920Sigor@sysoev.ru     /* STUB */
65065Sigor@sysoev.ru     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
65120Sigor@sysoev.ru     if (wq == NULL) {
65220Sigor@sysoev.ru         return NXT_ERROR;
65320Sigor@sysoev.ru     }
65420Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
65520Sigor@sysoev.ru     /**/
65620Sigor@sysoev.ru 
65720Sigor@sysoev.ru     ls->work_queue = wq;
65820Sigor@sysoev.ru #endif
65920Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
66020Sigor@sysoev.ru 
6611451Svbart@nginx.com     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
66220Sigor@sysoev.ru         return NXT_ERROR;
66320Sigor@sysoev.ru     }
66420Sigor@sysoev.ru 
66520Sigor@sysoev.ru     rt->controller_socket = ls;
66620Sigor@sysoev.ru 
66720Sigor@sysoev.ru     return NXT_OK;
66820Sigor@sysoev.ru }
66920Sigor@sysoev.ru 
67020Sigor@sysoev.ru 
67120Sigor@sysoev.ru static void
67220Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
67320Sigor@sysoev.ru {
67427Svbart@nginx.com     nxt_buf_t                 *b;
67562Sigor@sysoev.ru     nxt_conn_t                *c;
67627Svbart@nginx.com     nxt_event_engine_t        *engine;
67727Svbart@nginx.com     nxt_controller_request_t  *r;
67820Sigor@sysoev.ru 
67920Sigor@sysoev.ru     c = obj;
68020Sigor@sysoev.ru 
68120Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
68220Sigor@sysoev.ru 
68365Sigor@sysoev.ru     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
68427Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
68527Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
68627Svbart@nginx.com         return;
68727Svbart@nginx.com     }
68827Svbart@nginx.com 
689140Svbart@nginx.com     r->conn = c;
690140Svbart@nginx.com 
69160Svbart@nginx.com     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
69260Svbart@nginx.com                       != NXT_OK))
69360Svbart@nginx.com     {
69460Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
69560Svbart@nginx.com         return;
69660Svbart@nginx.com     }
69727Svbart@nginx.com 
6981167Svbart@nginx.com     r->parser.encoded_slashes = 1;
6991167Svbart@nginx.com 
70020Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
70120Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
70220Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
70320Sigor@sysoev.ru         return;
70420Sigor@sysoev.ru     }
70520Sigor@sysoev.ru 
70620Sigor@sysoev.ru     c->read = b;
70727Svbart@nginx.com     c->socket.data = r;
70820Sigor@sysoev.ru     c->socket.read_ready = 1;
70920Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
71020Sigor@sysoev.ru 
71120Sigor@sysoev.ru     engine = task->thread->engine;
71220Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
71327Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
71420Sigor@sysoev.ru 
71562Sigor@sysoev.ru     nxt_conn_read(engine, c);
71620Sigor@sysoev.ru }
71720Sigor@sysoev.ru 
71820Sigor@sysoev.ru 
71920Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
72020Sigor@sysoev.ru     nxt_aligned(64) =
72120Sigor@sysoev.ru {
72256Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_read,
72356Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
72456Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
72520Sigor@sysoev.ru 
72656Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
72756Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
72856Sigor@sysoev.ru     .timer_data = 60 * 1000,
72920Sigor@sysoev.ru };
73020Sigor@sysoev.ru 
73120Sigor@sysoev.ru 
73220Sigor@sysoev.ru static void
73320Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
73420Sigor@sysoev.ru {
73527Svbart@nginx.com     size_t                    preread;
73627Svbart@nginx.com     nxt_buf_t                 *b;
73727Svbart@nginx.com     nxt_int_t                 rc;
73862Sigor@sysoev.ru     nxt_conn_t                *c;
73927Svbart@nginx.com     nxt_controller_request_t  *r;
74020Sigor@sysoev.ru 
74120Sigor@sysoev.ru     c = obj;
74227Svbart@nginx.com     r = data;
74320Sigor@sysoev.ru 
74420Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
74520Sigor@sysoev.ru 
74627Svbart@nginx.com     nxt_queue_remove(&c->link);
74727Svbart@nginx.com     nxt_queue_self(&c->link);
74827Svbart@nginx.com 
74927Svbart@nginx.com     b = c->read;
75027Svbart@nginx.com 
75127Svbart@nginx.com     rc = nxt_http_parse_request(&r->parser, &b->mem);
75227Svbart@nginx.com 
75327Svbart@nginx.com     if (nxt_slow_path(rc != NXT_DONE)) {
75427Svbart@nginx.com 
75527Svbart@nginx.com         if (rc == NXT_AGAIN) {
75627Svbart@nginx.com             if (nxt_buf_mem_free_size(&b->mem) == 0) {
75727Svbart@nginx.com                 nxt_log(task, NXT_LOG_ERR, "too long request headers");
75827Svbart@nginx.com                 nxt_controller_conn_close(task, c, r);
75927Svbart@nginx.com                 return;
76027Svbart@nginx.com             }
76127Svbart@nginx.com 
76262Sigor@sysoev.ru             nxt_conn_read(task->thread->engine, c);
76327Svbart@nginx.com             return;
76427Svbart@nginx.com         }
76527Svbart@nginx.com 
76627Svbart@nginx.com         /* rc == NXT_ERROR */
76727Svbart@nginx.com 
76827Svbart@nginx.com         nxt_log(task, NXT_LOG_ERR, "parsing error");
769