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->link); 69627Svbart@nginx.com nxt_queue_self(&c->link); 69727Svbart@nginx.com 69827Svbart@nginx.com b = c->read; 69927Svbart@nginx.com 70027Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 70127Svbart@nginx.com 70227Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 70327Svbart@nginx.com 70427Svbart@nginx.com if (rc == NXT_AGAIN) { 70527Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 70627Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 70727Svbart@nginx.com nxt_controller_conn_close(task, c, r); 70827Svbart@nginx.com return; 70927Svbart@nginx.com } 71027Svbart@nginx.com 71162Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 71227Svbart@nginx.com return; 71327Svbart@nginx.com } 71427Svbart@nginx.com 71527Svbart@nginx.com /* rc == NXT_ERROR */ 71627Svbart@nginx.com 71727Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 71827Svbart@nginx.com 71927Svbart@nginx.com nxt_controller_conn_close(task, c, r); 72027Svbart@nginx.com return; 72127Svbart@nginx.com } 72227Svbart@nginx.com 723417Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash, 724417Svbart@nginx.com r); 72560Svbart@nginx.com 72660Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 72760Svbart@nginx.com nxt_controller_conn_close(task, c, r); 72860Svbart@nginx.com return; 72960Svbart@nginx.com } 73060Svbart@nginx.com 73127Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 73227Svbart@nginx.com 73327Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 734107Svbart@nginx.com "body length: %uz, preread: %uz", 73527Svbart@nginx.com r->length, preread); 73627Svbart@nginx.com 73727Svbart@nginx.com if (preread >= r->length) { 738140Svbart@nginx.com nxt_controller_process_request(task, r); 73927Svbart@nginx.com return; 74027Svbart@nginx.com } 74127Svbart@nginx.com 74227Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 74327Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 74427Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 74527Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 74627Svbart@nginx.com return; 74727Svbart@nginx.com } 74827Svbart@nginx.com 74927Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 75027Svbart@nginx.com 75127Svbart@nginx.com c->read = b; 75227Svbart@nginx.com } 75327Svbart@nginx.com 75427Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 75527Svbart@nginx.com 75662Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 75720Sigor@sysoev.ru } 75820Sigor@sysoev.ru 75920Sigor@sysoev.ru 76020Sigor@sysoev.ru static nxt_msec_t 76162Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 76220Sigor@sysoev.ru { 76320Sigor@sysoev.ru return (nxt_msec_t) data; 76420Sigor@sysoev.ru } 76520Sigor@sysoev.ru 76620Sigor@sysoev.ru 76720Sigor@sysoev.ru static void 76820Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 76920Sigor@sysoev.ru { 77062Sigor@sysoev.ru nxt_conn_t *c; 77120Sigor@sysoev.ru 77220Sigor@sysoev.ru c = obj; 77320Sigor@sysoev.ru 77420Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 77520Sigor@sysoev.ru 77627Svbart@nginx.com nxt_controller_conn_close(task, c, data); 77720Sigor@sysoev.ru } 77820Sigor@sysoev.ru 77920Sigor@sysoev.ru 78020Sigor@sysoev.ru static void 78120Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 78220Sigor@sysoev.ru { 78362Sigor@sysoev.ru nxt_timer_t *timer; 78462Sigor@sysoev.ru nxt_conn_t *c; 78520Sigor@sysoev.ru 78662Sigor@sysoev.ru timer = obj; 78720Sigor@sysoev.ru 78862Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 78920Sigor@sysoev.ru c->socket.timedout = 1; 79020Sigor@sysoev.ru c->socket.closed = 1; 79120Sigor@sysoev.ru 79220Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 79320Sigor@sysoev.ru 79427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 79527Svbart@nginx.com } 79627Svbart@nginx.com 79727Svbart@nginx.com 79827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 79927Svbart@nginx.com nxt_aligned(64) = 80027Svbart@nginx.com { 80156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 80256Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 80356Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 80427Svbart@nginx.com 80556Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 80656Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 80756Sigor@sysoev.ru .timer_data = 60 * 1000, 80856Sigor@sysoev.ru .timer_autoreset = 1, 80927Svbart@nginx.com }; 81027Svbart@nginx.com 81127Svbart@nginx.com 81227Svbart@nginx.com static void 81327Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 81427Svbart@nginx.com { 815107Svbart@nginx.com size_t read; 816107Svbart@nginx.com nxt_buf_t *b; 817107Svbart@nginx.com nxt_conn_t *c; 818107Svbart@nginx.com nxt_controller_request_t *r; 81927Svbart@nginx.com 82027Svbart@nginx.com c = obj; 821107Svbart@nginx.com r = data; 82227Svbart@nginx.com b = c->read; 82327Svbart@nginx.com 824107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 82527Svbart@nginx.com 826107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 827107Svbart@nginx.com read, r->length); 82827Svbart@nginx.com 829107Svbart@nginx.com if (read >= r->length) { 830140Svbart@nginx.com nxt_controller_process_request(task, r); 83127Svbart@nginx.com return; 83227Svbart@nginx.com } 83327Svbart@nginx.com 83462Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 83527Svbart@nginx.com } 83627Svbart@nginx.com 83727Svbart@nginx.com 83827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 83927Svbart@nginx.com nxt_aligned(64) = 84027Svbart@nginx.com { 84156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 84256Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 84327Svbart@nginx.com 84456Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 84556Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 84656Sigor@sysoev.ru .timer_data = 60 * 1000, 84756Sigor@sysoev.ru .timer_autoreset = 1, 84827Svbart@nginx.com }; 84927Svbart@nginx.com 85027Svbart@nginx.com 85127Svbart@nginx.com static void 85227Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 85327Svbart@nginx.com { 85462Sigor@sysoev.ru nxt_buf_t *b; 85562Sigor@sysoev.ru nxt_conn_t *c; 85627Svbart@nginx.com 85727Svbart@nginx.com c = obj; 85827Svbart@nginx.com 85927Svbart@nginx.com nxt_debug(task, "controller conn write"); 86027Svbart@nginx.com 86127Svbart@nginx.com b = c->write; 86227Svbart@nginx.com 86327Svbart@nginx.com if (b->mem.pos != b->mem.free) { 86462Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 86527Svbart@nginx.com return; 86627Svbart@nginx.com } 86727Svbart@nginx.com 86827Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 86927Svbart@nginx.com 87027Svbart@nginx.com nxt_controller_conn_close(task, c, data); 87127Svbart@nginx.com } 87227Svbart@nginx.com 87327Svbart@nginx.com 87427Svbart@nginx.com static void 87527Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 87627Svbart@nginx.com { 87762Sigor@sysoev.ru nxt_conn_t *c; 87827Svbart@nginx.com 87927Svbart@nginx.com c = obj; 88027Svbart@nginx.com 88127Svbart@nginx.com nxt_debug(task, "controller conn write error"); 88227Svbart@nginx.com 88327Svbart@nginx.com nxt_controller_conn_close(task, c, data); 88427Svbart@nginx.com } 88527Svbart@nginx.com 88627Svbart@nginx.com 88727Svbart@nginx.com static void 88827Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 88927Svbart@nginx.com { 89062Sigor@sysoev.ru nxt_conn_t *c; 89162Sigor@sysoev.ru nxt_timer_t *timer; 89227Svbart@nginx.com 89362Sigor@sysoev.ru timer = obj; 89427Svbart@nginx.com 89562Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 89627Svbart@nginx.com c->socket.timedout = 1; 89727Svbart@nginx.com c->socket.closed = 1; 89827Svbart@nginx.com 89927Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 90027Svbart@nginx.com 90127Svbart@nginx.com nxt_controller_conn_close(task, c, data); 90220Sigor@sysoev.ru } 90320Sigor@sysoev.ru 90420Sigor@sysoev.ru 90520Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 90620Sigor@sysoev.ru nxt_aligned(64) = 90720Sigor@sysoev.ru { 90856Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 90920Sigor@sysoev.ru }; 91020Sigor@sysoev.ru 91120Sigor@sysoev.ru 91220Sigor@sysoev.ru static void 91320Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 91420Sigor@sysoev.ru { 91562Sigor@sysoev.ru nxt_conn_t *c; 91620Sigor@sysoev.ru 91720Sigor@sysoev.ru c = obj; 91820Sigor@sysoev.ru 91920Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 92020Sigor@sysoev.ru 92127Svbart@nginx.com nxt_queue_remove(&c->link); 92227Svbart@nginx.com 92320Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 92420Sigor@sysoev.ru 92562Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 92620Sigor@sysoev.ru } 92720Sigor@sysoev.ru 92820Sigor@sysoev.ru 92920Sigor@sysoev.ru static void 93020Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 93120Sigor@sysoev.ru { 93262Sigor@sysoev.ru nxt_conn_t *c; 93320Sigor@sysoev.ru 93420Sigor@sysoev.ru c = obj; 93520Sigor@sysoev.ru 93620Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 93720Sigor@sysoev.ru 938337Sigor@sysoev.ru nxt_sockaddr_cache_free(task->thread->engine, c); 939337Sigor@sysoev.ru 940386Sigor@sysoev.ru nxt_conn_free(task, c); 94120Sigor@sysoev.ru } 94227Svbart@nginx.com 94327Svbart@nginx.com 94427Svbart@nginx.com static nxt_int_t 94560Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 946417Svbart@nginx.com uintptr_t data) 94727Svbart@nginx.com { 94827Svbart@nginx.com off_t length; 94927Svbart@nginx.com nxt_controller_request_t *r; 95027Svbart@nginx.com 95127Svbart@nginx.com r = ctx; 95227Svbart@nginx.com 953417Svbart@nginx.com length = nxt_off_t_parse(field->value, field->value_length); 95427Svbart@nginx.com 955710Svbart@nginx.com if (nxt_fast_path(length >= 0)) { 956107Svbart@nginx.com 957107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 958417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, 959417Svbart@nginx.com "Content-Length is too big"); 960107Svbart@nginx.com return NXT_ERROR; 961107Svbart@nginx.com } 96227Svbart@nginx.com 96327Svbart@nginx.com r->length = length; 96427Svbart@nginx.com return NXT_OK; 96527Svbart@nginx.com } 96627Svbart@nginx.com 967417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid"); 96827Svbart@nginx.com 96927Svbart@nginx.com return NXT_ERROR; 97027Svbart@nginx.com } 97127Svbart@nginx.com 97227Svbart@nginx.com 97327Svbart@nginx.com static void 974140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 97527Svbart@nginx.com { 976774Svbart@nginx.com uint32_t i, count; 977774Svbart@nginx.com nxt_str_t path; 978774Svbart@nginx.com nxt_conn_t *c; 979774Svbart@nginx.com nxt_conf_value_t *value; 980774Svbart@nginx.com nxt_controller_response_t resp; 981774Svbart@nginx.com #if (NXT_TLS) 982774Svbart@nginx.com nxt_conf_value_t *certs; 983774Svbart@nginx.com 984774Svbart@nginx.com static nxt_str_t certificates = nxt_string("certificates"); 985774Svbart@nginx.com #endif 986774Svbart@nginx.com static nxt_str_t config = nxt_string("config"); 987774Svbart@nginx.com 988774Svbart@nginx.com c = req->conn; 989774Svbart@nginx.com path = req->parser.path; 990774Svbart@nginx.com 991774Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 992774Svbart@nginx.com path.length--; 993774Svbart@nginx.com } 994774Svbart@nginx.com 995774Svbart@nginx.com if (nxt_str_start(&path, "/config", 7) 996774Svbart@nginx.com && (path.length == 7 || path.start[7] == '/')) 997774Svbart@nginx.com { 998774Svbart@nginx.com if (path.length == 7) { 999774Svbart@nginx.com path.length = 1; 1000774Svbart@nginx.com 1001774Svbart@nginx.com } else { 1002774Svbart@nginx.com path.length -= 7; 1003774Svbart@nginx.com path.start += 7; 1004774Svbart@nginx.com } 1005774Svbart@nginx.com 1006774Svbart@nginx.com nxt_controller_process_config(task, req, &path); 1007774Svbart@nginx.com return; 1008774Svbart@nginx.com } 1009774Svbart@nginx.com 1010774Svbart@nginx.com #if (NXT_TLS) 1011774Svbart@nginx.com 1012774Svbart@nginx.com if (nxt_str_start(&path, "/certificates", 13) 1013774Svbart@nginx.com && (path.length == 13 || path.start[13] == '/')) 1014774Svbart@nginx.com { 1015774Svbart@nginx.com if (path.length == 13) { 1016774Svbart@nginx.com path.length = 1; 1017774Svbart@nginx.com 1018774Svbart@nginx.com } else { 1019774Svbart@nginx.com path.length -= 13; 1020774Svbart@nginx.com path.start += 13; 1021774Svbart@nginx.com } 1022774Svbart@nginx.com 1023774Svbart@nginx.com nxt_controller_process_cert(task, req, &path); 1024774Svbart@nginx.com return; 1025774Svbart@nginx.com } 1026774Svbart@nginx.com 1027774Svbart@nginx.com #endif 1028774Svbart@nginx.com 1029*1926Smax.romanov@nginx.com if (nxt_str_start(&path, "/control/", 9)) { 1030*1926Smax.romanov@nginx.com path.length -= 9; 1031*1926Smax.romanov@nginx.com path.start += 9; 1032*1926Smax.romanov@nginx.com 1033*1926Smax.romanov@nginx.com nxt_controller_process_control(task, req, &path); 1034*1926Smax.romanov@nginx.com return; 1035*1926Smax.romanov@nginx.com } 1036*1926Smax.romanov@nginx.com 1037774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1038774Svbart@nginx.com 1039774Svbart@nginx.com if (path.length == 1 && path.start[0] == '/') { 1040774Svbart@nginx.com 1041774Svbart@nginx.com if (!nxt_str_eq(&req->parser.method, "GET", 3)) { 1042774Svbart@nginx.com goto invalid_method; 1043774Svbart@nginx.com } 1044774Svbart@nginx.com 1045774Svbart@nginx.com count = 1; 1046774Svbart@nginx.com #if (NXT_TLS) 1047774Svbart@nginx.com count++; 1048774Svbart@nginx.com #endif 1049774Svbart@nginx.com 1050774Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, count); 1051774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1052774Svbart@nginx.com goto alloc_fail; 1053774Svbart@nginx.com } 1054774Svbart@nginx.com 1055774Svbart@nginx.com i = 0; 1056774Svbart@nginx.com 1057774Svbart@nginx.com #if (NXT_TLS) 1058774Svbart@nginx.com certs = nxt_cert_info_get_all(c->mem_pool); 1059774Svbart@nginx.com if (nxt_slow_path(certs == NULL)) { 1060774Svbart@nginx.com goto alloc_fail; 1061774Svbart@nginx.com } 1062774Svbart@nginx.com 1063774Svbart@nginx.com nxt_conf_set_member(value, &certificates, certs, i++); 1064774Svbart@nginx.com #endif 1065774Svbart@nginx.com 1066774Svbart@nginx.com nxt_conf_set_member(value, &config, nxt_controller_conf.root, i); 1067774Svbart@nginx.com 1068774Svbart@nginx.com resp.status = 200; 1069774Svbart@nginx.com resp.conf = value; 1070774Svbart@nginx.com 1071774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1072774Svbart@nginx.com return; 1073774Svbart@nginx.com } 1074774Svbart@nginx.com 1075774Svbart@nginx.com resp.status = 404; 1076774Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1077774Svbart@nginx.com resp.offset = -1; 1078774Svbart@nginx.com 1079774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1080774Svbart@nginx.com return; 1081774Svbart@nginx.com 1082774Svbart@nginx.com invalid_method: 1083774Svbart@nginx.com 1084774Svbart@nginx.com resp.status = 405; 1085774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 1086774Svbart@nginx.com resp.offset = -1; 1087774Svbart@nginx.com 1088774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1089774Svbart@nginx.com return; 1090774Svbart@nginx.com 1091774Svbart@nginx.com alloc_fail: 1092774Svbart@nginx.com 1093774Svbart@nginx.com resp.status = 500; 1094774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1095774Svbart@nginx.com resp.offset = -1; 1096774Svbart@nginx.com 1097774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1098774Svbart@nginx.com return; 1099774Svbart@nginx.com } 1100774Svbart@nginx.com 1101774Svbart@nginx.com 1102774Svbart@nginx.com static void 1103774Svbart@nginx.com nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, 1104774Svbart@nginx.com nxt_str_t *path) 1105774Svbart@nginx.com { 110665Sigor@sysoev.ru nxt_mp_t *mp; 110751Svbart@nginx.com nxt_int_t rc; 1108140Svbart@nginx.com nxt_conn_t *c; 11091049Svbart@nginx.com nxt_bool_t post; 111051Svbart@nginx.com nxt_buf_mem_t *mbuf; 1111106Svbart@nginx.com nxt_conf_op_t *ops; 1112106Svbart@nginx.com nxt_conf_value_t *value; 1113357Svbart@nginx.com nxt_conf_validation_t vldt; 1114208Svbart@nginx.com nxt_conf_json_error_t error; 111544Svbart@nginx.com nxt_controller_response_t resp; 111644Svbart@nginx.com 111751Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 111851Svbart@nginx.com 1119774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1120632Svbart@nginx.com 1121774Svbart@nginx.com c = req->conn; 112244Svbart@nginx.com 112344Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 112446Svbart@nginx.com 1125774Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, path); 112651Svbart@nginx.com 112751Svbart@nginx.com if (value == NULL) { 1128208Svbart@nginx.com goto not_found; 112951Svbart@nginx.com } 113051Svbart@nginx.com 1131208Svbart@nginx.com resp.status = 200; 1132106Svbart@nginx.com resp.conf = value; 113346Svbart@nginx.com 1134208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1135208Svbart@nginx.com return; 113651Svbart@nginx.com } 113751Svbart@nginx.com 11381049Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "POST", 4)) { 11391049Svbart@nginx.com if (path->length == 1) { 11401049Svbart@nginx.com goto not_allowed; 11411049Svbart@nginx.com } 11421049Svbart@nginx.com 11431049Svbart@nginx.com post = 1; 11441049Svbart@nginx.com 11451049Svbart@nginx.com } else { 11461049Svbart@nginx.com post = 0; 11471049Svbart@nginx.com } 11481049Svbart@nginx.com 11491049Svbart@nginx.com if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) { 115046Svbart@nginx.com 11511470Smax.romanov@nginx.com if (nxt_controller_check_postpone_request(task)) { 1152238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 1153238Svbart@nginx.com return; 1154238Svbart@nginx.com } 1155238Svbart@nginx.com 115665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 115751Svbart@nginx.com 115851Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1159208Svbart@nginx.com goto alloc_fail; 116046Svbart@nginx.com } 116146Svbart@nginx.com 116251Svbart@nginx.com mbuf = &c->read->mem; 116351Svbart@nginx.com 1164208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 1165208Svbart@nginx.com 11661364Svbart@nginx.com /* Skip UTF-8 BOM. */ 11671364Svbart@nginx.com if (nxt_buf_mem_used_size(mbuf) >= 3 11681364Svbart@nginx.com && nxt_memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0) 11691364Svbart@nginx.com { 11701364Svbart@nginx.com mbuf->pos += 3; 11711364Svbart@nginx.com } 11721364Svbart@nginx.com 1173208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 117451Svbart@nginx.com 117551Svbart@nginx.com if (value == NULL) { 117665Sigor@sysoev.ru nxt_mp_destroy(mp); 1177208Svbart@nginx.com 1178208Svbart@nginx.com if (error.pos == NULL) { 1179208Svbart@nginx.com goto alloc_fail; 1180208Svbart@nginx.com } 1181208Svbart@nginx.com 1182208Svbart@nginx.com resp.status = 400; 1183208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 1184357Svbart@nginx.com resp.detail.length = nxt_strlen(error.detail); 1185357Svbart@nginx.com resp.detail.start = error.detail; 1186208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 1187208Svbart@nginx.com 1188208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 1189208Svbart@nginx.com &resp.line, &resp.column); 1190208Svbart@nginx.com 1191208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1192208Svbart@nginx.com return; 119351Svbart@nginx.com } 119451Svbart@nginx.com 1195774Svbart@nginx.com if (path->length != 1) { 1196106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1197106Svbart@nginx.com nxt_controller_conf.root, 11981049Svbart@nginx.com path, value, post); 119946Svbart@nginx.com 12001049Svbart@nginx.com if (rc != NXT_CONF_OP_OK) { 1201619Svbart@nginx.com nxt_mp_destroy(mp); 1202619Svbart@nginx.com 12031049Svbart@nginx.com switch (rc) { 12041049Svbart@nginx.com case NXT_CONF_OP_NOT_FOUND: 1205208Svbart@nginx.com goto not_found; 12061049Svbart@nginx.com 12071049Svbart@nginx.com case NXT_CONF_OP_NOT_ALLOWED: 12081049Svbart@nginx.com goto not_allowed; 120951Svbart@nginx.com } 121046Svbart@nginx.com 12111049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1212208Svbart@nginx.com goto alloc_fail; 121351Svbart@nginx.com } 121451Svbart@nginx.com 1215106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 121651Svbart@nginx.com 121751Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 121865Sigor@sysoev.ru nxt_mp_destroy(mp); 1219208Svbart@nginx.com goto alloc_fail; 122051Svbart@nginx.com } 122146Svbart@nginx.com } 122244Svbart@nginx.com 1223357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1224357Svbart@nginx.com 1225357Svbart@nginx.com vldt.conf = value; 1226357Svbart@nginx.com vldt.pool = c->mem_pool; 1227357Svbart@nginx.com 1228357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1229357Svbart@nginx.com 1230357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1231121Svbart@nginx.com nxt_mp_destroy(mp); 1232357Svbart@nginx.com 1233357Svbart@nginx.com if (rc == NXT_DECLINED) { 1234357Svbart@nginx.com resp.detail = vldt.error; 1235357Svbart@nginx.com goto invalid_conf; 1236357Svbart@nginx.com } 1237357Svbart@nginx.com 1238357Svbart@nginx.com /* rc == NXT_ERROR */ 1239357Svbart@nginx.com goto alloc_fail; 1240116Svbart@nginx.com } 1241116Svbart@nginx.com 12421526Smax.romanov@nginx.com rc = nxt_controller_conf_send(task, mp, value, 1243249Svbart@nginx.com nxt_controller_conf_handler, req); 1244247Svbart@nginx.com 1245247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1246121Svbart@nginx.com nxt_mp_destroy(mp); 1247247Svbart@nginx.com 1248247Svbart@nginx.com /* rc == NXT_ERROR */ 1249208Svbart@nginx.com goto alloc_fail; 1250121Svbart@nginx.com } 1251121Svbart@nginx.com 1252249Svbart@nginx.com req->conf.root = value; 1253249Svbart@nginx.com req->conf.pool = mp; 1254249Svbart@nginx.com 1255249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1256249Svbart@nginx.com 1257140Svbart@nginx.com return; 125851Svbart@nginx.com } 125927Svbart@nginx.com 126051Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 126151Svbart@nginx.com 12621470Smax.romanov@nginx.com if (nxt_controller_check_postpone_request(task)) { 1263238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 1264238Svbart@nginx.com return; 1265238Svbart@nginx.com } 1266238Svbart@nginx.com 1267774Svbart@nginx.com if (path->length == 1) { 126865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 126944Svbart@nginx.com 127051Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1271208Svbart@nginx.com goto alloc_fail; 127251Svbart@nginx.com } 127351Svbart@nginx.com 1274106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 127527Svbart@nginx.com 127644Svbart@nginx.com } else { 1277106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1278106Svbart@nginx.com nxt_controller_conf.root, 12791049Svbart@nginx.com path, NULL, 0); 128051Svbart@nginx.com 128151Svbart@nginx.com if (rc != NXT_OK) { 12821049Svbart@nginx.com if (rc == NXT_CONF_OP_NOT_FOUND) { 1283208Svbart@nginx.com goto not_found; 128451Svbart@nginx.com } 128551Svbart@nginx.com 12861049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1287208Svbart@nginx.com goto alloc_fail; 128851Svbart@nginx.com } 128951Svbart@nginx.com 129065Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 129151Svbart@nginx.com 129251Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1293208Svbart@nginx.com goto alloc_fail; 129451Svbart@nginx.com } 129551Svbart@nginx.com 1296106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 129751Svbart@nginx.com } 129851Svbart@nginx.com 129951Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 130065Sigor@sysoev.ru nxt_mp_destroy(mp); 1301208Svbart@nginx.com goto alloc_fail; 130244Svbart@nginx.com } 130344Svbart@nginx.com 1304357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1305357Svbart@nginx.com 1306357Svbart@nginx.com vldt.conf = value; 1307357Svbart@nginx.com vldt.pool = c->mem_pool; 1308357Svbart@nginx.com 1309357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1310357Svbart@nginx.com 1311357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1312121Svbart@nginx.com nxt_mp_destroy(mp); 1313357Svbart@nginx.com 1314357Svbart@nginx.com if (rc == NXT_DECLINED) { 1315357Svbart@nginx.com resp.detail = vldt.error; 1316357Svbart@nginx.com goto invalid_conf; 1317357Svbart@nginx.com } 1318357Svbart@nginx.com 1319357Svbart@nginx.com /* rc == NXT_ERROR */ 1320357Svbart@nginx.com goto alloc_fail; 1321116Svbart@nginx.com } 1322116Svbart@nginx.com 13231526Smax.romanov@nginx.com rc = nxt_controller_conf_send(task, mp, value, 1324249Svbart@nginx.com nxt_controller_conf_handler, req); 1325247Svbart@nginx.com 1326247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1327121Svbart@nginx.com nxt_mp_destroy(mp); 1328247Svbart@nginx.com 1329247Svbart@nginx.com /* rc == NXT_ERROR */ 1330208Svbart@nginx.com goto alloc_fail; 1331121Svbart@nginx.com } 1332121Svbart@nginx.com 1333249Svbart@nginx.com req->conf.root = value; 1334249Svbart@nginx.com req->conf.pool = mp; 1335249Svbart@nginx.com 1336249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1337249Svbart@nginx.com 1338140Svbart@nginx.com return; 133951Svbart@nginx.com } 134051Svbart@nginx.com 13411049Svbart@nginx.com not_allowed: 13421049Svbart@nginx.com 1343208Svbart@nginx.com resp.status = 405; 13441049Svbart@nginx.com resp.title = (u_char *) "Method isn't allowed."; 1345208Svbart@nginx.com resp.offset = -1; 134651Svbart@nginx.com 1347208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1348208Svbart@nginx.com return; 134951Svbart@nginx.com 1350208Svbart@nginx.com not_found: 1351208Svbart@nginx.com 1352208Svbart@nginx.com resp.status = 404; 1353208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1354208Svbart@nginx.com resp.offset = -1; 1355208Svbart@nginx.com 1356208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1357208Svbart@nginx.com return; 1358208Svbart@nginx.com 1359208Svbart@nginx.com invalid_conf: 1360208Svbart@nginx.com 1361208Svbart@nginx.com resp.status = 400; 1362208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 1363208Svbart@nginx.com resp.offset = -1; 1364208Svbart@nginx.com 1365208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1366208Svbart@nginx.com return; 1367247Svbart@nginx.com 1368247Svbart@nginx.com alloc_fail: 1369247Svbart@nginx.com 1370247Svbart@nginx.com resp.status = 500; 1371247Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1372247Svbart@nginx.com resp.offset = -1; 1373247Svbart@nginx.com 1374247Svbart@nginx.com nxt_controller_response(task, req, &resp); 13751470Smax.romanov@nginx.com } 13761470Smax.romanov@nginx.com 1377247Svbart@nginx.com 13781470Smax.romanov@nginx.com static nxt_bool_t 13791470Smax.romanov@nginx.com nxt_controller_check_postpone_request(nxt_task_t *task) 13801470Smax.romanov@nginx.com { 13811470Smax.romanov@nginx.com nxt_port_t *router_port; 13821470Smax.romanov@nginx.com nxt_runtime_t *rt; 1383247Svbart@nginx.com 13841470Smax.romanov@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests) 13851470Smax.romanov@nginx.com || nxt_controller_waiting_init_conf 13861470Smax.romanov@nginx.com || !nxt_controller_router_ready) 13871470Smax.romanov@nginx.com { 13881470Smax.romanov@nginx.com return 1; 13891470Smax.romanov@nginx.com } 1390247Svbart@nginx.com 13911470Smax.romanov@nginx.com rt = task->thread->runtime; 13921470Smax.romanov@nginx.com 13931470Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 13941470Smax.romanov@nginx.com 13951470Smax.romanov@nginx.com return (router_port == NULL); 139627Svbart@nginx.com } 139727Svbart@nginx.com 139827Svbart@nginx.com 1399774Svbart@nginx.com #if (NXT_TLS) 1400774Svbart@nginx.com 1401774Svbart@nginx.com static void 1402774Svbart@nginx.com nxt_controller_process_cert(nxt_task_t *task, 1403774Svbart@nginx.com nxt_controller_request_t *req, nxt_str_t *path) 1404774Svbart@nginx.com { 1405774Svbart@nginx.com u_char *p; 1406774Svbart@nginx.com nxt_str_t name; 1407774Svbart@nginx.com nxt_int_t ret; 1408774Svbart@nginx.com nxt_conn_t *c; 1409774Svbart@nginx.com nxt_cert_t *cert; 1410774Svbart@nginx.com nxt_conf_value_t *value; 1411774Svbart@nginx.com nxt_controller_response_t resp; 1412774Svbart@nginx.com 1413774Svbart@nginx.com name.length = path->length - 1; 1414774Svbart@nginx.com name.start = path->start + 1; 1415774Svbart@nginx.com 1416774Svbart@nginx.com p = nxt_memchr(name.start, '/', name.length); 1417774Svbart@nginx.com 1418774Svbart@nginx.com if (p != NULL) { 1419774Svbart@nginx.com name.length = p - name.start; 1420774Svbart@nginx.com 1421774Svbart@nginx.com path->length -= p - path->start; 1422774Svbart@nginx.com path->start = p; 1423774Svbart@nginx.com 1424774Svbart@nginx.com } else { 1425774Svbart@nginx.com path = NULL; 1426774Svbart@nginx.com } 1427774Svbart@nginx.com 1428774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1429774Svbart@nginx.com 1430774Svbart@nginx.com c = req->conn; 1431774Svbart@nginx.com 1432774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 1433774Svbart@nginx.com 1434774Svbart@nginx.com if (name.length != 0) { 1435774Svbart@nginx.com value = nxt_cert_info_get(&name); 1436774Svbart@nginx.com if (value == NULL) { 1437774Svbart@nginx.com goto cert_not_found; 1438774Svbart@nginx.com } 1439774Svbart@nginx.com 1440774Svbart@nginx.com if (path != NULL) { 1441774Svbart@nginx.com value = nxt_conf_get_path(value, path); 1442774Svbart@nginx.com if (value == NULL) { 1443774Svbart@nginx.com goto not_found; 1444774Svbart@nginx.com } 1445774Svbart@nginx.com } 1446774Svbart@nginx.com 1447774Svbart@nginx.com } else { 1448774Svbart@nginx.com value = nxt_cert_info_get_all(c->mem_pool); 1449774Svbart@nginx.com if (value == NULL) { 1450774Svbart@nginx.com goto alloc_fail; 1451774Svbart@nginx.com } 1452774Svbart@nginx.com } 1453774Svbart@nginx.com 1454774Svbart@nginx.com resp.status = 200; 1455774Svbart@nginx.com resp.conf = value; 1456774Svbart@nginx.com 1457774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1458774Svbart@nginx.com return; 1459774Svbart@nginx.com } 1460774Svbart@nginx.com 1461774Svbart@nginx.com if (name.length == 0 || path != NULL) { 1462774Svbart@nginx.com goto invalid_name; 1463774Svbart@nginx.com } 1464774Svbart@nginx.com 1465774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 1466774Svbart@nginx.com value = nxt_cert_info_get(&name); 1467774Svbart@nginx.com if (value != NULL) { 1468774Svbart@nginx.com goto exists_cert; 1469774Svbart@nginx.com } 1470774Svbart@nginx.com 1471774Svbart@nginx.com cert = nxt_cert_mem(task, &c->read->mem); 1472774Svbart@nginx.com if (cert == NULL) { 1473774Svbart@nginx.com goto invalid_cert; 1474774Svbart@nginx.com } 1475774Svbart@nginx.com 1476774Svbart@nginx.com ret = nxt_cert_info_save(&name, cert); 1477774Svbart@nginx.com 1478774Svbart@nginx.com nxt_cert_destroy(cert); 1479774Svbart@nginx.com 1480774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1481774Svbart@nginx.com goto alloc_fail; 1482774Svbart@nginx.com } 1483774Svbart@nginx.com 1484774Svbart@nginx.com nxt_cert_store_get(task, &name, c->mem_pool, 1485774Svbart@nginx.com nxt_controller_process_cert_save, req); 1486774Svbart@nginx.com return; 1487774Svbart@nginx.com } 1488774Svbart@nginx.com 1489774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 1490774Svbart@nginx.com 1491774Svbart@nginx.com if (nxt_controller_cert_in_use(&name)) { 1492774Svbart@nginx.com goto cert_in_use; 1493774Svbart@nginx.com } 1494774Svbart@nginx.com 1495774Svbart@nginx.com if (nxt_cert_info_delete(&name) != NXT_OK) { 1496774Svbart@nginx.com goto cert_not_found; 1497774Svbart@nginx.com } 1498774Svbart@nginx.com 1499774Svbart@nginx.com nxt_cert_store_delete(task, &name, c->mem_pool); 1500774Svbart@nginx.com 1501774Svbart@nginx.com resp.status = 200; 1502774Svbart@nginx.com resp.title = (u_char *) "Certificate deleted."; 1503774Svbart@nginx.com 1504774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1505774Svbart@nginx.com return; 1506774Svbart@nginx.com } 1507774Svbart@nginx.com 1508774Svbart@nginx.com resp.status = 405; 1509774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 1510774Svbart@nginx.com resp.offset = -1; 1511774Svbart@nginx.com 1512774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1513774Svbart@nginx.com return; 1514774Svbart@nginx.com 1515774Svbart@nginx.com invalid_name: 1516774Svbart@nginx.com 1517774Svbart@nginx.com resp.status = 400; 1518774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate name."; 1519774Svbart@nginx.com resp.offset = -1; 1520774Svbart@nginx.com 1521774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1522774Svbart@nginx.com return; 1523774Svbart@nginx.com 1524774Svbart@nginx.com invalid_cert: 1525774Svbart@nginx.com 1526774Svbart@nginx.com resp.status = 400; 1527774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate."; 1528774Svbart@nginx.com resp.offset = -1; 1529774Svbart@nginx.com 1530774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1531774Svbart@nginx.com return; 1532774Svbart@nginx.com 1533774Svbart@nginx.com exists_cert: 1534774Svbart@nginx.com 1535774Svbart@nginx.com resp.status = 400; 1536774Svbart@nginx.com resp.title = (u_char *) "Certificate already exists."; 1537774Svbart@nginx.com resp.offset = -1; 1538774Svbart@nginx.com 1539774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1540774Svbart@nginx.com return; 1541774Svbart@nginx.com 1542774Svbart@nginx.com cert_in_use: 1543774Svbart@nginx.com 1544774Svbart@nginx.com resp.status = 400; 1545774Svbart@nginx.com resp.title = (u_char *) "Certificate is used in the configuration."; 1546774Svbart@nginx.com resp.offset = -1; 1547774Svbart@nginx.com 1548774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1549774Svbart@nginx.com return; 1550774Svbart@nginx.com 1551774Svbart@nginx.com cert_not_found: 1552774Svbart@nginx.com 1553774Svbart@nginx.com resp.status = 404; 1554774Svbart@nginx.com resp.title = (u_char *) "Certificate doesn't exist."; 1555774Svbart@nginx.com resp.offset = -1; 1556774Svbart@nginx.com 1557774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1558774Svbart@nginx.com return; 1559774Svbart@nginx.com 1560774Svbart@nginx.com not_found: 1561774Svbart@nginx.com 1562774Svbart@nginx.com resp.status = 404; 1563774Svbart@nginx.com resp.title = (u_char *) "Invalid path."; 1564774Svbart@nginx.com resp.offset = -1; 1565774Svbart@nginx.com 1566774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1567774Svbart@nginx.com return; 1568774Svbart@nginx.com 1569774Svbart@nginx.com alloc_fail: 1570774Svbart@nginx.com 1571774Svbart@nginx.com resp.status = 500; 1572774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1573774Svbart@nginx.com resp.offset = -1; 1574774Svbart@nginx.com 1575774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1576774Svbart@nginx.com return; 1577774Svbart@nginx.com } 1578774Svbart@nginx.com 1579774Svbart@nginx.com 1580774Svbart@nginx.com static void 1581774Svbart@nginx.com nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1582774Svbart@nginx.com void *data) 1583774Svbart@nginx.com { 1584774Svbart@nginx.com nxt_conn_t *c; 1585774Svbart@nginx.com nxt_buf_mem_t *mbuf; 1586774Svbart@nginx.com nxt_controller_request_t *req; 1587774Svbart@nginx.com nxt_controller_response_t resp; 1588774Svbart@nginx.com 1589774Svbart@nginx.com req = data; 1590774Svbart@nginx.com 1591774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1592774Svbart@nginx.com 1593774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 1594774Svbart@nginx.com resp.status = 500; 1595774Svbart@nginx.com resp.title = (u_char *) "Failed to store certificate."; 1596774Svbart@nginx.com 1597774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1598774Svbart@nginx.com return; 1599774Svbart@nginx.com } 1600774Svbart@nginx.com 1601774Svbart@nginx.com c = req->conn; 1602774Svbart@nginx.com 1603774Svbart@nginx.com mbuf = &c->read->mem; 1604774Svbart@nginx.com 16051558Smax.romanov@nginx.com nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf)); 16061558Smax.romanov@nginx.com 16071558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 1608774Svbart@nginx.com 1609774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1610774Svbart@nginx.com 1611774Svbart@nginx.com resp.status = 200; 1612774Svbart@nginx.com resp.title = (u_char *) "Certificate chain uploaded."; 1613774Svbart@nginx.com 1614774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1615774Svbart@nginx.com } 1616774Svbart@nginx.com 1617774Svbart@nginx.com 1618774Svbart@nginx.com static nxt_bool_t 1619774Svbart@nginx.com nxt_controller_cert_in_use(nxt_str_t *name) 1620774Svbart@nginx.com { 1621774Svbart@nginx.com uint32_t next; 1622774Svbart@nginx.com nxt_str_t str; 1623774Svbart@nginx.com nxt_conf_value_t *listeners, *listener, *value; 1624774Svbart@nginx.com 1625774Svbart@nginx.com static nxt_str_t listeners_path = nxt_string("/listeners"); 1626774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1627774Svbart@nginx.com 1628774Svbart@nginx.com listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path); 1629774Svbart@nginx.com 1630774Svbart@nginx.com if (listeners != NULL) { 1631774Svbart@nginx.com next = 0; 1632774Svbart@nginx.com 1633774Svbart@nginx.com for ( ;; ) { 1634774Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &str, &next); 1635774Svbart@nginx.com if (listener == NULL) { 1636774Svbart@nginx.com break; 1637774Svbart@nginx.com } 1638774Svbart@nginx.com 1639774Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 1640774Svbart@nginx.com if (value == NULL) { 1641774Svbart@nginx.com continue; 1642774Svbart@nginx.com } 1643774Svbart@nginx.com 1644774Svbart@nginx.com nxt_conf_get_string(value, &str); 1645774Svbart@nginx.com 1646774Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 1647774Svbart@nginx.com return 1; 1648774Svbart@nginx.com } 1649774Svbart@nginx.com } 1650774Svbart@nginx.com } 1651774Svbart@nginx.com 1652774Svbart@nginx.com return 0; 1653774Svbart@nginx.com } 1654774Svbart@nginx.com 1655774Svbart@nginx.com #endif 1656774Svbart@nginx.com 1657774Svbart@nginx.com 1658193Smax.romanov@nginx.com static void 1659193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1660193Smax.romanov@nginx.com void *data) 1661140Svbart@nginx.com { 1662140Svbart@nginx.com nxt_controller_request_t *req; 1663140Svbart@nginx.com nxt_controller_response_t resp; 1664140Svbart@nginx.com 1665238Svbart@nginx.com req = data; 1666238Svbart@nginx.com 1667201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 1668201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 1669140Svbart@nginx.com 1670238Svbart@nginx.com nxt_queue_remove(&req->link); 1671140Svbart@nginx.com 1672238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1673140Svbart@nginx.com 1674193Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 1675140Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 1676140Svbart@nginx.com 1677140Svbart@nginx.com nxt_controller_conf = req->conf; 1678140Svbart@nginx.com 1679314Svbart@nginx.com nxt_controller_conf_store(task, req->conf.root); 1680314Svbart@nginx.com 1681208Svbart@nginx.com resp.status = 200; 1682208Svbart@nginx.com resp.title = (u_char *) "Reconfiguration done."; 1683140Svbart@nginx.com 1684140Svbart@nginx.com } else { 1685140Svbart@nginx.com nxt_mp_destroy(req->conf.pool); 1686140Svbart@nginx.com 1687208Svbart@nginx.com resp.status = 500; 1688208Svbart@nginx.com resp.title = (u_char *) "Failed to apply new configuration."; 1689208Svbart@nginx.com resp.offset = -1; 1690140Svbart@nginx.com } 1691140Svbart@nginx.com 1692140Svbart@nginx.com nxt_controller_response(task, req, &resp); 1693140Svbart@nginx.com 16941469Smax.romanov@nginx.com nxt_controller_flush_requests(task); 1695121Svbart@nginx.com } 1696121Svbart@nginx.com 1697121Svbart@nginx.com 1698140Svbart@nginx.com static void 1699*1926Smax.romanov@nginx.com nxt_controller_process_control(nxt_task_t *task, 1700*1926Smax.romanov@nginx.com nxt_controller_request_t *req, nxt_str_t *path) 1701*1926Smax.romanov@nginx.com { 1702*1926Smax.romanov@nginx.com uint32_t stream; 1703*1926Smax.romanov@nginx.com nxt_buf_t *b; 1704*1926Smax.romanov@nginx.com nxt_int_t rc; 1705*1926Smax.romanov@nginx.com nxt_port_t *router_port, *controller_port; 1706*1926Smax.romanov@nginx.com nxt_runtime_t *rt; 1707*1926Smax.romanov@nginx.com nxt_conf_value_t *value; 1708*1926Smax.romanov@nginx.com nxt_controller_response_t resp; 1709*1926Smax.romanov@nginx.com 1710*1926Smax.romanov@nginx.com static nxt_str_t applications = nxt_string("applications"); 1711*1926Smax.romanov@nginx.com 1712*1926Smax.romanov@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1713*1926Smax.romanov@nginx.com 1714*1926Smax.romanov@nginx.com if (!nxt_str_eq(&req->parser.method, "GET", 3)) { 1715*1926Smax.romanov@nginx.com goto not_allowed; 1716*1926Smax.romanov@nginx.com } 1717*1926Smax.romanov@nginx.com 1718*1926Smax.romanov@nginx.com if (!nxt_str_start(path, "applications/", 13) 1719*1926Smax.romanov@nginx.com || nxt_memcmp(path->start + path->length - 8, "/restart", 8) != 0) 1720*1926Smax.romanov@nginx.com { 1721*1926Smax.romanov@nginx.com goto not_found; 1722*1926Smax.romanov@nginx.com } 1723*1926Smax.romanov@nginx.com 1724*1926Smax.romanov@nginx.com path->start += 13; 1725*1926Smax.romanov@nginx.com path->length -= 13 + 8; 1726*1926Smax.romanov@nginx.com 1727*1926Smax.romanov@nginx.com if (nxt_controller_check_postpone_request(task)) { 1728*1926Smax.romanov@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 1729*1926Smax.romanov@nginx.com return; 1730*1926Smax.romanov@nginx.com } 1731*1926Smax.romanov@nginx.com 1732*1926Smax.romanov@nginx.com value = nxt_controller_conf.root; 1733*1926Smax.romanov@nginx.com if (value == NULL) { 1734*1926Smax.romanov@nginx.com goto not_found; 1735*1926Smax.romanov@nginx.com } 1736*1926Smax.romanov@nginx.com 1737*1926Smax.romanov@nginx.com value = nxt_conf_get_object_member(value, &applications, NULL); 1738*1926Smax.romanov@nginx.com if (value == NULL) { 1739*1926Smax.romanov@nginx.com goto not_found; 1740*1926Smax.romanov@nginx.com } 1741*1926Smax.romanov@nginx.com 1742*1926Smax.romanov@nginx.com value = nxt_conf_get_object_member(value, path, NULL); 1743*1926Smax.romanov@nginx.com if (value == NULL) { 1744*1926Smax.romanov@nginx.com goto not_found; 1745*1926Smax.romanov@nginx.com } 1746*1926Smax.romanov@nginx.com 1747*1926Smax.romanov@nginx.com b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0); 1748*1926Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1749*1926Smax.romanov@nginx.com goto alloc_fail; 1750*1926Smax.romanov@nginx.com } 1751*1926Smax.romanov@nginx.com 1752*1926Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length); 1753*1926Smax.romanov@nginx.com 1754*1926Smax.romanov@nginx.com rt = task->thread->runtime; 1755*1926Smax.romanov@nginx.com 1756*1926Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 1757*1926Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1758*1926Smax.romanov@nginx.com 1759*1926Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, controller_port, 1760*1926Smax.romanov@nginx.com nxt_controller_app_restart_handler, 1761*1926Smax.romanov@nginx.com nxt_controller_app_restart_handler, 1762*1926Smax.romanov@nginx.com router_port->pid, req); 1763*1926Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 1764*1926Smax.romanov@nginx.com goto alloc_fail; 1765*1926Smax.romanov@nginx.com } 1766*1926Smax.romanov@nginx.com 1767*1926Smax.romanov@nginx.com rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART, 1768*1926Smax.romanov@nginx.com -1, stream, 0, b); 1769*1926Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1770*1926Smax.romanov@nginx.com nxt_port_rpc_cancel(task, controller_port, stream); 1771*1926Smax.romanov@nginx.com 1772*1926Smax.romanov@nginx.com goto fail; 1773*1926Smax.romanov@nginx.com } 1774*1926Smax.romanov@nginx.com 1775*1926Smax.romanov@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1776*1926Smax.romanov@nginx.com 1777*1926Smax.romanov@nginx.com return; 1778*1926Smax.romanov@nginx.com 1779*1926Smax.romanov@nginx.com not_allowed: 1780*1926Smax.romanov@nginx.com 1781*1926Smax.romanov@nginx.com resp.status = 405; 1782*1926Smax.romanov@nginx.com resp.title = (u_char *) "Method isn't allowed."; 1783*1926Smax.romanov@nginx.com resp.offset = -1; 1784*1926Smax.romanov@nginx.com 1785*1926Smax.romanov@nginx.com nxt_controller_response(task, req, &resp); 1786*1926Smax.romanov@nginx.com return; 1787*1926Smax.romanov@nginx.com 1788*1926Smax.romanov@nginx.com not_found: 1789*1926Smax.romanov@nginx.com 1790*1926Smax.romanov@nginx.com resp.status = 404; 1791*1926Smax.romanov@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1792*1926Smax.romanov@nginx.com resp.offset = -1; 1793*1926Smax.romanov@nginx.com 1794*1926Smax.romanov@nginx.com nxt_controller_response(task, req, &resp); 1795*1926Smax.romanov@nginx.com return; 1796*1926Smax.romanov@nginx.com 1797*1926Smax.romanov@nginx.com alloc_fail: 1798*1926Smax.romanov@nginx.com 1799*1926Smax.romanov@nginx.com resp.status = 500; 1800*1926Smax.romanov@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1801*1926Smax.romanov@nginx.com resp.offset = -1; 1802*1926Smax.romanov@nginx.com 1803*1926Smax.romanov@nginx.com nxt_controller_response(task, req, &resp); 1804*1926Smax.romanov@nginx.com return; 1805*1926Smax.romanov@nginx.com 1806*1926Smax.romanov@nginx.com fail: 1807*1926Smax.romanov@nginx.com 1808*1926Smax.romanov@nginx.com resp.status = 500; 1809*1926Smax.romanov@nginx.com resp.title = (u_char *) "Send restart failed."; 1810*1926Smax.romanov@nginx.com resp.offset = -1; 1811*1926Smax.romanov@nginx.com 1812*1926Smax.romanov@nginx.com nxt_controller_response(task, req, &resp); 1813*1926Smax.romanov@nginx.com } 1814*1926Smax.romanov@nginx.com 1815*1926Smax.romanov@nginx.com 1816*1926Smax.romanov@nginx.com static void 1817*1926Smax.romanov@nginx.com nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1818*1926Smax.romanov@nginx.com void *data) 1819*1926Smax.romanov@nginx.com { 1820*1926Smax.romanov@nginx.com nxt_controller_request_t *req; 1821*1926Smax.romanov@nginx.com nxt_controller_response_t resp; 1822*1926Smax.romanov@nginx.com 1823*1926Smax.romanov@nginx.com req = data; 1824*1926Smax.romanov@nginx.com 1825*1926Smax.romanov@nginx.com nxt_debug(task, "controller app restart handler"); 1826*1926Smax.romanov@nginx.com 1827*1926Smax.romanov@nginx.com nxt_queue_remove(&req->link); 1828*1926Smax.romanov@nginx.com 1829*1926Smax.romanov@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1830*1926Smax.romanov@nginx.com 1831*1926Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 1832*1926Smax.romanov@nginx.com resp.status = 200; 1833*1926Smax.romanov@nginx.com resp.title = (u_char *) "Ok"; 1834*1926Smax.romanov@nginx.com 1835*1926Smax.romanov@nginx.com } else { 1836*1926Smax.romanov@nginx.com resp.status = 500; 1837*1926Smax.romanov@nginx.com resp.title = (u_char *) "Failed to restart app."; 1838*1926Smax.romanov@nginx.com resp.offset = -1; 1839*1926Smax.romanov@nginx.com } 1840*1926Smax.romanov@nginx.com 1841*1926Smax.romanov@nginx.com nxt_controller_response(task, req, &resp); 1842*1926Smax.romanov@nginx.com 1843*1926Smax.romanov@nginx.com nxt_controller_flush_requests(task); 1844*1926Smax.romanov@nginx.com } 1845*1926Smax.romanov@nginx.com 1846*1926Smax.romanov@nginx.com 1847*1926Smax.romanov@nginx.com static void 1848314Svbart@nginx.com nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) 1849314Svbart@nginx.com { 18501787Smax.romanov@nginx.com void *mem; 18511787Smax.romanov@nginx.com u_char *end; 1852314Svbart@nginx.com size_t size; 18531787Smax.romanov@nginx.com nxt_fd_t fd; 1854314Svbart@nginx.com nxt_buf_t *b; 1855314Svbart@nginx.com nxt_port_t *main_port; 1856314Svbart@nginx.com nxt_runtime_t *rt; 1857314Svbart@nginx.com 1858314Svbart@nginx.com rt = task->thread->runtime; 1859314Svbart@nginx.com 1860314Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1861314Svbart@nginx.com 1862314Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 1863314Svbart@nginx.com 18641787Smax.romanov@nginx.com fd = nxt_shm_open(task, size); 18651787Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 18661787Smax.romanov@nginx.com return; 18671787Smax.romanov@nginx.com } 18681787Smax.romanov@nginx.com 18691787Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 18701787Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 18711787Smax.romanov@nginx.com goto fail; 1872314Svbart@nginx.com } 18731787Smax.romanov@nginx.com 18741787Smax.romanov@nginx.com end = nxt_conf_json_print(mem, conf, NULL); 18751787Smax.romanov@nginx.com 18761787Smax.romanov@nginx.com nxt_mem_munmap(mem, size); 18771787Smax.romanov@nginx.com 18781787Smax.romanov@nginx.com size = end - (u_char *) mem; 18791787Smax.romanov@nginx.com 18801787Smax.romanov@nginx.com b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0); 18811787Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 18821787Smax.romanov@nginx.com goto fail; 18831787Smax.romanov@nginx.com } 18841787Smax.romanov@nginx.com 18851787Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t)); 18861787Smax.romanov@nginx.com 18871787Smax.romanov@nginx.com (void) nxt_port_socket_write(task, main_port, 18881787Smax.romanov@nginx.com NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD, 18891787Smax.romanov@nginx.com fd, 0, -1, b); 18901787Smax.romanov@nginx.com 18911787Smax.romanov@nginx.com return; 18921787Smax.romanov@nginx.com 18931787Smax.romanov@nginx.com fail: 18941787Smax.romanov@nginx.com 18951787Smax.romanov@nginx.com nxt_fd_close(fd); 1896314Svbart@nginx.com } 1897314Svbart@nginx.com 1898314Svbart@nginx.com 1899314Svbart@nginx.com static void 1900140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, 190144Svbart@nginx.com nxt_controller_response_t *resp) 190233Svbart@nginx.com { 1903208Svbart@nginx.com size_t size; 1904208Svbart@nginx.com nxt_str_t status_line, str; 1905208Svbart@nginx.com nxt_buf_t *b, *body; 1906208Svbart@nginx.com nxt_conn_t *c; 1907208Svbart@nginx.com nxt_uint_t n; 1908208Svbart@nginx.com nxt_conf_value_t *value, *location; 1909208Svbart@nginx.com nxt_conf_json_pretty_t pretty; 1910208Svbart@nginx.com 1911208Svbart@nginx.com static nxt_str_t success_str = nxt_string("success"); 1912208Svbart@nginx.com static nxt_str_t error_str = nxt_string("error"); 1913208Svbart@nginx.com static nxt_str_t detail_str = nxt_string("detail"); 1914208Svbart@nginx.com static nxt_str_t location_str = nxt_string("location"); 1915208Svbart@nginx.com static nxt_str_t offset_str = nxt_string("offset"); 1916208Svbart@nginx.com static nxt_str_t line_str = nxt_string("line"); 1917208Svbart@nginx.com static nxt_str_t column_str = nxt_string("column"); 1918208Svbart@nginx.com 1919208Svbart@nginx.com static nxt_time_string_t date_cache = { 1920208Svbart@nginx.com (nxt_atomic_uint_t) -1, 1921208Svbart@nginx.com nxt_controller_date, 1922208Svbart@nginx.com "%s, %02d %s %4d %02d:%02d:%02d GMT", 1923703Svbart@nginx.com nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), 1924208Svbart@nginx.com NXT_THREAD_TIME_GMT, 1925208Svbart@nginx.com NXT_THREAD_TIME_SEC, 1926208Svbart@nginx.com }; 1927208Svbart@nginx.com 1928208Svbart@nginx.com switch (resp->status) { 1929208Svbart@nginx.com 1930208Svbart@nginx.com case 200: 1931208Svbart@nginx.com nxt_str_set(&status_line, "200 OK"); 1932208Svbart@nginx.com break; 1933208Svbart@nginx.com 1934208Svbart@nginx.com case 400: 1935208Svbart@nginx.com nxt_str_set(&status_line, "400 Bad Request"); 1936208Svbart@nginx.com break; 1937208Svbart@nginx.com 1938208Svbart@nginx.com case 404: 1939208Svbart@nginx.com nxt_str_set(&status_line, "404 Not Found"); 1940208Svbart@nginx.com break; 1941208Svbart@nginx.com 1942208Svbart@nginx.com case 405: 1943208Svbart@nginx.com nxt_str_set(&status_line, "405 Method Not Allowed"); 1944208Svbart@nginx.com break; 1945208Svbart@nginx.com 1946209Svbart@nginx.com default: 1947208Svbart@nginx.com nxt_str_set(&status_line, "500 Internal Server Error"); 1948208Svbart@nginx.com break; 1949208Svbart@nginx.com } 1950140Svbart@nginx.com 1951140Svbart@nginx.com c = req->conn; 1952208Svbart@nginx.com value = resp->conf; 195333Svbart@nginx.com 1954208Svbart@nginx.com if (value == NULL) { 1955208Svbart@nginx.com n = 1 1956357Svbart@nginx.com + (resp->detail.length != 0) 1957208Svbart@nginx.com + (resp->status >= 400 && resp->offset != -1); 1958208Svbart@nginx.com 1959208Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, n); 1960208Svbart@nginx.com 1961208Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1962208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1963208Svbart@nginx.com return; 1964208Svbart@nginx.com } 1965208Svbart@nginx.com 1966208Svbart@nginx.com str.length = nxt_strlen(resp->title); 1967208Svbart@nginx.com str.start = resp->title; 1968208Svbart@nginx.com 1969208Svbart@nginx.com if (resp->status < 400) { 1970208Svbart@nginx.com nxt_conf_set_member_string(value, &success_str, &str, 0); 1971208Svbart@nginx.com 1972208Svbart@nginx.com } else { 1973208Svbart@nginx.com nxt_conf_set_member_string(value, &error_str, &str, 0); 1974208Svbart@nginx.com } 1975208Svbart@nginx.com 1976208Svbart@nginx.com n = 0; 1977208Svbart@nginx.com 1978357Svbart@nginx.com if (resp->detail.length != 0) { 1979208Svbart@nginx.com n++; 1980208Svbart@nginx.com 1981357Svbart@nginx.com nxt_conf_set_member_string(value, &detail_str, &resp->detail, n); 1982208Svbart@nginx.com } 1983208Svbart@nginx.com 1984208Svbart@nginx.com if (resp->status >= 400 && resp->offset != -1) { 1985208Svbart@nginx.com n++; 1986208Svbart@nginx.com 1987208Svbart@nginx.com location = nxt_conf_create_object(c->mem_pool, 1988208Svbart@nginx.com resp->line != 0 ? 3 : 1); 1989208Svbart@nginx.com 1990208Svbart@nginx.com nxt_conf_set_member(value, &location_str, location, n); 1991208Svbart@nginx.com 1992208Svbart@nginx.com nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); 1993208Svbart@nginx.com 1994208Svbart@nginx.com if (resp->line != 0) { 1995208Svbart@nginx.com nxt_conf_set_member_integer(location, &line_str, 1996208Svbart@nginx.com resp->line, 1); 1997208Svbart@nginx.com 1998208Svbart@nginx.com nxt_conf_set_member_integer(location, &column_str, 1999208Svbart@nginx.com resp->column, 2); 2000208Svbart@nginx.com } 2001208Svbart@nginx.com } 2002208Svbart@nginx.com } 2003208Svbart@nginx.com 2004208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 2005208Svbart@nginx.com 2006208Svbart@nginx.com size = nxt_conf_json_length(value, &pretty) + 2; 2007208Svbart@nginx.com 2008208Svbart@nginx.com body = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2009208Svbart@nginx.com if (nxt_slow_path(body == NULL)) { 2010208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 2011208Svbart@nginx.com return; 2012208Svbart@nginx.com } 2013208Svbart@nginx.com 2014208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 2015208Svbart@nginx.com 2016208Svbart@nginx.com body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); 2017208Svbart@nginx.com 2018208Svbart@nginx.com body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); 2019208Svbart@nginx.com 2020703Svbart@nginx.com size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length 2021703Svbart@nginx.com + nxt_length("Server: " NXT_SERVER "\r\n") 2022703Svbart@nginx.com + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") 2023703Svbart@nginx.com + nxt_length("Content-Type: application/json\r\n") 2024703Svbart@nginx.com + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN 2025703Svbart@nginx.com + nxt_length("Connection: close\r\n") 2026703Svbart@nginx.com + nxt_length("\r\n"); 202733Svbart@nginx.com 202844Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 202933Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 2030140Svbart@nginx.com nxt_controller_conn_close(task, c, req); 2031140Svbart@nginx.com return; 203233Svbart@nginx.com } 203333Svbart@nginx.com 2034208Svbart@nginx.com b->next = body; 2035208Svbart@nginx.com 2036208Svbart@nginx.com nxt_str_set(&str, "HTTP/1.1 "); 203744Svbart@nginx.com 2038208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 2039208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, status_line.start, 2040208Svbart@nginx.com status_line.length); 2041208Svbart@nginx.com 2042208Svbart@nginx.com nxt_str_set(&str, "\r\n" 2043673Svbart@nginx.com "Server: " NXT_SERVER "\r\n" 2044208Svbart@nginx.com "Date: "); 2045208Svbart@nginx.com 2046208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 204744Svbart@nginx.com 2048208Svbart@nginx.com b->mem.free = nxt_thread_time_string(task->thread, &date_cache, 2049208Svbart@nginx.com b->mem.free); 2050208Svbart@nginx.com 2051208Svbart@nginx.com nxt_str_set(&str, "\r\n" 2052208Svbart@nginx.com "Content-Type: application/json\r\n" 2053208Svbart@nginx.com "Content-Length: "); 2054208Svbart@nginx.com 2055208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 205645Svbart@nginx.com 2057208Svbart@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", 2058208Svbart@nginx.com nxt_buf_mem_used_size(&body->mem)); 2059208Svbart@nginx.com 2060208Svbart@nginx.com nxt_str_set(&str, "\r\n" 2061208Svbart@nginx.com "Connection: close\r\n" 2062208Svbart@nginx.com "\r\n"); 2063208Svbart@nginx.com 2064208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 206533Svbart@nginx.com 206633Svbart@nginx.com c->write = b; 206744Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 206833Svbart@nginx.com 206962Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 207033Svbart@nginx.com } 207145Svbart@nginx.com 207245Svbart@nginx.com 2073208Svbart@nginx.com static u_char * 2074208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 2075208Svbart@nginx.com size_t size, const char *format) 207645Svbart@nginx.com { 2077208Svbart@nginx.com static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 2078208Svbart@nginx.com "Sat" }; 207945Svbart@nginx.com 2080208Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2081208Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 208245Svbart@nginx.com 2083208Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 2084208Svbart@nginx.com week[tm->tm_wday], tm->tm_mday, 2085208Svbart@nginx.com month[tm->tm_mon], tm->tm_year + 1900, 2086208Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec); 208745Svbart@nginx.com } 2088