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);
441969Sz.hong@f5.com static nxt_int_t nxt_controller_file_read(nxt_task_t *task, const char *name,
451969Sz.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
nxt_controller_prefork(nxt_task_t * task,nxt_process_t * process,nxt_mp_t * mp)1571488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
1581488St.nateldemoura@f5.com {
1591969Sz.hong@f5.com nxt_str_t ver;
1601969Sz.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
1701969Sz.hong@f5.com /*
1711969Sz.hong@f5.com * Since configuration version has only been introduced in 1.26,
1721969Sz.hong@f5.com * set the default version to 1.25.
1731969Sz.hong@f5.com */
1741969Sz.hong@f5.com nxt_conf_ver = 12500;
1751969Sz.hong@f5.com
1761969Sz.hong@f5.com ret = nxt_controller_file_read(task, rt->conf, &ctrl_init.conf, mp);
1771969Sz.hong@f5.com if (nxt_slow_path(ret == NXT_ERROR)) {
1781969Sz.hong@f5.com return NXT_ERROR;
1791969Sz.hong@f5.com }
1801488St.nateldemoura@f5.com
1811488St.nateldemoura@f5.com if (ret == NXT_OK) {
1821969Sz.hong@f5.com ret = nxt_controller_file_read(task, rt->ver, &ver, mp);
1831969Sz.hong@f5.com if (nxt_slow_path(ret == NXT_ERROR)) {
1841969Sz.hong@f5.com return NXT_ERROR;
1851969Sz.hong@f5.com }
1861969Sz.hong@f5.com
1871969Sz.hong@f5.com if (ret == NXT_OK) {
1881969Sz.hong@f5.com num = nxt_int_parse(ver.start, ver.length);
1891969Sz.hong@f5.com
1901969Sz.hong@f5.com if (nxt_slow_path(num < 0)) {
1911488St.nateldemoura@f5.com nxt_alert(task, "failed to restore previous configuration: "
1921969Sz.hong@f5.com "invalid version string \"%V\"", &ver);
1931969Sz.hong@f5.com
1941969Sz.hong@f5.com nxt_str_null(&ctrl_init.conf);
1951969Sz.hong@f5.com
1961969Sz.hong@f5.com } else {
1971969Sz.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
2141969Sz.hong@f5.com static nxt_int_t
nxt_controller_file_read(nxt_task_t * task,const char * name,nxt_str_t * str,nxt_mp_t * mp)2151969Sz.hong@f5.com nxt_controller_file_read(nxt_task_t *task, const char *name, nxt_str_t *str,
2161969Sz.hong@f5.com nxt_mp_t *mp)
2171969Sz.hong@f5.com {
2181969Sz.hong@f5.com ssize_t n;
2191969Sz.hong@f5.com nxt_int_t ret;
2201969Sz.hong@f5.com nxt_file_t file;
2211969Sz.hong@f5.com nxt_file_info_t fi;
2221969Sz.hong@f5.com
2231969Sz.hong@f5.com nxt_memzero(&file, sizeof(nxt_file_t));
2241969Sz.hong@f5.com
2251969Sz.hong@f5.com file.name = (nxt_file_name_t *) name;
2261969Sz.hong@f5.com
2271969Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
2281969Sz.hong@f5.com
2291969Sz.hong@f5.com if (ret == NXT_OK) {
2301969Sz.hong@f5.com ret = nxt_file_info(&file, &fi);
2311969Sz.hong@f5.com if (nxt_slow_path(ret != NXT_OK)) {
2321969Sz.hong@f5.com goto fail;
2331969Sz.hong@f5.com }
2341969Sz.hong@f5.com
2351969Sz.hong@f5.com if (nxt_fast_path(nxt_is_file(&fi))) {
2361969Sz.hong@f5.com str->length = nxt_file_size(&fi);
2371969Sz.hong@f5.com str->start = nxt_mp_nget(mp, str->length);
2381969Sz.hong@f5.com if (nxt_slow_path(str->start == NULL)) {
2391969Sz.hong@f5.com goto fail;
2401969Sz.hong@f5.com }
2411969Sz.hong@f5.com
2421969Sz.hong@f5.com n = nxt_file_read(&file, str->start, str->length, 0);
2431969Sz.hong@f5.com if (nxt_slow_path(n != (ssize_t) str->length)) {
2441969Sz.hong@f5.com goto fail;
2451969Sz.hong@f5.com }
2461969Sz.hong@f5.com
2471969Sz.hong@f5.com nxt_file_close(task, &file);
2481969Sz.hong@f5.com
2491969Sz.hong@f5.com return NXT_OK;
2501969Sz.hong@f5.com }
2511969Sz.hong@f5.com
2521969Sz.hong@f5.com nxt_file_close(task, &file);
2531969Sz.hong@f5.com }
2541969Sz.hong@f5.com
2551969Sz.hong@f5.com return NXT_DECLINED;
2561969Sz.hong@f5.com
2571969Sz.hong@f5.com fail:
2581969Sz.hong@f5.com
2591969Sz.hong@f5.com nxt_file_close(task, &file);
2601969Sz.hong@f5.com
2611969Sz.hong@f5.com return NXT_ERROR;
2621969Sz.hong@f5.com }
2631969Sz.hong@f5.com
2641969Sz.hong@f5.com
2651488St.nateldemoura@f5.com #if (NXT_TLS)
2661488St.nateldemoura@f5.com
2671488St.nateldemoura@f5.com static void
nxt_controller_cert_cleanup(nxt_task_t * task,void * obj,void * data)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
nxt_controller_start(nxt_task_t * task,nxt_process_data_t * data)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;
3451969Sz.hong@f5.com vldt.conf_pool = mp;
3461969Sz.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
nxt_controller_process_new_port_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)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
nxt_controller_send_current_conf(nxt_task_t * task)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
nxt_controller_router_ready_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)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
nxt_controller_remove_pid_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)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
nxt_controller_conf_default(void)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
nxt_controller_conf_init_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)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
nxt_controller_flush_requests(nxt_task_t * task)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
nxt_controller_conf_send(nxt_task_t * task,nxt_mp_t * mp,nxt_conf_value_t * conf,nxt_port_rpc_handler_t handler,void * data)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
nxt_runtime_controller_socket(nxt_task_t * task,nxt_runtime_t * rt)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
nxt_controller_conn_init(nxt_task_t * task,void * obj,void * data)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,
728*2145Stippexs91@googlemail.com .timer_data = 300 * 1000,
72920Sigor@sysoev.ru };
73020Sigor@sysoev.ru
73120Sigor@sysoev.ru
73220Sigor@sysoev.ru static void
nxt_controller_conn_read(nxt_task_t * task,void * obj,void * data)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