1240Sigor@sysoev.ru 2240Sigor@sysoev.ru /* 3240Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4240Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5240Sigor@sysoev.ru */ 6240Sigor@sysoev.ru 7240Sigor@sysoev.ru #include <nxt_main.h> 8240Sigor@sysoev.ru #include <nxt_runtime.h> 9240Sigor@sysoev.ru #include <nxt_port.h> 10240Sigor@sysoev.ru #include <nxt_main_process.h> 11240Sigor@sysoev.ru #include <nxt_conf.h> 12240Sigor@sysoev.ru #include <nxt_application.h> 13240Sigor@sysoev.ru 14240Sigor@sysoev.ru 15240Sigor@sysoev.ru typedef struct { 16240Sigor@sysoev.ru nxt_socket_t socket; 17240Sigor@sysoev.ru nxt_socket_error_t error; 18240Sigor@sysoev.ru u_char *start; 19240Sigor@sysoev.ru u_char *end; 20240Sigor@sysoev.ru } nxt_listening_socket_t; 21240Sigor@sysoev.ru 22240Sigor@sysoev.ru 23240Sigor@sysoev.ru static nxt_int_t nxt_main_process_port_create(nxt_task_t *task, 24240Sigor@sysoev.ru nxt_runtime_t *rt); 25240Sigor@sysoev.ru static void nxt_main_process_title(nxt_task_t *task); 26240Sigor@sysoev.ru static nxt_int_t nxt_main_start_controller_process(nxt_task_t *task, 27240Sigor@sysoev.ru nxt_runtime_t *rt); 28368Svbart@nginx.com static nxt_int_t nxt_main_create_controller_process(nxt_task_t *task, 29368Svbart@nginx.com nxt_runtime_t *rt, nxt_process_init_t *init); 30240Sigor@sysoev.ru static nxt_int_t nxt_main_start_router_process(nxt_task_t *task, 31240Sigor@sysoev.ru nxt_runtime_t *rt); 32240Sigor@sysoev.ru static nxt_int_t nxt_main_start_discovery_process(nxt_task_t *task, 33240Sigor@sysoev.ru nxt_runtime_t *rt); 34240Sigor@sysoev.ru static nxt_int_t nxt_main_start_worker_process(nxt_task_t *task, 35240Sigor@sysoev.ru nxt_runtime_t *rt, nxt_common_app_conf_t *app_conf, uint32_t stream); 36240Sigor@sysoev.ru static nxt_int_t nxt_main_create_worker_process(nxt_task_t *task, 37240Sigor@sysoev.ru nxt_runtime_t *rt, nxt_process_init_t *init); 38240Sigor@sysoev.ru static void nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, 39240Sigor@sysoev.ru void *data); 40240Sigor@sysoev.ru static void nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, 41240Sigor@sysoev.ru void *data); 42240Sigor@sysoev.ru static void nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, 43240Sigor@sysoev.ru void *data); 44240Sigor@sysoev.ru static void nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, 45240Sigor@sysoev.ru void *data); 46240Sigor@sysoev.ru static void nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid); 47240Sigor@sysoev.ru static void nxt_main_port_socket_handler(nxt_task_t *task, 48240Sigor@sysoev.ru nxt_port_recv_msg_t *msg); 49240Sigor@sysoev.ru static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa, 50240Sigor@sysoev.ru nxt_listening_socket_t *ls); 51240Sigor@sysoev.ru static void nxt_main_port_modules_handler(nxt_task_t *task, 52240Sigor@sysoev.ru nxt_port_recv_msg_t *msg); 53240Sigor@sysoev.ru static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2); 54314Svbart@nginx.com static void nxt_main_port_conf_store_handler(nxt_task_t *task, 55314Svbart@nginx.com nxt_port_recv_msg_t *msg); 56240Sigor@sysoev.ru 57240Sigor@sysoev.ru 58240Sigor@sysoev.ru const nxt_sig_event_t nxt_main_process_signals[] = { 59240Sigor@sysoev.ru nxt_event_signal(SIGINT, nxt_main_process_sigterm_handler), 60240Sigor@sysoev.ru nxt_event_signal(SIGQUIT, nxt_main_process_sigquit_handler), 61240Sigor@sysoev.ru nxt_event_signal(SIGTERM, nxt_main_process_sigterm_handler), 62240Sigor@sysoev.ru nxt_event_signal(SIGCHLD, nxt_main_process_sigchld_handler), 63240Sigor@sysoev.ru nxt_event_signal(SIGUSR1, nxt_main_process_sigusr1_handler), 64240Sigor@sysoev.ru nxt_event_signal_end, 65240Sigor@sysoev.ru }; 66240Sigor@sysoev.ru 67240Sigor@sysoev.ru 68240Sigor@sysoev.ru static nxt_bool_t nxt_exiting; 69240Sigor@sysoev.ru 70240Sigor@sysoev.ru 71240Sigor@sysoev.ru nxt_int_t 72240Sigor@sysoev.ru nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task, 73240Sigor@sysoev.ru nxt_runtime_t *rt) 74240Sigor@sysoev.ru { 75240Sigor@sysoev.ru rt->types |= (1U << NXT_PROCESS_MAIN); 76240Sigor@sysoev.ru 77240Sigor@sysoev.ru if (nxt_main_process_port_create(task, rt) != NXT_OK) { 78240Sigor@sysoev.ru return NXT_ERROR; 79240Sigor@sysoev.ru } 80240Sigor@sysoev.ru 81240Sigor@sysoev.ru nxt_main_process_title(task); 82240Sigor@sysoev.ru 83240Sigor@sysoev.ru /* 84240Sigor@sysoev.ru * The dicsovery process will send a message processed by 85240Sigor@sysoev.ru * nxt_main_port_modules_handler() which starts the controller 86240Sigor@sysoev.ru * and router processes. 87240Sigor@sysoev.ru */ 88240Sigor@sysoev.ru return nxt_main_start_discovery_process(task, rt); 89240Sigor@sysoev.ru } 90240Sigor@sysoev.ru 91240Sigor@sysoev.ru 92240Sigor@sysoev.ru static nxt_conf_map_t nxt_common_app_conf[] = { 93240Sigor@sysoev.ru { 94240Sigor@sysoev.ru nxt_string("type"), 95240Sigor@sysoev.ru NXT_CONF_MAP_STR, 96240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, type), 97240Sigor@sysoev.ru }, 98240Sigor@sysoev.ru 99240Sigor@sysoev.ru { 100240Sigor@sysoev.ru nxt_string("user"), 101240Sigor@sysoev.ru NXT_CONF_MAP_STR, 102240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, user), 103240Sigor@sysoev.ru }, 104240Sigor@sysoev.ru 105240Sigor@sysoev.ru { 106240Sigor@sysoev.ru nxt_string("group"), 107240Sigor@sysoev.ru NXT_CONF_MAP_STR, 108240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, group), 109240Sigor@sysoev.ru }, 110240Sigor@sysoev.ru 111240Sigor@sysoev.ru { 112271Smax.romanov@nginx.com nxt_string("working_directory"), 113271Smax.romanov@nginx.com NXT_CONF_MAP_CSTRZ, 114271Smax.romanov@nginx.com offsetof(nxt_common_app_conf_t, working_directory), 115271Smax.romanov@nginx.com }, 116271Smax.romanov@nginx.com 117271Smax.romanov@nginx.com { 118240Sigor@sysoev.ru nxt_string("workers"), 119240Sigor@sysoev.ru NXT_CONF_MAP_INT32, 120240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, workers), 121240Sigor@sysoev.ru }, 122240Sigor@sysoev.ru 123240Sigor@sysoev.ru { 124*394Smax.romanov@nginx.com nxt_string("home"), 125*394Smax.romanov@nginx.com NXT_CONF_MAP_CSTRZ, 126*394Smax.romanov@nginx.com offsetof(nxt_common_app_conf_t, u.python.home), 127*394Smax.romanov@nginx.com }, 128*394Smax.romanov@nginx.com 129*394Smax.romanov@nginx.com { 130240Sigor@sysoev.ru nxt_string("path"), 131240Sigor@sysoev.ru NXT_CONF_MAP_STR, 132240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.python.path), 133240Sigor@sysoev.ru }, 134240Sigor@sysoev.ru 135240Sigor@sysoev.ru { 136240Sigor@sysoev.ru nxt_string("module"), 137240Sigor@sysoev.ru NXT_CONF_MAP_STR, 138240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.python.module), 139240Sigor@sysoev.ru }, 140240Sigor@sysoev.ru 141240Sigor@sysoev.ru { 142240Sigor@sysoev.ru nxt_string("root"), 143240Sigor@sysoev.ru NXT_CONF_MAP_STR, 144240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.root), 145240Sigor@sysoev.ru }, 146240Sigor@sysoev.ru 147240Sigor@sysoev.ru { 148240Sigor@sysoev.ru nxt_string("script"), 149240Sigor@sysoev.ru NXT_CONF_MAP_STR, 150240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.script), 151240Sigor@sysoev.ru }, 152240Sigor@sysoev.ru 153240Sigor@sysoev.ru { 154240Sigor@sysoev.ru nxt_string("index"), 155240Sigor@sysoev.ru NXT_CONF_MAP_STR, 156240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.index), 157240Sigor@sysoev.ru }, 158240Sigor@sysoev.ru 159240Sigor@sysoev.ru { 160240Sigor@sysoev.ru nxt_string("executable"), 161272Smax.romanov@nginx.com NXT_CONF_MAP_CSTRZ, 162240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.go.executable), 163240Sigor@sysoev.ru }, 164240Sigor@sysoev.ru }; 165240Sigor@sysoev.ru 166240Sigor@sysoev.ru 167240Sigor@sysoev.ru static void 168240Sigor@sysoev.ru nxt_port_main_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 169240Sigor@sysoev.ru { 170240Sigor@sysoev.ru nxt_debug(task, "main data: %*s", 171240Sigor@sysoev.ru nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 172240Sigor@sysoev.ru } 173240Sigor@sysoev.ru 174240Sigor@sysoev.ru 175240Sigor@sysoev.ru static void 176240Sigor@sysoev.ru nxt_port_main_start_worker_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 177240Sigor@sysoev.ru { 178240Sigor@sysoev.ru u_char *start; 179240Sigor@sysoev.ru nxt_mp_t *mp; 180240Sigor@sysoev.ru nxt_int_t ret; 181240Sigor@sysoev.ru nxt_buf_t *b; 182318Smax.romanov@nginx.com nxt_port_t *port; 183240Sigor@sysoev.ru nxt_conf_value_t *conf; 184240Sigor@sysoev.ru nxt_common_app_conf_t app_conf; 185240Sigor@sysoev.ru 186240Sigor@sysoev.ru static nxt_str_t nobody = nxt_string("nobody"); 187240Sigor@sysoev.ru 188318Smax.romanov@nginx.com ret = NXT_ERROR; 189318Smax.romanov@nginx.com 190352Smax.romanov@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 191352Smax.romanov@nginx.com 192352Smax.romanov@nginx.com if (nxt_slow_path(mp == NULL)) { 193352Smax.romanov@nginx.com return; 194352Smax.romanov@nginx.com } 195352Smax.romanov@nginx.com 196352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(mp, msg->buf, msg->size); 197352Smax.romanov@nginx.com 198352Smax.romanov@nginx.com if (b == NULL) { 199352Smax.romanov@nginx.com return; 200352Smax.romanov@nginx.com } 201240Sigor@sysoev.ru 202240Sigor@sysoev.ru nxt_debug(task, "main start worker: %*s", b->mem.free - b->mem.pos, 203240Sigor@sysoev.ru b->mem.pos); 204240Sigor@sysoev.ru 205240Sigor@sysoev.ru nxt_memzero(&app_conf, sizeof(nxt_common_app_conf_t)); 206240Sigor@sysoev.ru 207240Sigor@sysoev.ru start = b->mem.pos; 208240Sigor@sysoev.ru 209240Sigor@sysoev.ru app_conf.name.start = start; 210240Sigor@sysoev.ru app_conf.name.length = nxt_strlen(start); 211240Sigor@sysoev.ru 212240Sigor@sysoev.ru start += app_conf.name.length + 1; 213240Sigor@sysoev.ru 214240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, start, b->mem.free, NULL); 215240Sigor@sysoev.ru 216240Sigor@sysoev.ru if (conf == NULL) { 217240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 218318Smax.romanov@nginx.com 219318Smax.romanov@nginx.com goto failed; 220240Sigor@sysoev.ru } 221240Sigor@sysoev.ru 222240Sigor@sysoev.ru app_conf.user = nobody; 223240Sigor@sysoev.ru 224240Sigor@sysoev.ru ret = nxt_conf_map_object(mp, conf, nxt_common_app_conf, 225240Sigor@sysoev.ru nxt_nitems(nxt_common_app_conf), &app_conf); 226240Sigor@sysoev.ru if (ret != NXT_OK) { 227240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 228318Smax.romanov@nginx.com 229318Smax.romanov@nginx.com goto failed; 230240Sigor@sysoev.ru } 231240Sigor@sysoev.ru 232240Sigor@sysoev.ru ret = nxt_main_start_worker_process(task, task->thread->runtime, 233240Sigor@sysoev.ru &app_conf, msg->port_msg.stream); 234240Sigor@sysoev.ru 235318Smax.romanov@nginx.com failed: 236318Smax.romanov@nginx.com 237318Smax.romanov@nginx.com if (ret == NXT_ERROR) { 238318Smax.romanov@nginx.com port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 239318Smax.romanov@nginx.com msg->port_msg.reply_port); 240318Smax.romanov@nginx.com if (nxt_fast_path(port != NULL)) { 241318Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 242318Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 243318Smax.romanov@nginx.com } 244318Smax.romanov@nginx.com } 245318Smax.romanov@nginx.com 246240Sigor@sysoev.ru nxt_mp_destroy(mp); 247240Sigor@sysoev.ru } 248240Sigor@sysoev.ru 249240Sigor@sysoev.ru 250320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_main_process_port_handlers = { 251320Smax.romanov@nginx.com .data = nxt_port_main_data_handler, 252320Smax.romanov@nginx.com .process_ready = nxt_port_process_ready_handler, 253320Smax.romanov@nginx.com .start_worker = nxt_port_main_start_worker_handler, 254320Smax.romanov@nginx.com .socket = nxt_main_port_socket_handler, 255320Smax.romanov@nginx.com .modules = nxt_main_port_modules_handler, 256320Smax.romanov@nginx.com .conf_store = nxt_main_port_conf_store_handler, 257320Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 258320Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 259240Sigor@sysoev.ru }; 260240Sigor@sysoev.ru 261240Sigor@sysoev.ru 262240Sigor@sysoev.ru static nxt_int_t 263240Sigor@sysoev.ru nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt) 264240Sigor@sysoev.ru { 265240Sigor@sysoev.ru nxt_int_t ret; 266240Sigor@sysoev.ru nxt_port_t *port; 267240Sigor@sysoev.ru nxt_process_t *process; 268240Sigor@sysoev.ru 269240Sigor@sysoev.ru process = nxt_runtime_process_get(rt, nxt_pid); 270240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 271240Sigor@sysoev.ru return NXT_ERROR; 272240Sigor@sysoev.ru } 273240Sigor@sysoev.ru 274240Sigor@sysoev.ru port = nxt_port_new(task, 0, nxt_pid, NXT_PROCESS_MAIN); 275240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 276349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 277240Sigor@sysoev.ru return NXT_ERROR; 278240Sigor@sysoev.ru } 279240Sigor@sysoev.ru 280343Smax.romanov@nginx.com nxt_process_port_add(task, process, port); 281343Smax.romanov@nginx.com 282349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 283349Smax.romanov@nginx.com 284240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 285240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 286343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 287240Sigor@sysoev.ru return ret; 288240Sigor@sysoev.ru } 289240Sigor@sysoev.ru 290343Smax.romanov@nginx.com nxt_runtime_port_add(task, port); 291240Sigor@sysoev.ru 292343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 293240Sigor@sysoev.ru 294240Sigor@sysoev.ru /* 295240Sigor@sysoev.ru * A main process port. A write port is not closed 296240Sigor@sysoev.ru * since it should be inherited by worker processes. 297240Sigor@sysoev.ru */ 298320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_main_process_port_handlers); 299240Sigor@sysoev.ru 300240Sigor@sysoev.ru process->ready = 1; 301240Sigor@sysoev.ru 302240Sigor@sysoev.ru return NXT_OK; 303240Sigor@sysoev.ru } 304240Sigor@sysoev.ru 305240Sigor@sysoev.ru 306240Sigor@sysoev.ru static void 307240Sigor@sysoev.ru nxt_main_process_title(nxt_task_t *task) 308240Sigor@sysoev.ru { 309240Sigor@sysoev.ru u_char *p, *end; 310240Sigor@sysoev.ru nxt_uint_t i; 311240Sigor@sysoev.ru u_char title[2048]; 312240Sigor@sysoev.ru 313240Sigor@sysoev.ru end = title + sizeof(title) - 1; 314240Sigor@sysoev.ru 315259Sigor@sysoev.ru p = nxt_sprintf(title, end, "unit: main [%s", nxt_process_argv[0]); 316240Sigor@sysoev.ru 317240Sigor@sysoev.ru for (i = 1; nxt_process_argv[i] != NULL; i++) { 318240Sigor@sysoev.ru p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]); 319240Sigor@sysoev.ru } 320240Sigor@sysoev.ru 321240Sigor@sysoev.ru if (p < end) { 322240Sigor@sysoev.ru *p++ = ']'; 323240Sigor@sysoev.ru } 324240Sigor@sysoev.ru 325240Sigor@sysoev.ru *p = '\0'; 326240Sigor@sysoev.ru 327240Sigor@sysoev.ru nxt_process_title(task, "%s", title); 328240Sigor@sysoev.ru } 329240Sigor@sysoev.ru 330240Sigor@sysoev.ru 331240Sigor@sysoev.ru static nxt_int_t 332240Sigor@sysoev.ru nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt) 333240Sigor@sysoev.ru { 334240Sigor@sysoev.ru nxt_process_init_t *init; 335240Sigor@sysoev.ru 336368Svbart@nginx.com init = nxt_malloc(sizeof(nxt_process_init_t)); 337368Svbart@nginx.com if (nxt_slow_path(init == NULL)) { 338368Svbart@nginx.com return NXT_ERROR; 339368Svbart@nginx.com } 340368Svbart@nginx.com 341368Svbart@nginx.com init->start = nxt_controller_start; 342368Svbart@nginx.com init->name = "controller"; 343368Svbart@nginx.com init->user_cred = &rt->user_cred; 344368Svbart@nginx.com init->port_handlers = &nxt_controller_process_port_handlers; 345368Svbart@nginx.com init->signals = nxt_worker_process_signals; 346368Svbart@nginx.com init->type = NXT_PROCESS_CONTROLLER; 347368Svbart@nginx.com init->stream = 0; 348368Svbart@nginx.com init->restart = &nxt_main_create_controller_process; 349368Svbart@nginx.com 350368Svbart@nginx.com return nxt_main_create_controller_process(task, rt, init);; 351368Svbart@nginx.com } 352368Svbart@nginx.com 353368Svbart@nginx.com 354368Svbart@nginx.com static nxt_int_t 355368Svbart@nginx.com nxt_main_create_controller_process(nxt_task_t *task, nxt_runtime_t *rt, 356368Svbart@nginx.com nxt_process_init_t *init) 357368Svbart@nginx.com { 358368Svbart@nginx.com ssize_t n; 359368Svbart@nginx.com nxt_int_t ret; 360368Svbart@nginx.com nxt_str_t conf; 361368Svbart@nginx.com nxt_file_t file; 362368Svbart@nginx.com nxt_file_info_t fi; 363368Svbart@nginx.com 364314Svbart@nginx.com conf.length = 0; 365314Svbart@nginx.com 366314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 367314Svbart@nginx.com 368314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf; 369314Svbart@nginx.com 370329Sigor@sysoev.ru ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 371314Svbart@nginx.com 372329Sigor@sysoev.ru if (ret == NXT_OK) { 373329Sigor@sysoev.ru ret = nxt_file_info(&file, &fi); 374329Sigor@sysoev.ru 375329Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) { 376314Svbart@nginx.com conf.length = nxt_file_size(&fi); 377314Svbart@nginx.com conf.start = nxt_malloc(conf.length); 378314Svbart@nginx.com 379314Svbart@nginx.com if (nxt_slow_path(conf.start == NULL)) { 380314Svbart@nginx.com nxt_file_close(task, &file); 381314Svbart@nginx.com return NXT_ERROR; 382314Svbart@nginx.com } 383314Svbart@nginx.com 384314Svbart@nginx.com n = nxt_file_read(&file, conf.start, conf.length, 0); 385314Svbart@nginx.com 386314Svbart@nginx.com if (nxt_slow_path(n != (ssize_t) conf.length)) { 387314Svbart@nginx.com conf.length = 0; 388314Svbart@nginx.com nxt_free(conf.start); 389314Svbart@nginx.com 390314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, 391314Svbart@nginx.com "failed to restore previous configuration: " 392314Svbart@nginx.com "cannot read the file"); 393314Svbart@nginx.com } 394314Svbart@nginx.com } 395314Svbart@nginx.com 396314Svbart@nginx.com nxt_file_close(task, &file); 397314Svbart@nginx.com } 398314Svbart@nginx.com 399314Svbart@nginx.com init->data = &conf; 400240Sigor@sysoev.ru 401314Svbart@nginx.com ret = nxt_main_create_worker_process(task, rt, init); 402314Svbart@nginx.com 403314Svbart@nginx.com if (ret == NXT_OK && conf.length != 0) { 404314Svbart@nginx.com nxt_free(conf.start); 405314Svbart@nginx.com } 406314Svbart@nginx.com 407314Svbart@nginx.com return ret; 408240Sigor@sysoev.ru } 409240Sigor@sysoev.ru 410240Sigor@sysoev.ru 411240Sigor@sysoev.ru static nxt_int_t 412240Sigor@sysoev.ru nxt_main_start_discovery_process(nxt_task_t *task, nxt_runtime_t *rt) 413240Sigor@sysoev.ru { 414240Sigor@sysoev.ru nxt_process_init_t *init; 415240Sigor@sysoev.ru 416240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 417240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 418240Sigor@sysoev.ru return NXT_ERROR; 419240Sigor@sysoev.ru } 420240Sigor@sysoev.ru 421240Sigor@sysoev.ru init->start = nxt_discovery_start; 422240Sigor@sysoev.ru init->name = "discovery"; 423240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 424320Smax.romanov@nginx.com init->port_handlers = &nxt_discovery_process_port_handlers; 425240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 426240Sigor@sysoev.ru init->type = NXT_PROCESS_DISCOVERY; 427240Sigor@sysoev.ru init->data = rt; 428240Sigor@sysoev.ru init->stream = 0; 429368Svbart@nginx.com init->restart = NULL; 430240Sigor@sysoev.ru 431240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 432240Sigor@sysoev.ru } 433240Sigor@sysoev.ru 434240Sigor@sysoev.ru 435240Sigor@sysoev.ru static nxt_int_t 436240Sigor@sysoev.ru nxt_main_start_router_process(nxt_task_t *task, nxt_runtime_t *rt) 437240Sigor@sysoev.ru { 438240Sigor@sysoev.ru nxt_process_init_t *init; 439240Sigor@sysoev.ru 440240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 441240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 442240Sigor@sysoev.ru return NXT_ERROR; 443240Sigor@sysoev.ru } 444240Sigor@sysoev.ru 445240Sigor@sysoev.ru init->start = nxt_router_start; 446240Sigor@sysoev.ru init->name = "router"; 447240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 448320Smax.romanov@nginx.com init->port_handlers = &nxt_router_process_port_handlers; 449240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 450240Sigor@sysoev.ru init->type = NXT_PROCESS_ROUTER; 451240Sigor@sysoev.ru init->data = rt; 452240Sigor@sysoev.ru init->stream = 0; 453368Svbart@nginx.com init->restart = &nxt_main_create_worker_process; 454240Sigor@sysoev.ru 455240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 456240Sigor@sysoev.ru } 457240Sigor@sysoev.ru 458240Sigor@sysoev.ru 459240Sigor@sysoev.ru static nxt_int_t 460240Sigor@sysoev.ru nxt_main_start_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 461240Sigor@sysoev.ru nxt_common_app_conf_t *app_conf, uint32_t stream) 462240Sigor@sysoev.ru { 463240Sigor@sysoev.ru char *user, *group; 464240Sigor@sysoev.ru u_char *title, *last, *end; 465240Sigor@sysoev.ru size_t size; 466240Sigor@sysoev.ru nxt_process_init_t *init; 467240Sigor@sysoev.ru 468240Sigor@sysoev.ru size = sizeof(nxt_process_init_t) 469240Sigor@sysoev.ru + sizeof(nxt_user_cred_t) 470240Sigor@sysoev.ru + app_conf->user.length + 1 471240Sigor@sysoev.ru + app_conf->group.length + 1 472240Sigor@sysoev.ru + app_conf->name.length + sizeof("\"\" application"); 473240Sigor@sysoev.ru 474240Sigor@sysoev.ru init = nxt_malloc(size); 475240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 476240Sigor@sysoev.ru return NXT_ERROR; 477240Sigor@sysoev.ru } 478240Sigor@sysoev.ru 479240Sigor@sysoev.ru init->user_cred = nxt_pointer_to(init, sizeof(nxt_process_init_t)); 480240Sigor@sysoev.ru user = nxt_pointer_to(init->user_cred, sizeof(nxt_user_cred_t)); 481240Sigor@sysoev.ru 482240Sigor@sysoev.ru nxt_memcpy(user, app_conf->user.start, app_conf->user.length); 483240Sigor@sysoev.ru last = nxt_pointer_to(user, app_conf->user.length); 484240Sigor@sysoev.ru *last++ = '\0'; 485240Sigor@sysoev.ru 486240Sigor@sysoev.ru init->user_cred->user = user; 487240Sigor@sysoev.ru 488240Sigor@sysoev.ru if (app_conf->group.start != NULL) { 489240Sigor@sysoev.ru group = (char *) last; 490240Sigor@sysoev.ru 491240Sigor@sysoev.ru nxt_memcpy(group, app_conf->group.start, app_conf->group.length); 492240Sigor@sysoev.ru last = nxt_pointer_to(group, app_conf->group.length); 493240Sigor@sysoev.ru *last++ = '\0'; 494240Sigor@sysoev.ru 495240Sigor@sysoev.ru } else { 496240Sigor@sysoev.ru group = NULL; 497240Sigor@sysoev.ru } 498240Sigor@sysoev.ru 499240Sigor@sysoev.ru if (nxt_user_cred_get(task, init->user_cred, group) != NXT_OK) { 500240Sigor@sysoev.ru return NXT_ERROR; 501240Sigor@sysoev.ru } 502240Sigor@sysoev.ru 503240Sigor@sysoev.ru title = last; 504240Sigor@sysoev.ru end = title + app_conf->name.length + sizeof("\"\" application"); 505240Sigor@sysoev.ru 506240Sigor@sysoev.ru nxt_sprintf(title, end, "\"%V\" application%Z", &app_conf->name); 507240Sigor@sysoev.ru 508240Sigor@sysoev.ru init->start = nxt_app_start; 509240Sigor@sysoev.ru init->name = (char *) title; 510320Smax.romanov@nginx.com init->port_handlers = &nxt_app_process_port_handlers; 511240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 512240Sigor@sysoev.ru init->type = NXT_PROCESS_WORKER; 513240Sigor@sysoev.ru init->data = app_conf; 514240Sigor@sysoev.ru init->stream = stream; 515368Svbart@nginx.com init->restart = NULL; 516240Sigor@sysoev.ru 517240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 518240Sigor@sysoev.ru } 519240Sigor@sysoev.ru 520240Sigor@sysoev.ru 521240Sigor@sysoev.ru static nxt_int_t 522240Sigor@sysoev.ru nxt_main_create_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 523240Sigor@sysoev.ru nxt_process_init_t *init) 524240Sigor@sysoev.ru { 525240Sigor@sysoev.ru nxt_int_t ret; 526240Sigor@sysoev.ru nxt_pid_t pid; 527240Sigor@sysoev.ru nxt_port_t *port; 528240Sigor@sysoev.ru nxt_process_t *process; 529240Sigor@sysoev.ru 530240Sigor@sysoev.ru /* 531240Sigor@sysoev.ru * TODO: remove process, init, ports from array on memory and fork failures. 532240Sigor@sysoev.ru */ 533240Sigor@sysoev.ru 534240Sigor@sysoev.ru process = nxt_runtime_process_new(rt); 535240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 536240Sigor@sysoev.ru return NXT_ERROR; 537240Sigor@sysoev.ru } 538240Sigor@sysoev.ru 539240Sigor@sysoev.ru process->init = init; 540240Sigor@sysoev.ru 541240Sigor@sysoev.ru port = nxt_port_new(task, 0, 0, init->type); 542240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 543349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 544240Sigor@sysoev.ru return NXT_ERROR; 545240Sigor@sysoev.ru } 546240Sigor@sysoev.ru 547240Sigor@sysoev.ru nxt_process_port_add(task, process, port); 548240Sigor@sysoev.ru 549349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 550349Smax.romanov@nginx.com 551240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 552240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 553343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 554240Sigor@sysoev.ru return ret; 555240Sigor@sysoev.ru } 556240Sigor@sysoev.ru 557240Sigor@sysoev.ru pid = nxt_process_create(task, process); 558240Sigor@sysoev.ru 559343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 560343Smax.romanov@nginx.com 561240Sigor@sysoev.ru switch (pid) { 562240Sigor@sysoev.ru 563240Sigor@sysoev.ru case -1: 564240Sigor@sysoev.ru return NXT_ERROR; 565240Sigor@sysoev.ru 566240Sigor@sysoev.ru case 0: 567240Sigor@sysoev.ru /* A worker process, return to the event engine work queue loop. */ 568240Sigor@sysoev.ru return NXT_AGAIN; 569240Sigor@sysoev.ru 570240Sigor@sysoev.ru default: 571240Sigor@sysoev.ru /* The main process created a new process. */ 572240Sigor@sysoev.ru 573240Sigor@sysoev.ru nxt_port_read_close(port); 574240Sigor@sysoev.ru nxt_port_write_enable(task, port); 575240Sigor@sysoev.ru 576240Sigor@sysoev.ru return NXT_OK; 577240Sigor@sysoev.ru } 578240Sigor@sysoev.ru } 579240Sigor@sysoev.ru 580240Sigor@sysoev.ru 581240Sigor@sysoev.ru void 582240Sigor@sysoev.ru nxt_main_stop_worker_processes(nxt_task_t *task, nxt_runtime_t *rt) 583240Sigor@sysoev.ru { 584240Sigor@sysoev.ru nxt_port_t *port; 585240Sigor@sysoev.ru nxt_process_t *process; 586240Sigor@sysoev.ru 587277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 588277Sigor@sysoev.ru 589240Sigor@sysoev.ru if (nxt_pid != process->pid) { 590240Sigor@sysoev.ru process->init = NULL; 591240Sigor@sysoev.ru 592240Sigor@sysoev.ru nxt_process_port_each(process, port) { 593240Sigor@sysoev.ru 594240Sigor@sysoev.ru (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 595240Sigor@sysoev.ru -1, 0, 0, NULL); 596240Sigor@sysoev.ru 597240Sigor@sysoev.ru } nxt_process_port_loop; 598240Sigor@sysoev.ru } 599277Sigor@sysoev.ru 600277Sigor@sysoev.ru } nxt_runtime_process_loop; 601240Sigor@sysoev.ru } 602240Sigor@sysoev.ru 603240Sigor@sysoev.ru 604240Sigor@sysoev.ru 605240Sigor@sysoev.ru static void 606240Sigor@sysoev.ru nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data) 607240Sigor@sysoev.ru { 608240Sigor@sysoev.ru nxt_debug(task, "sigterm handler signo:%d (%s)", 609240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 610240Sigor@sysoev.ru 611240Sigor@sysoev.ru /* TODO: fast exit. */ 612240Sigor@sysoev.ru 613240Sigor@sysoev.ru nxt_exiting = 1; 614240Sigor@sysoev.ru 615240Sigor@sysoev.ru nxt_runtime_quit(task); 616240Sigor@sysoev.ru } 617240Sigor@sysoev.ru 618240Sigor@sysoev.ru 619240Sigor@sysoev.ru static void 620240Sigor@sysoev.ru nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data) 621240Sigor@sysoev.ru { 622240Sigor@sysoev.ru nxt_debug(task, "sigquit handler signo:%d (%s)", 623240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 624240Sigor@sysoev.ru 625240Sigor@sysoev.ru /* TODO: graceful exit. */ 626240Sigor@sysoev.ru 627240Sigor@sysoev.ru nxt_exiting = 1; 628240Sigor@sysoev.ru 629240Sigor@sysoev.ru nxt_runtime_quit(task); 630240Sigor@sysoev.ru } 631240Sigor@sysoev.ru 632240Sigor@sysoev.ru 633240Sigor@sysoev.ru static void 634240Sigor@sysoev.ru nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data) 635240Sigor@sysoev.ru { 636240Sigor@sysoev.ru nxt_mp_t *mp; 637240Sigor@sysoev.ru nxt_int_t ret; 638240Sigor@sysoev.ru nxt_uint_t n; 639240Sigor@sysoev.ru nxt_file_t *file, *new_file; 640240Sigor@sysoev.ru nxt_runtime_t *rt; 641240Sigor@sysoev.ru nxt_array_t *new_files; 642240Sigor@sysoev.ru 643240Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s", 644240Sigor@sysoev.ru (int) (uintptr_t) obj, data, "log files rotation"); 645240Sigor@sysoev.ru 646240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 647240Sigor@sysoev.ru if (mp == NULL) { 648240Sigor@sysoev.ru return; 649240Sigor@sysoev.ru } 650240Sigor@sysoev.ru 651240Sigor@sysoev.ru rt = task->thread->runtime; 652240Sigor@sysoev.ru 653240Sigor@sysoev.ru n = nxt_list_nelts(rt->log_files); 654240Sigor@sysoev.ru 655240Sigor@sysoev.ru new_files = nxt_array_create(mp, n, sizeof(nxt_file_t)); 656240Sigor@sysoev.ru if (new_files == NULL) { 657240Sigor@sysoev.ru nxt_mp_destroy(mp); 658240Sigor@sysoev.ru return; 659240Sigor@sysoev.ru } 660240Sigor@sysoev.ru 661240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 662240Sigor@sysoev.ru 663240Sigor@sysoev.ru /* This allocation cannot fail. */ 664240Sigor@sysoev.ru new_file = nxt_array_add(new_files); 665240Sigor@sysoev.ru 666240Sigor@sysoev.ru new_file->name = file->name; 667240Sigor@sysoev.ru new_file->fd = NXT_FILE_INVALID; 668240Sigor@sysoev.ru new_file->log_level = NXT_LOG_CRIT; 669240Sigor@sysoev.ru 670240Sigor@sysoev.ru ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT, 671240Sigor@sysoev.ru NXT_FILE_OWNER_ACCESS); 672240Sigor@sysoev.ru 673240Sigor@sysoev.ru if (ret != NXT_OK) { 674240Sigor@sysoev.ru goto fail; 675240Sigor@sysoev.ru } 676240Sigor@sysoev.ru 677240Sigor@sysoev.ru } nxt_list_loop; 678240Sigor@sysoev.ru 679240Sigor@sysoev.ru new_file = new_files->elts; 680240Sigor@sysoev.ru 681240Sigor@sysoev.ru ret = nxt_file_stderr(&new_file[0]); 682240Sigor@sysoev.ru 683240Sigor@sysoev.ru if (ret == NXT_OK) { 684240Sigor@sysoev.ru n = 0; 685240Sigor@sysoev.ru 686240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 687240Sigor@sysoev.ru 688240Sigor@sysoev.ru nxt_port_change_log_file(task, rt, n, new_file[n].fd); 689240Sigor@sysoev.ru /* 690240Sigor@sysoev.ru * The old log file descriptor must be closed at the moment 691240Sigor@sysoev.ru * when no other threads use it. dup2() allows to use the 692240Sigor@sysoev.ru * old file descriptor for new log file. This change is 693240Sigor@sysoev.ru * performed atomically in the kernel. 694240Sigor@sysoev.ru */ 695240Sigor@sysoev.ru (void) nxt_file_redirect(file, new_file[n].fd); 696240Sigor@sysoev.ru 697240Sigor@sysoev.ru n++; 698240Sigor@sysoev.ru 699240Sigor@sysoev.ru } nxt_list_loop; 700240Sigor@sysoev.ru 701240Sigor@sysoev.ru nxt_mp_destroy(mp); 702240Sigor@sysoev.ru return; 703240Sigor@sysoev.ru } 704240Sigor@sysoev.ru 705240Sigor@sysoev.ru fail: 706240Sigor@sysoev.ru 707240Sigor@sysoev.ru new_file = new_files->elts; 708240Sigor@sysoev.ru n = new_files->nelts; 709240Sigor@sysoev.ru 710240Sigor@sysoev.ru while (n != 0) { 711240Sigor@sysoev.ru if (new_file->fd != NXT_FILE_INVALID) { 712240Sigor@sysoev.ru nxt_file_close(task, new_file); 713240Sigor@sysoev.ru } 714240Sigor@sysoev.ru 715240Sigor@sysoev.ru new_file++; 716240Sigor@sysoev.ru n--; 717240Sigor@sysoev.ru } 718240Sigor@sysoev.ru 719240Sigor@sysoev.ru nxt_mp_destroy(mp); 720240Sigor@sysoev.ru } 721240Sigor@sysoev.ru 722240Sigor@sysoev.ru 723240Sigor@sysoev.ru static void 724240Sigor@sysoev.ru nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data) 725240Sigor@sysoev.ru { 726240Sigor@sysoev.ru int status; 727240Sigor@sysoev.ru nxt_err_t err; 728240Sigor@sysoev.ru nxt_pid_t pid; 729240Sigor@sysoev.ru 730240Sigor@sysoev.ru nxt_debug(task, "sigchld handler signo:%d (%s)", 731240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 732240Sigor@sysoev.ru 733240Sigor@sysoev.ru for ( ;; ) { 734240Sigor@sysoev.ru pid = waitpid(-1, &status, WNOHANG); 735240Sigor@sysoev.ru 736240Sigor@sysoev.ru if (pid == -1) { 737240Sigor@sysoev.ru 738240Sigor@sysoev.ru switch (err = nxt_errno) { 739240Sigor@sysoev.ru 740240Sigor@sysoev.ru case NXT_ECHILD: 741240Sigor@sysoev.ru return; 742240Sigor@sysoev.ru 743240Sigor@sysoev.ru case NXT_EINTR: 744240Sigor@sysoev.ru continue; 745240Sigor@sysoev.ru 746240Sigor@sysoev.ru default: 747240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "waitpid() failed: %E", err); 748240Sigor@sysoev.ru return; 749240Sigor@sysoev.ru } 750240Sigor@sysoev.ru } 751240Sigor@sysoev.ru 752240Sigor@sysoev.ru nxt_debug(task, "waitpid(): %PI", pid); 753240Sigor@sysoev.ru 754240Sigor@sysoev.ru if (pid == 0) { 755240Sigor@sysoev.ru return; 756240Sigor@sysoev.ru } 757240Sigor@sysoev.ru 758240Sigor@sysoev.ru if (WTERMSIG(status)) { 759240Sigor@sysoev.ru #ifdef WCOREDUMP 760240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d%s", 761240Sigor@sysoev.ru pid, WTERMSIG(status), 762240Sigor@sysoev.ru WCOREDUMP(status) ? " (core dumped)" : ""); 763240Sigor@sysoev.ru #else 764240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d", 765240Sigor@sysoev.ru pid, WTERMSIG(status)); 766240Sigor@sysoev.ru #endif 767240Sigor@sysoev.ru 768240Sigor@sysoev.ru } else { 769240Sigor@sysoev.ru nxt_trace(task, "process %PI exited with code %d", 770240Sigor@sysoev.ru pid, WEXITSTATUS(status)); 771240Sigor@sysoev.ru } 772240Sigor@sysoev.ru 773240Sigor@sysoev.ru nxt_main_cleanup_worker_process(task, pid); 774240Sigor@sysoev.ru } 775240Sigor@sysoev.ru } 776240Sigor@sysoev.ru 777240Sigor@sysoev.ru 778240Sigor@sysoev.ru static void 779240Sigor@sysoev.ru nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid) 780240Sigor@sysoev.ru { 781240Sigor@sysoev.ru nxt_buf_t *buf; 782240Sigor@sysoev.ru nxt_port_t *port; 783240Sigor@sysoev.ru nxt_runtime_t *rt; 784240Sigor@sysoev.ru nxt_process_t *process; 785366Smax.romanov@nginx.com nxt_process_type_t ptype; 786240Sigor@sysoev.ru nxt_process_init_t *init; 787240Sigor@sysoev.ru 788240Sigor@sysoev.ru rt = task->thread->runtime; 789240Sigor@sysoev.ru 790240Sigor@sysoev.ru process = nxt_runtime_process_find(rt, pid); 791240Sigor@sysoev.ru 792240Sigor@sysoev.ru if (process) { 793240Sigor@sysoev.ru init = process->init; 794240Sigor@sysoev.ru 795366Smax.romanov@nginx.com ptype = nxt_process_type(process); 796366Smax.romanov@nginx.com 797349Smax.romanov@nginx.com nxt_process_close_ports(task, process); 798240Sigor@sysoev.ru 799240Sigor@sysoev.ru if (!nxt_exiting) { 800277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 801277Sigor@sysoev.ru 802277Sigor@sysoev.ru if (process->pid == nxt_pid 803277Sigor@sysoev.ru || process->pid == pid 804277Sigor@sysoev.ru || nxt_queue_is_empty(&process->ports)) 805277Sigor@sysoev.ru { 806240Sigor@sysoev.ru continue; 807240Sigor@sysoev.ru } 808240Sigor@sysoev.ru 809240Sigor@sysoev.ru port = nxt_process_port_first(process); 810240Sigor@sysoev.ru 811366Smax.romanov@nginx.com if (nxt_proc_remove_notify_martix[ptype][port->type] == 0) { 812366Smax.romanov@nginx.com continue; 813366Smax.romanov@nginx.com } 814366Smax.romanov@nginx.com 815342Smax.romanov@nginx.com buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 816342Smax.romanov@nginx.com sizeof(pid)); 817382Smax.romanov@nginx.com 818382Smax.romanov@nginx.com nxt_assert(buf != NULL); 819382Smax.romanov@nginx.com 820240Sigor@sysoev.ru buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid)); 821240Sigor@sysoev.ru 822240Sigor@sysoev.ru nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, 823240Sigor@sysoev.ru -1, init->stream, 0, buf); 824277Sigor@sysoev.ru } nxt_runtime_process_loop; 825240Sigor@sysoev.ru } 826240Sigor@sysoev.ru 827240Sigor@sysoev.ru if (nxt_exiting) { 828240Sigor@sysoev.ru 829240Sigor@sysoev.ru if (rt->nprocesses == 2) { 830240Sigor@sysoev.ru nxt_runtime_quit(task); 831240Sigor@sysoev.ru } 832240Sigor@sysoev.ru 833240Sigor@sysoev.ru } else if (init != NULL) { 834368Svbart@nginx.com if (init->restart != NULL) { 835368Svbart@nginx.com init->restart(task, rt, init); 836240Sigor@sysoev.ru 837240Sigor@sysoev.ru } else { 838240Sigor@sysoev.ru nxt_free(init); 839240Sigor@sysoev.ru } 840240Sigor@sysoev.ru } 841240Sigor@sysoev.ru } 842240Sigor@sysoev.ru } 843240Sigor@sysoev.ru 844240Sigor@sysoev.ru 845240Sigor@sysoev.ru static void 846240Sigor@sysoev.ru nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 847240Sigor@sysoev.ru { 848240Sigor@sysoev.ru size_t size; 849240Sigor@sysoev.ru nxt_int_t ret; 850240Sigor@sysoev.ru nxt_buf_t *b, *out; 851240Sigor@sysoev.ru nxt_port_t *port; 852240Sigor@sysoev.ru nxt_sockaddr_t *sa; 853240Sigor@sysoev.ru nxt_port_msg_type_t type; 854240Sigor@sysoev.ru nxt_listening_socket_t ls; 855240Sigor@sysoev.ru u_char message[2048]; 856240Sigor@sysoev.ru 857240Sigor@sysoev.ru b = msg->buf; 858240Sigor@sysoev.ru sa = (nxt_sockaddr_t *) b->mem.pos; 859240Sigor@sysoev.ru 860352Smax.romanov@nginx.com /* TODO check b size and make plain */ 861352Smax.romanov@nginx.com 862240Sigor@sysoev.ru out = NULL; 863240Sigor@sysoev.ru 864240Sigor@sysoev.ru ls.socket = -1; 865240Sigor@sysoev.ru ls.error = NXT_SOCKET_ERROR_SYSTEM; 866240Sigor@sysoev.ru ls.start = message; 867240Sigor@sysoev.ru ls.end = message + sizeof(message); 868240Sigor@sysoev.ru 869240Sigor@sysoev.ru port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 870240Sigor@sysoev.ru msg->port_msg.reply_port); 871240Sigor@sysoev.ru 872240Sigor@sysoev.ru nxt_debug(task, "listening socket \"%*s\"", 873240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 874240Sigor@sysoev.ru 875240Sigor@sysoev.ru ret = nxt_main_listening_socket(sa, &ls); 876240Sigor@sysoev.ru 877240Sigor@sysoev.ru if (ret == NXT_OK) { 878240Sigor@sysoev.ru nxt_debug(task, "socket(\"%*s\"): %d", 879240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), ls.socket); 880240Sigor@sysoev.ru 881240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 882240Sigor@sysoev.ru 883240Sigor@sysoev.ru } else { 884240Sigor@sysoev.ru size = ls.end - ls.start; 885240Sigor@sysoev.ru 886240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "%*s", size, ls.start); 887240Sigor@sysoev.ru 888342Smax.romanov@nginx.com out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 889342Smax.romanov@nginx.com size + 1); 890240Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 891240Sigor@sysoev.ru return; 892240Sigor@sysoev.ru } 893240Sigor@sysoev.ru 894240Sigor@sysoev.ru *out->mem.free++ = (uint8_t) ls.error; 895240Sigor@sysoev.ru 896240Sigor@sysoev.ru out->mem.free = nxt_cpymem(out->mem.free, ls.start, size); 897240Sigor@sysoev.ru 898240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_ERROR; 899240Sigor@sysoev.ru } 900240Sigor@sysoev.ru 901240Sigor@sysoev.ru nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream, 902240Sigor@sysoev.ru 0, out); 903240Sigor@sysoev.ru } 904240Sigor@sysoev.ru 905240Sigor@sysoev.ru 906240Sigor@sysoev.ru static nxt_int_t 907240Sigor@sysoev.ru nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls) 908240Sigor@sysoev.ru { 909240Sigor@sysoev.ru nxt_err_t err; 910240Sigor@sysoev.ru nxt_socket_t s; 911240Sigor@sysoev.ru 912240Sigor@sysoev.ru const socklen_t length = sizeof(int); 913240Sigor@sysoev.ru static const int enable = 1; 914240Sigor@sysoev.ru 915240Sigor@sysoev.ru s = socket(sa->u.sockaddr.sa_family, sa->type, 0); 916240Sigor@sysoev.ru 917240Sigor@sysoev.ru if (nxt_slow_path(s == -1)) { 918240Sigor@sysoev.ru err = nxt_errno; 919240Sigor@sysoev.ru 920240Sigor@sysoev.ru #if (NXT_INET6) 921240Sigor@sysoev.ru 922240Sigor@sysoev.ru if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) { 923240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOINET6; 924240Sigor@sysoev.ru } 925240Sigor@sysoev.ru 926240Sigor@sysoev.ru #endif 927240Sigor@sysoev.ru 928240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 929240Sigor@sysoev.ru "socket(\\\"%*s\\\") failed %E", 930240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 931240Sigor@sysoev.ru 932240Sigor@sysoev.ru return NXT_ERROR; 933240Sigor@sysoev.ru } 934240Sigor@sysoev.ru 935240Sigor@sysoev.ru if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) { 936240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 937240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E", 938240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 939240Sigor@sysoev.ru goto fail; 940240Sigor@sysoev.ru } 941240Sigor@sysoev.ru 942240Sigor@sysoev.ru #if (NXT_INET6) 943240Sigor@sysoev.ru 944240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_INET6) { 945240Sigor@sysoev.ru 946240Sigor@sysoev.ru if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) { 947240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 948240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E", 949240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 950240Sigor@sysoev.ru goto fail; 951240Sigor@sysoev.ru } 952240Sigor@sysoev.ru } 953240Sigor@sysoev.ru 954240Sigor@sysoev.ru #endif 955240Sigor@sysoev.ru 956240Sigor@sysoev.ru if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) { 957240Sigor@sysoev.ru err = nxt_errno; 958240Sigor@sysoev.ru 959240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 960240Sigor@sysoev.ru 961240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 962240Sigor@sysoev.ru switch (err) { 963240Sigor@sysoev.ru 964240Sigor@sysoev.ru case EACCES: 965240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_ACCESS; 966240Sigor@sysoev.ru break; 967240Sigor@sysoev.ru 968240Sigor@sysoev.ru case ENOENT: 969240Sigor@sysoev.ru case ENOTDIR: 970240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PATH; 971240Sigor@sysoev.ru break; 972240Sigor@sysoev.ru } 973240Sigor@sysoev.ru 974240Sigor@sysoev.ru goto next; 975240Sigor@sysoev.ru } 976240Sigor@sysoev.ru 977240Sigor@sysoev.ru #endif 978240Sigor@sysoev.ru 979240Sigor@sysoev.ru switch (err) { 980240Sigor@sysoev.ru 981240Sigor@sysoev.ru case EACCES: 982240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PORT; 983240Sigor@sysoev.ru break; 984240Sigor@sysoev.ru 985240Sigor@sysoev.ru case EADDRINUSE: 986240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_INUSE; 987240Sigor@sysoev.ru break; 988240Sigor@sysoev.ru 989240Sigor@sysoev.ru case EADDRNOTAVAIL: 990240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOADDR; 991240Sigor@sysoev.ru break; 992240Sigor@sysoev.ru } 993240Sigor@sysoev.ru 994240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E", 995240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 996240Sigor@sysoev.ru goto fail; 997240Sigor@sysoev.ru } 998240Sigor@sysoev.ru 999240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1000240Sigor@sysoev.ru 1001240Sigor@sysoev.ru next: 1002240Sigor@sysoev.ru 1003240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 1004240Sigor@sysoev.ru char *filename; 1005240Sigor@sysoev.ru mode_t access; 1006240Sigor@sysoev.ru 1007240Sigor@sysoev.ru filename = sa->u.sockaddr_un.sun_path; 1008240Sigor@sysoev.ru access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 1009240Sigor@sysoev.ru 1010240Sigor@sysoev.ru if (chmod(filename, access) != 0) { 1011240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 1012240Sigor@sysoev.ru "chmod(\\\"%*s\\\") failed %E", 1013240Sigor@sysoev.ru filename, nxt_errno); 1014240Sigor@sysoev.ru goto fail; 1015240Sigor@sysoev.ru } 1016240Sigor@sysoev.ru } 1017240Sigor@sysoev.ru 1018240Sigor@sysoev.ru #endif 1019240Sigor@sysoev.ru 1020240Sigor@sysoev.ru ls->socket = s; 1021240Sigor@sysoev.ru 1022240Sigor@sysoev.ru return NXT_OK; 1023240Sigor@sysoev.ru 1024240Sigor@sysoev.ru fail: 1025240Sigor@sysoev.ru 1026240Sigor@sysoev.ru (void) close(s); 1027240Sigor@sysoev.ru 1028240Sigor@sysoev.ru return NXT_ERROR; 1029240Sigor@sysoev.ru } 1030240Sigor@sysoev.ru 1031240Sigor@sysoev.ru 1032240Sigor@sysoev.ru static nxt_conf_map_t nxt_app_lang_module_map[] = { 1033240Sigor@sysoev.ru { 1034240Sigor@sysoev.ru nxt_string("type"), 1035356Svbart@nginx.com NXT_CONF_MAP_INT, 1036240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, type), 1037240Sigor@sysoev.ru }, 1038240Sigor@sysoev.ru 1039240Sigor@sysoev.ru { 1040240Sigor@sysoev.ru nxt_string("version"), 1041354Svbart@nginx.com NXT_CONF_MAP_CSTRZ, 1042240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, version), 1043240Sigor@sysoev.ru }, 1044240Sigor@sysoev.ru 1045240Sigor@sysoev.ru { 1046240Sigor@sysoev.ru nxt_string("file"), 1047240Sigor@sysoev.ru NXT_CONF_MAP_CSTRZ, 1048240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, file), 1049240Sigor@sysoev.ru }, 1050240Sigor@sysoev.ru }; 1051240Sigor@sysoev.ru 1052240Sigor@sysoev.ru 1053240Sigor@sysoev.ru static void 1054240Sigor@sysoev.ru nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1055240Sigor@sysoev.ru { 1056240Sigor@sysoev.ru uint32_t index; 1057240Sigor@sysoev.ru nxt_mp_t *mp; 1058240Sigor@sysoev.ru nxt_int_t ret; 1059240Sigor@sysoev.ru nxt_buf_t *b; 1060240Sigor@sysoev.ru nxt_runtime_t *rt; 1061240Sigor@sysoev.ru nxt_conf_value_t *conf, *root, *value; 1062240Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1063240Sigor@sysoev.ru 1064240Sigor@sysoev.ru static nxt_str_t root_path = nxt_string("/"); 1065240Sigor@sysoev.ru 1066240Sigor@sysoev.ru rt = task->thread->runtime; 1067240Sigor@sysoev.ru 1068240Sigor@sysoev.ru if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) { 1069240Sigor@sysoev.ru return; 1070240Sigor@sysoev.ru } 1071240Sigor@sysoev.ru 1072240Sigor@sysoev.ru b = msg->buf; 1073240Sigor@sysoev.ru 1074240Sigor@sysoev.ru if (b == NULL) { 1075240Sigor@sysoev.ru return; 1076240Sigor@sysoev.ru } 1077240Sigor@sysoev.ru 1078240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 1079240Sigor@sysoev.ru if (mp == NULL) { 1080240Sigor@sysoev.ru return; 1081240Sigor@sysoev.ru } 1082240Sigor@sysoev.ru 1083352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(mp, b, msg->size); 1084352Smax.romanov@nginx.com 1085352Smax.romanov@nginx.com if (b == NULL) { 1086352Smax.romanov@nginx.com return; 1087352Smax.romanov@nginx.com } 1088352Smax.romanov@nginx.com 1089352Smax.romanov@nginx.com nxt_debug(task, "application languages: \"%*s\"", 1090352Smax.romanov@nginx.com b->mem.free - b->mem.pos, b->mem.pos); 1091352Smax.romanov@nginx.com 1092240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL); 1093240Sigor@sysoev.ru if (conf == NULL) { 1094240Sigor@sysoev.ru goto fail; 1095240Sigor@sysoev.ru } 1096240Sigor@sysoev.ru 1097240Sigor@sysoev.ru root = nxt_conf_get_path(conf, &root_path); 1098240Sigor@sysoev.ru if (root == NULL) { 1099240Sigor@sysoev.ru goto fail; 1100240Sigor@sysoev.ru } 1101240Sigor@sysoev.ru 1102240Sigor@sysoev.ru for (index = 0; /* void */ ; index++) { 1103240Sigor@sysoev.ru value = nxt_conf_get_array_element(root, index); 1104240Sigor@sysoev.ru if (value == NULL) { 1105240Sigor@sysoev.ru break; 1106240Sigor@sysoev.ru } 1107240Sigor@sysoev.ru 1108240Sigor@sysoev.ru lang = nxt_array_add(rt->languages); 1109240Sigor@sysoev.ru if (lang == NULL) { 1110240Sigor@sysoev.ru goto fail; 1111240Sigor@sysoev.ru } 1112240Sigor@sysoev.ru 1113240Sigor@sysoev.ru lang->module = NULL; 1114240Sigor@sysoev.ru 1115240Sigor@sysoev.ru ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map, 1116240Sigor@sysoev.ru nxt_nitems(nxt_app_lang_module_map), lang); 1117240Sigor@sysoev.ru 1118240Sigor@sysoev.ru if (ret != NXT_OK) { 1119240Sigor@sysoev.ru goto fail; 1120240Sigor@sysoev.ru } 1121240Sigor@sysoev.ru 1122356Svbart@nginx.com nxt_debug(task, "lang %d %s \"%s\"", 1123356Svbart@nginx.com lang->type, lang->version, lang->file); 1124240Sigor@sysoev.ru } 1125240Sigor@sysoev.ru 1126240Sigor@sysoev.ru qsort(rt->languages->elts, rt->languages->nelts, 1127240Sigor@sysoev.ru sizeof(nxt_app_lang_module_t), nxt_app_lang_compare); 1128240Sigor@sysoev.ru 1129240Sigor@sysoev.ru fail: 1130240Sigor@sysoev.ru 1131240Sigor@sysoev.ru nxt_mp_destroy(mp); 1132240Sigor@sysoev.ru 1133240Sigor@sysoev.ru ret = nxt_main_start_controller_process(task, rt); 1134240Sigor@sysoev.ru 1135240Sigor@sysoev.ru if (ret == NXT_OK) { 1136240Sigor@sysoev.ru (void) nxt_main_start_router_process(task, rt); 1137240Sigor@sysoev.ru } 1138240Sigor@sysoev.ru } 1139240Sigor@sysoev.ru 1140240Sigor@sysoev.ru 1141240Sigor@sysoev.ru static int nxt_cdecl 1142240Sigor@sysoev.ru nxt_app_lang_compare(const void *v1, const void *v2) 1143240Sigor@sysoev.ru { 1144240Sigor@sysoev.ru int n; 1145240Sigor@sysoev.ru const nxt_app_lang_module_t *lang1, *lang2; 1146240Sigor@sysoev.ru 1147240Sigor@sysoev.ru lang1 = v1; 1148240Sigor@sysoev.ru lang2 = v2; 1149240Sigor@sysoev.ru 1150356Svbart@nginx.com n = lang1->type - lang2->type; 1151258Sigor@sysoev.ru 1152258Sigor@sysoev.ru if (n != 0) { 1153258Sigor@sysoev.ru return n; 1154258Sigor@sysoev.ru } 1155258Sigor@sysoev.ru 1156354Svbart@nginx.com n = nxt_strverscmp(lang1->version, lang2->version); 1157240Sigor@sysoev.ru 1158240Sigor@sysoev.ru /* Negate result to move higher versions to the beginning. */ 1159240Sigor@sysoev.ru 1160240Sigor@sysoev.ru return -n; 1161240Sigor@sysoev.ru } 1162314Svbart@nginx.com 1163314Svbart@nginx.com 1164314Svbart@nginx.com static void 1165314Svbart@nginx.com nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1166314Svbart@nginx.com { 1167352Smax.romanov@nginx.com ssize_t n, size, offset; 1168314Svbart@nginx.com nxt_buf_t *b; 1169314Svbart@nginx.com nxt_int_t ret; 1170314Svbart@nginx.com nxt_file_t file; 1171314Svbart@nginx.com nxt_runtime_t *rt; 1172314Svbart@nginx.com 1173314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 1174314Svbart@nginx.com 1175314Svbart@nginx.com rt = task->thread->runtime; 1176314Svbart@nginx.com 1177314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf_tmp; 1178314Svbart@nginx.com 1179314Svbart@nginx.com if (nxt_slow_path(nxt_file_open(task, &file, NXT_FILE_WRONLY, 1180314Svbart@nginx.com NXT_FILE_TRUNCATE, NXT_FILE_OWNER_ACCESS) 1181314Svbart@nginx.com != NXT_OK)) 1182314Svbart@nginx.com { 1183314Svbart@nginx.com goto error; 1184314Svbart@nginx.com } 1185314Svbart@nginx.com 1186352Smax.romanov@nginx.com offset = 0; 1187352Smax.romanov@nginx.com 1188314Svbart@nginx.com for (b = msg->buf; b != NULL; b = b->next) { 1189314Svbart@nginx.com size = nxt_buf_mem_used_size(&b->mem); 1190314Svbart@nginx.com 1191352Smax.romanov@nginx.com n = nxt_file_write(&file, b->mem.pos, size, offset); 1192314Svbart@nginx.com 1193314Svbart@nginx.com if (nxt_slow_path(n != size)) { 1194314Svbart@nginx.com nxt_file_close(task, &file); 1195314Svbart@nginx.com (void) nxt_file_delete(file.name); 1196314Svbart@nginx.com goto error; 1197314Svbart@nginx.com } 1198352Smax.romanov@nginx.com 1199352Smax.romanov@nginx.com offset += n; 1200314Svbart@nginx.com } 1201314Svbart@nginx.com 1202314Svbart@nginx.com nxt_file_close(task, &file); 1203314Svbart@nginx.com 1204314Svbart@nginx.com ret = nxt_file_rename(file.name, (nxt_file_name_t *) rt->conf); 1205314Svbart@nginx.com 1206314Svbart@nginx.com if (nxt_fast_path(ret == NXT_OK)) { 1207314Svbart@nginx.com return; 1208314Svbart@nginx.com } 1209314Svbart@nginx.com 1210314Svbart@nginx.com error: 1211314Svbart@nginx.com 1212314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, "failed to store current configuration"); 1213314Svbart@nginx.com } 1214