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); 28240Sigor@sysoev.ru static nxt_int_t nxt_main_start_router_process(nxt_task_t *task, 29240Sigor@sysoev.ru nxt_runtime_t *rt); 30240Sigor@sysoev.ru static nxt_int_t nxt_main_start_discovery_process(nxt_task_t *task, 31240Sigor@sysoev.ru nxt_runtime_t *rt); 32240Sigor@sysoev.ru static nxt_int_t nxt_main_start_worker_process(nxt_task_t *task, 33240Sigor@sysoev.ru nxt_runtime_t *rt, nxt_common_app_conf_t *app_conf, uint32_t stream); 34240Sigor@sysoev.ru static nxt_int_t nxt_main_create_worker_process(nxt_task_t *task, 35240Sigor@sysoev.ru nxt_runtime_t *rt, nxt_process_init_t *init); 36240Sigor@sysoev.ru static void nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, 37240Sigor@sysoev.ru void *data); 38240Sigor@sysoev.ru static void nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, 39240Sigor@sysoev.ru void *data); 40240Sigor@sysoev.ru static void nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, 41240Sigor@sysoev.ru void *data); 42240Sigor@sysoev.ru static void nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, 43240Sigor@sysoev.ru void *data); 44240Sigor@sysoev.ru static void nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid); 45240Sigor@sysoev.ru static void nxt_main_port_socket_handler(nxt_task_t *task, 46240Sigor@sysoev.ru nxt_port_recv_msg_t *msg); 47240Sigor@sysoev.ru static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa, 48240Sigor@sysoev.ru nxt_listening_socket_t *ls); 49240Sigor@sysoev.ru static void nxt_main_port_modules_handler(nxt_task_t *task, 50240Sigor@sysoev.ru nxt_port_recv_msg_t *msg); 51240Sigor@sysoev.ru static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2); 52314Svbart@nginx.com static void nxt_main_port_conf_store_handler(nxt_task_t *task, 53314Svbart@nginx.com nxt_port_recv_msg_t *msg); 54240Sigor@sysoev.ru 55240Sigor@sysoev.ru 56240Sigor@sysoev.ru const nxt_sig_event_t nxt_main_process_signals[] = { 57240Sigor@sysoev.ru nxt_event_signal(SIGINT, nxt_main_process_sigterm_handler), 58240Sigor@sysoev.ru nxt_event_signal(SIGQUIT, nxt_main_process_sigquit_handler), 59240Sigor@sysoev.ru nxt_event_signal(SIGTERM, nxt_main_process_sigterm_handler), 60240Sigor@sysoev.ru nxt_event_signal(SIGCHLD, nxt_main_process_sigchld_handler), 61240Sigor@sysoev.ru nxt_event_signal(SIGUSR1, nxt_main_process_sigusr1_handler), 62240Sigor@sysoev.ru nxt_event_signal_end, 63240Sigor@sysoev.ru }; 64240Sigor@sysoev.ru 65240Sigor@sysoev.ru 66240Sigor@sysoev.ru static nxt_bool_t nxt_exiting; 67240Sigor@sysoev.ru 68240Sigor@sysoev.ru 69240Sigor@sysoev.ru nxt_int_t 70240Sigor@sysoev.ru nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task, 71240Sigor@sysoev.ru nxt_runtime_t *rt) 72240Sigor@sysoev.ru { 73240Sigor@sysoev.ru rt->types |= (1U << NXT_PROCESS_MAIN); 74240Sigor@sysoev.ru 75240Sigor@sysoev.ru if (nxt_main_process_port_create(task, rt) != NXT_OK) { 76240Sigor@sysoev.ru return NXT_ERROR; 77240Sigor@sysoev.ru } 78240Sigor@sysoev.ru 79240Sigor@sysoev.ru nxt_main_process_title(task); 80240Sigor@sysoev.ru 81240Sigor@sysoev.ru /* 82240Sigor@sysoev.ru * The dicsovery process will send a message processed by 83240Sigor@sysoev.ru * nxt_main_port_modules_handler() which starts the controller 84240Sigor@sysoev.ru * and router processes. 85240Sigor@sysoev.ru */ 86240Sigor@sysoev.ru return nxt_main_start_discovery_process(task, rt); 87240Sigor@sysoev.ru } 88240Sigor@sysoev.ru 89240Sigor@sysoev.ru 90240Sigor@sysoev.ru static nxt_conf_map_t nxt_common_app_conf[] = { 91240Sigor@sysoev.ru { 92240Sigor@sysoev.ru nxt_string("type"), 93240Sigor@sysoev.ru NXT_CONF_MAP_STR, 94240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, type), 95240Sigor@sysoev.ru }, 96240Sigor@sysoev.ru 97240Sigor@sysoev.ru { 98240Sigor@sysoev.ru nxt_string("user"), 99240Sigor@sysoev.ru NXT_CONF_MAP_STR, 100240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, user), 101240Sigor@sysoev.ru }, 102240Sigor@sysoev.ru 103240Sigor@sysoev.ru { 104240Sigor@sysoev.ru nxt_string("group"), 105240Sigor@sysoev.ru NXT_CONF_MAP_STR, 106240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, group), 107240Sigor@sysoev.ru }, 108240Sigor@sysoev.ru 109240Sigor@sysoev.ru { 110271Smax.romanov@nginx.com nxt_string("working_directory"), 111271Smax.romanov@nginx.com NXT_CONF_MAP_CSTRZ, 112271Smax.romanov@nginx.com offsetof(nxt_common_app_conf_t, working_directory), 113271Smax.romanov@nginx.com }, 114271Smax.romanov@nginx.com 115271Smax.romanov@nginx.com { 116240Sigor@sysoev.ru nxt_string("workers"), 117240Sigor@sysoev.ru NXT_CONF_MAP_INT32, 118240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, workers), 119240Sigor@sysoev.ru }, 120240Sigor@sysoev.ru 121240Sigor@sysoev.ru { 122240Sigor@sysoev.ru nxt_string("path"), 123240Sigor@sysoev.ru NXT_CONF_MAP_STR, 124240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.python.path), 125240Sigor@sysoev.ru }, 126240Sigor@sysoev.ru 127240Sigor@sysoev.ru { 128240Sigor@sysoev.ru nxt_string("module"), 129240Sigor@sysoev.ru NXT_CONF_MAP_STR, 130240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.python.module), 131240Sigor@sysoev.ru }, 132240Sigor@sysoev.ru 133240Sigor@sysoev.ru { 134240Sigor@sysoev.ru nxt_string("root"), 135240Sigor@sysoev.ru NXT_CONF_MAP_STR, 136240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.root), 137240Sigor@sysoev.ru }, 138240Sigor@sysoev.ru 139240Sigor@sysoev.ru { 140240Sigor@sysoev.ru nxt_string("script"), 141240Sigor@sysoev.ru NXT_CONF_MAP_STR, 142240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.script), 143240Sigor@sysoev.ru }, 144240Sigor@sysoev.ru 145240Sigor@sysoev.ru { 146240Sigor@sysoev.ru nxt_string("index"), 147240Sigor@sysoev.ru NXT_CONF_MAP_STR, 148240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.php.index), 149240Sigor@sysoev.ru }, 150240Sigor@sysoev.ru 151240Sigor@sysoev.ru { 152240Sigor@sysoev.ru nxt_string("executable"), 153272Smax.romanov@nginx.com NXT_CONF_MAP_CSTRZ, 154240Sigor@sysoev.ru offsetof(nxt_common_app_conf_t, u.go.executable), 155240Sigor@sysoev.ru }, 156240Sigor@sysoev.ru }; 157240Sigor@sysoev.ru 158240Sigor@sysoev.ru 159240Sigor@sysoev.ru static void 160240Sigor@sysoev.ru nxt_port_main_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 161240Sigor@sysoev.ru { 162240Sigor@sysoev.ru nxt_debug(task, "main data: %*s", 163240Sigor@sysoev.ru nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 164240Sigor@sysoev.ru } 165240Sigor@sysoev.ru 166240Sigor@sysoev.ru 167240Sigor@sysoev.ru static void 168240Sigor@sysoev.ru nxt_port_main_start_worker_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 169240Sigor@sysoev.ru { 170240Sigor@sysoev.ru u_char *start; 171240Sigor@sysoev.ru nxt_mp_t *mp; 172240Sigor@sysoev.ru nxt_int_t ret; 173240Sigor@sysoev.ru nxt_buf_t *b; 174318Smax.romanov@nginx.com nxt_port_t *port; 175240Sigor@sysoev.ru nxt_conf_value_t *conf; 176240Sigor@sysoev.ru nxt_common_app_conf_t app_conf; 177240Sigor@sysoev.ru 178240Sigor@sysoev.ru static nxt_str_t nobody = nxt_string("nobody"); 179240Sigor@sysoev.ru 180318Smax.romanov@nginx.com ret = NXT_ERROR; 181318Smax.romanov@nginx.com 182*352Smax.romanov@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 183*352Smax.romanov@nginx.com 184*352Smax.romanov@nginx.com if (nxt_slow_path(mp == NULL)) { 185*352Smax.romanov@nginx.com return; 186*352Smax.romanov@nginx.com } 187*352Smax.romanov@nginx.com 188*352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(mp, msg->buf, msg->size); 189*352Smax.romanov@nginx.com 190*352Smax.romanov@nginx.com if (b == NULL) { 191*352Smax.romanov@nginx.com return; 192*352Smax.romanov@nginx.com } 193240Sigor@sysoev.ru 194240Sigor@sysoev.ru nxt_debug(task, "main start worker: %*s", b->mem.free - b->mem.pos, 195240Sigor@sysoev.ru b->mem.pos); 196240Sigor@sysoev.ru 197240Sigor@sysoev.ru nxt_memzero(&app_conf, sizeof(nxt_common_app_conf_t)); 198240Sigor@sysoev.ru 199240Sigor@sysoev.ru start = b->mem.pos; 200240Sigor@sysoev.ru 201240Sigor@sysoev.ru app_conf.name.start = start; 202240Sigor@sysoev.ru app_conf.name.length = nxt_strlen(start); 203240Sigor@sysoev.ru 204240Sigor@sysoev.ru start += app_conf.name.length + 1; 205240Sigor@sysoev.ru 206240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, start, b->mem.free, NULL); 207240Sigor@sysoev.ru 208240Sigor@sysoev.ru if (conf == NULL) { 209240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 210318Smax.romanov@nginx.com 211318Smax.romanov@nginx.com goto failed; 212240Sigor@sysoev.ru } 213240Sigor@sysoev.ru 214240Sigor@sysoev.ru app_conf.user = nobody; 215240Sigor@sysoev.ru 216240Sigor@sysoev.ru ret = nxt_conf_map_object(mp, conf, nxt_common_app_conf, 217240Sigor@sysoev.ru nxt_nitems(nxt_common_app_conf), &app_conf); 218240Sigor@sysoev.ru if (ret != NXT_OK) { 219240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 220318Smax.romanov@nginx.com 221318Smax.romanov@nginx.com goto failed; 222240Sigor@sysoev.ru } 223240Sigor@sysoev.ru 224240Sigor@sysoev.ru ret = nxt_main_start_worker_process(task, task->thread->runtime, 225240Sigor@sysoev.ru &app_conf, msg->port_msg.stream); 226240Sigor@sysoev.ru 227318Smax.romanov@nginx.com failed: 228318Smax.romanov@nginx.com 229318Smax.romanov@nginx.com if (ret == NXT_ERROR) { 230318Smax.romanov@nginx.com port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 231318Smax.romanov@nginx.com msg->port_msg.reply_port); 232318Smax.romanov@nginx.com if (nxt_fast_path(port != NULL)) { 233318Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 234318Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 235318Smax.romanov@nginx.com } 236318Smax.romanov@nginx.com } 237318Smax.romanov@nginx.com 238240Sigor@sysoev.ru nxt_mp_destroy(mp); 239240Sigor@sysoev.ru } 240240Sigor@sysoev.ru 241240Sigor@sysoev.ru 242320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_main_process_port_handlers = { 243320Smax.romanov@nginx.com .data = nxt_port_main_data_handler, 244320Smax.romanov@nginx.com .process_ready = nxt_port_process_ready_handler, 245320Smax.romanov@nginx.com .start_worker = nxt_port_main_start_worker_handler, 246320Smax.romanov@nginx.com .socket = nxt_main_port_socket_handler, 247320Smax.romanov@nginx.com .modules = nxt_main_port_modules_handler, 248320Smax.romanov@nginx.com .conf_store = nxt_main_port_conf_store_handler, 249320Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 250320Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 251240Sigor@sysoev.ru }; 252240Sigor@sysoev.ru 253240Sigor@sysoev.ru 254240Sigor@sysoev.ru static nxt_int_t 255240Sigor@sysoev.ru nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt) 256240Sigor@sysoev.ru { 257240Sigor@sysoev.ru nxt_int_t ret; 258240Sigor@sysoev.ru nxt_port_t *port; 259240Sigor@sysoev.ru nxt_process_t *process; 260240Sigor@sysoev.ru 261240Sigor@sysoev.ru process = nxt_runtime_process_get(rt, nxt_pid); 262240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 263240Sigor@sysoev.ru return NXT_ERROR; 264240Sigor@sysoev.ru } 265240Sigor@sysoev.ru 266240Sigor@sysoev.ru port = nxt_port_new(task, 0, nxt_pid, NXT_PROCESS_MAIN); 267240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 268349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 269240Sigor@sysoev.ru return NXT_ERROR; 270240Sigor@sysoev.ru } 271240Sigor@sysoev.ru 272343Smax.romanov@nginx.com nxt_process_port_add(task, process, port); 273343Smax.romanov@nginx.com 274349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 275349Smax.romanov@nginx.com 276240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 277240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 278343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 279240Sigor@sysoev.ru return ret; 280240Sigor@sysoev.ru } 281240Sigor@sysoev.ru 282343Smax.romanov@nginx.com nxt_runtime_port_add(task, port); 283240Sigor@sysoev.ru 284343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 285240Sigor@sysoev.ru 286240Sigor@sysoev.ru /* 287240Sigor@sysoev.ru * A main process port. A write port is not closed 288240Sigor@sysoev.ru * since it should be inherited by worker processes. 289240Sigor@sysoev.ru */ 290320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_main_process_port_handlers); 291240Sigor@sysoev.ru 292240Sigor@sysoev.ru process->ready = 1; 293240Sigor@sysoev.ru 294240Sigor@sysoev.ru return NXT_OK; 295240Sigor@sysoev.ru } 296240Sigor@sysoev.ru 297240Sigor@sysoev.ru 298240Sigor@sysoev.ru static void 299240Sigor@sysoev.ru nxt_main_process_title(nxt_task_t *task) 300240Sigor@sysoev.ru { 301240Sigor@sysoev.ru u_char *p, *end; 302240Sigor@sysoev.ru nxt_uint_t i; 303240Sigor@sysoev.ru u_char title[2048]; 304240Sigor@sysoev.ru 305240Sigor@sysoev.ru end = title + sizeof(title) - 1; 306240Sigor@sysoev.ru 307259Sigor@sysoev.ru p = nxt_sprintf(title, end, "unit: main [%s", nxt_process_argv[0]); 308240Sigor@sysoev.ru 309240Sigor@sysoev.ru for (i = 1; nxt_process_argv[i] != NULL; i++) { 310240Sigor@sysoev.ru p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]); 311240Sigor@sysoev.ru } 312240Sigor@sysoev.ru 313240Sigor@sysoev.ru if (p < end) { 314240Sigor@sysoev.ru *p++ = ']'; 315240Sigor@sysoev.ru } 316240Sigor@sysoev.ru 317240Sigor@sysoev.ru *p = '\0'; 318240Sigor@sysoev.ru 319240Sigor@sysoev.ru nxt_process_title(task, "%s", title); 320240Sigor@sysoev.ru } 321240Sigor@sysoev.ru 322240Sigor@sysoev.ru 323240Sigor@sysoev.ru static nxt_int_t 324240Sigor@sysoev.ru nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt) 325240Sigor@sysoev.ru { 326314Svbart@nginx.com ssize_t n; 327314Svbart@nginx.com nxt_int_t ret; 328314Svbart@nginx.com nxt_str_t conf; 329314Svbart@nginx.com nxt_file_t file; 330314Svbart@nginx.com nxt_file_info_t fi; 331240Sigor@sysoev.ru nxt_process_init_t *init; 332240Sigor@sysoev.ru 333314Svbart@nginx.com conf.length = 0; 334314Svbart@nginx.com 335314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 336314Svbart@nginx.com 337314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf; 338314Svbart@nginx.com 339329Sigor@sysoev.ru ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 340314Svbart@nginx.com 341329Sigor@sysoev.ru if (ret == NXT_OK) { 342329Sigor@sysoev.ru ret = nxt_file_info(&file, &fi); 343329Sigor@sysoev.ru 344329Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) { 345314Svbart@nginx.com conf.length = nxt_file_size(&fi); 346314Svbart@nginx.com conf.start = nxt_malloc(conf.length); 347314Svbart@nginx.com 348314Svbart@nginx.com if (nxt_slow_path(conf.start == NULL)) { 349314Svbart@nginx.com nxt_file_close(task, &file); 350314Svbart@nginx.com return NXT_ERROR; 351314Svbart@nginx.com } 352314Svbart@nginx.com 353314Svbart@nginx.com n = nxt_file_read(&file, conf.start, conf.length, 0); 354314Svbart@nginx.com 355314Svbart@nginx.com if (nxt_slow_path(n != (ssize_t) conf.length)) { 356314Svbart@nginx.com conf.length = 0; 357314Svbart@nginx.com nxt_free(conf.start); 358314Svbart@nginx.com 359314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, 360314Svbart@nginx.com "failed to restore previous configuration: " 361314Svbart@nginx.com "cannot read the file"); 362314Svbart@nginx.com } 363314Svbart@nginx.com } 364314Svbart@nginx.com 365314Svbart@nginx.com nxt_file_close(task, &file); 366314Svbart@nginx.com } 367314Svbart@nginx.com 368240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 369240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 370240Sigor@sysoev.ru return NXT_ERROR; 371240Sigor@sysoev.ru } 372240Sigor@sysoev.ru 373240Sigor@sysoev.ru init->start = nxt_controller_start; 374240Sigor@sysoev.ru init->name = "controller"; 375240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 376320Smax.romanov@nginx.com init->port_handlers = &nxt_controller_process_port_handlers; 377240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 378240Sigor@sysoev.ru init->type = NXT_PROCESS_CONTROLLER; 379314Svbart@nginx.com init->data = &conf; 380240Sigor@sysoev.ru init->stream = 0; 381240Sigor@sysoev.ru init->restart = 1; 382240Sigor@sysoev.ru 383314Svbart@nginx.com ret = nxt_main_create_worker_process(task, rt, init); 384314Svbart@nginx.com 385314Svbart@nginx.com if (ret == NXT_OK && conf.length != 0) { 386314Svbart@nginx.com nxt_free(conf.start); 387314Svbart@nginx.com } 388314Svbart@nginx.com 389314Svbart@nginx.com return ret; 390240Sigor@sysoev.ru } 391240Sigor@sysoev.ru 392240Sigor@sysoev.ru 393240Sigor@sysoev.ru static nxt_int_t 394240Sigor@sysoev.ru nxt_main_start_discovery_process(nxt_task_t *task, nxt_runtime_t *rt) 395240Sigor@sysoev.ru { 396240Sigor@sysoev.ru nxt_process_init_t *init; 397240Sigor@sysoev.ru 398240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 399240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 400240Sigor@sysoev.ru return NXT_ERROR; 401240Sigor@sysoev.ru } 402240Sigor@sysoev.ru 403240Sigor@sysoev.ru init->start = nxt_discovery_start; 404240Sigor@sysoev.ru init->name = "discovery"; 405240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 406320Smax.romanov@nginx.com init->port_handlers = &nxt_discovery_process_port_handlers; 407240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 408240Sigor@sysoev.ru init->type = NXT_PROCESS_DISCOVERY; 409240Sigor@sysoev.ru init->data = rt; 410240Sigor@sysoev.ru init->stream = 0; 411240Sigor@sysoev.ru init->restart = 0; 412240Sigor@sysoev.ru 413240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 414240Sigor@sysoev.ru } 415240Sigor@sysoev.ru 416240Sigor@sysoev.ru 417240Sigor@sysoev.ru static nxt_int_t 418240Sigor@sysoev.ru nxt_main_start_router_process(nxt_task_t *task, nxt_runtime_t *rt) 419240Sigor@sysoev.ru { 420240Sigor@sysoev.ru nxt_process_init_t *init; 421240Sigor@sysoev.ru 422240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 423240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 424240Sigor@sysoev.ru return NXT_ERROR; 425240Sigor@sysoev.ru } 426240Sigor@sysoev.ru 427240Sigor@sysoev.ru init->start = nxt_router_start; 428240Sigor@sysoev.ru init->name = "router"; 429240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 430320Smax.romanov@nginx.com init->port_handlers = &nxt_router_process_port_handlers; 431240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 432240Sigor@sysoev.ru init->type = NXT_PROCESS_ROUTER; 433240Sigor@sysoev.ru init->data = rt; 434240Sigor@sysoev.ru init->stream = 0; 435240Sigor@sysoev.ru init->restart = 1; 436240Sigor@sysoev.ru 437240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 438240Sigor@sysoev.ru } 439240Sigor@sysoev.ru 440240Sigor@sysoev.ru 441240Sigor@sysoev.ru static nxt_int_t 442240Sigor@sysoev.ru nxt_main_start_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 443240Sigor@sysoev.ru nxt_common_app_conf_t *app_conf, uint32_t stream) 444240Sigor@sysoev.ru { 445240Sigor@sysoev.ru char *user, *group; 446240Sigor@sysoev.ru u_char *title, *last, *end; 447240Sigor@sysoev.ru size_t size; 448240Sigor@sysoev.ru nxt_process_init_t *init; 449240Sigor@sysoev.ru 450240Sigor@sysoev.ru size = sizeof(nxt_process_init_t) 451240Sigor@sysoev.ru + sizeof(nxt_user_cred_t) 452240Sigor@sysoev.ru + app_conf->user.length + 1 453240Sigor@sysoev.ru + app_conf->group.length + 1 454240Sigor@sysoev.ru + app_conf->name.length + sizeof("\"\" application"); 455240Sigor@sysoev.ru 456240Sigor@sysoev.ru init = nxt_malloc(size); 457240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 458240Sigor@sysoev.ru return NXT_ERROR; 459240Sigor@sysoev.ru } 460240Sigor@sysoev.ru 461240Sigor@sysoev.ru init->user_cred = nxt_pointer_to(init, sizeof(nxt_process_init_t)); 462240Sigor@sysoev.ru user = nxt_pointer_to(init->user_cred, sizeof(nxt_user_cred_t)); 463240Sigor@sysoev.ru 464240Sigor@sysoev.ru nxt_memcpy(user, app_conf->user.start, app_conf->user.length); 465240Sigor@sysoev.ru last = nxt_pointer_to(user, app_conf->user.length); 466240Sigor@sysoev.ru *last++ = '\0'; 467240Sigor@sysoev.ru 468240Sigor@sysoev.ru init->user_cred->user = user; 469240Sigor@sysoev.ru 470240Sigor@sysoev.ru if (app_conf->group.start != NULL) { 471240Sigor@sysoev.ru group = (char *) last; 472240Sigor@sysoev.ru 473240Sigor@sysoev.ru nxt_memcpy(group, app_conf->group.start, app_conf->group.length); 474240Sigor@sysoev.ru last = nxt_pointer_to(group, app_conf->group.length); 475240Sigor@sysoev.ru *last++ = '\0'; 476240Sigor@sysoev.ru 477240Sigor@sysoev.ru } else { 478240Sigor@sysoev.ru group = NULL; 479240Sigor@sysoev.ru } 480240Sigor@sysoev.ru 481240Sigor@sysoev.ru if (nxt_user_cred_get(task, init->user_cred, group) != NXT_OK) { 482240Sigor@sysoev.ru return NXT_ERROR; 483240Sigor@sysoev.ru } 484240Sigor@sysoev.ru 485240Sigor@sysoev.ru title = last; 486240Sigor@sysoev.ru end = title + app_conf->name.length + sizeof("\"\" application"); 487240Sigor@sysoev.ru 488240Sigor@sysoev.ru nxt_sprintf(title, end, "\"%V\" application%Z", &app_conf->name); 489240Sigor@sysoev.ru 490240Sigor@sysoev.ru init->start = nxt_app_start; 491240Sigor@sysoev.ru init->name = (char *) title; 492320Smax.romanov@nginx.com init->port_handlers = &nxt_app_process_port_handlers; 493240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 494240Sigor@sysoev.ru init->type = NXT_PROCESS_WORKER; 495240Sigor@sysoev.ru init->data = app_conf; 496240Sigor@sysoev.ru init->stream = stream; 497240Sigor@sysoev.ru init->restart = 0; 498240Sigor@sysoev.ru 499240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 500240Sigor@sysoev.ru } 501240Sigor@sysoev.ru 502240Sigor@sysoev.ru 503240Sigor@sysoev.ru static nxt_int_t 504240Sigor@sysoev.ru nxt_main_create_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 505240Sigor@sysoev.ru nxt_process_init_t *init) 506240Sigor@sysoev.ru { 507240Sigor@sysoev.ru nxt_int_t ret; 508240Sigor@sysoev.ru nxt_pid_t pid; 509240Sigor@sysoev.ru nxt_port_t *port; 510240Sigor@sysoev.ru nxt_process_t *process; 511240Sigor@sysoev.ru 512240Sigor@sysoev.ru /* 513240Sigor@sysoev.ru * TODO: remove process, init, ports from array on memory and fork failures. 514240Sigor@sysoev.ru */ 515240Sigor@sysoev.ru 516240Sigor@sysoev.ru process = nxt_runtime_process_new(rt); 517240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 518240Sigor@sysoev.ru return NXT_ERROR; 519240Sigor@sysoev.ru } 520240Sigor@sysoev.ru 521240Sigor@sysoev.ru process->init = init; 522240Sigor@sysoev.ru 523240Sigor@sysoev.ru port = nxt_port_new(task, 0, 0, init->type); 524240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 525349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 526240Sigor@sysoev.ru return NXT_ERROR; 527240Sigor@sysoev.ru } 528240Sigor@sysoev.ru 529240Sigor@sysoev.ru nxt_process_port_add(task, process, port); 530240Sigor@sysoev.ru 531349Smax.romanov@nginx.com nxt_process_use(task, process, -1); 532349Smax.romanov@nginx.com 533240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 534240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 535343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 536240Sigor@sysoev.ru return ret; 537240Sigor@sysoev.ru } 538240Sigor@sysoev.ru 539240Sigor@sysoev.ru pid = nxt_process_create(task, process); 540240Sigor@sysoev.ru 541343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 542343Smax.romanov@nginx.com 543240Sigor@sysoev.ru switch (pid) { 544240Sigor@sysoev.ru 545240Sigor@sysoev.ru case -1: 546240Sigor@sysoev.ru return NXT_ERROR; 547240Sigor@sysoev.ru 548240Sigor@sysoev.ru case 0: 549240Sigor@sysoev.ru /* A worker process, return to the event engine work queue loop. */ 550240Sigor@sysoev.ru return NXT_AGAIN; 551240Sigor@sysoev.ru 552240Sigor@sysoev.ru default: 553240Sigor@sysoev.ru /* The main process created a new process. */ 554240Sigor@sysoev.ru 555240Sigor@sysoev.ru nxt_port_read_close(port); 556240Sigor@sysoev.ru nxt_port_write_enable(task, port); 557240Sigor@sysoev.ru 558240Sigor@sysoev.ru return NXT_OK; 559240Sigor@sysoev.ru } 560240Sigor@sysoev.ru } 561240Sigor@sysoev.ru 562240Sigor@sysoev.ru 563240Sigor@sysoev.ru void 564240Sigor@sysoev.ru nxt_main_stop_worker_processes(nxt_task_t *task, nxt_runtime_t *rt) 565240Sigor@sysoev.ru { 566240Sigor@sysoev.ru nxt_port_t *port; 567240Sigor@sysoev.ru nxt_process_t *process; 568240Sigor@sysoev.ru 569277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 570277Sigor@sysoev.ru 571240Sigor@sysoev.ru if (nxt_pid != process->pid) { 572240Sigor@sysoev.ru process->init = NULL; 573240Sigor@sysoev.ru 574240Sigor@sysoev.ru nxt_process_port_each(process, port) { 575240Sigor@sysoev.ru 576240Sigor@sysoev.ru (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 577240Sigor@sysoev.ru -1, 0, 0, NULL); 578240Sigor@sysoev.ru 579240Sigor@sysoev.ru } nxt_process_port_loop; 580240Sigor@sysoev.ru } 581277Sigor@sysoev.ru 582277Sigor@sysoev.ru } nxt_runtime_process_loop; 583240Sigor@sysoev.ru } 584240Sigor@sysoev.ru 585240Sigor@sysoev.ru 586240Sigor@sysoev.ru 587240Sigor@sysoev.ru static void 588240Sigor@sysoev.ru nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data) 589240Sigor@sysoev.ru { 590240Sigor@sysoev.ru nxt_debug(task, "sigterm handler signo:%d (%s)", 591240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 592240Sigor@sysoev.ru 593240Sigor@sysoev.ru /* TODO: fast exit. */ 594240Sigor@sysoev.ru 595240Sigor@sysoev.ru nxt_exiting = 1; 596240Sigor@sysoev.ru 597240Sigor@sysoev.ru nxt_runtime_quit(task); 598240Sigor@sysoev.ru } 599240Sigor@sysoev.ru 600240Sigor@sysoev.ru 601240Sigor@sysoev.ru static void 602240Sigor@sysoev.ru nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data) 603240Sigor@sysoev.ru { 604240Sigor@sysoev.ru nxt_debug(task, "sigquit handler signo:%d (%s)", 605240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 606240Sigor@sysoev.ru 607240Sigor@sysoev.ru /* TODO: graceful exit. */ 608240Sigor@sysoev.ru 609240Sigor@sysoev.ru nxt_exiting = 1; 610240Sigor@sysoev.ru 611240Sigor@sysoev.ru nxt_runtime_quit(task); 612240Sigor@sysoev.ru } 613240Sigor@sysoev.ru 614240Sigor@sysoev.ru 615240Sigor@sysoev.ru static void 616240Sigor@sysoev.ru nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data) 617240Sigor@sysoev.ru { 618240Sigor@sysoev.ru nxt_mp_t *mp; 619240Sigor@sysoev.ru nxt_int_t ret; 620240Sigor@sysoev.ru nxt_uint_t n; 621240Sigor@sysoev.ru nxt_file_t *file, *new_file; 622240Sigor@sysoev.ru nxt_runtime_t *rt; 623240Sigor@sysoev.ru nxt_array_t *new_files; 624240Sigor@sysoev.ru 625240Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s", 626240Sigor@sysoev.ru (int) (uintptr_t) obj, data, "log files rotation"); 627240Sigor@sysoev.ru 628240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 629240Sigor@sysoev.ru if (mp == NULL) { 630240Sigor@sysoev.ru return; 631240Sigor@sysoev.ru } 632240Sigor@sysoev.ru 633240Sigor@sysoev.ru rt = task->thread->runtime; 634240Sigor@sysoev.ru 635240Sigor@sysoev.ru n = nxt_list_nelts(rt->log_files); 636240Sigor@sysoev.ru 637240Sigor@sysoev.ru new_files = nxt_array_create(mp, n, sizeof(nxt_file_t)); 638240Sigor@sysoev.ru if (new_files == NULL) { 639240Sigor@sysoev.ru nxt_mp_destroy(mp); 640240Sigor@sysoev.ru return; 641240Sigor@sysoev.ru } 642240Sigor@sysoev.ru 643240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 644240Sigor@sysoev.ru 645240Sigor@sysoev.ru /* This allocation cannot fail. */ 646240Sigor@sysoev.ru new_file = nxt_array_add(new_files); 647240Sigor@sysoev.ru 648240Sigor@sysoev.ru new_file->name = file->name; 649240Sigor@sysoev.ru new_file->fd = NXT_FILE_INVALID; 650240Sigor@sysoev.ru new_file->log_level = NXT_LOG_CRIT; 651240Sigor@sysoev.ru 652240Sigor@sysoev.ru ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT, 653240Sigor@sysoev.ru NXT_FILE_OWNER_ACCESS); 654240Sigor@sysoev.ru 655240Sigor@sysoev.ru if (ret != NXT_OK) { 656240Sigor@sysoev.ru goto fail; 657240Sigor@sysoev.ru } 658240Sigor@sysoev.ru 659240Sigor@sysoev.ru } nxt_list_loop; 660240Sigor@sysoev.ru 661240Sigor@sysoev.ru new_file = new_files->elts; 662240Sigor@sysoev.ru 663240Sigor@sysoev.ru ret = nxt_file_stderr(&new_file[0]); 664240Sigor@sysoev.ru 665240Sigor@sysoev.ru if (ret == NXT_OK) { 666240Sigor@sysoev.ru n = 0; 667240Sigor@sysoev.ru 668240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 669240Sigor@sysoev.ru 670240Sigor@sysoev.ru nxt_port_change_log_file(task, rt, n, new_file[n].fd); 671240Sigor@sysoev.ru /* 672240Sigor@sysoev.ru * The old log file descriptor must be closed at the moment 673240Sigor@sysoev.ru * when no other threads use it. dup2() allows to use the 674240Sigor@sysoev.ru * old file descriptor for new log file. This change is 675240Sigor@sysoev.ru * performed atomically in the kernel. 676240Sigor@sysoev.ru */ 677240Sigor@sysoev.ru (void) nxt_file_redirect(file, new_file[n].fd); 678240Sigor@sysoev.ru 679240Sigor@sysoev.ru n++; 680240Sigor@sysoev.ru 681240Sigor@sysoev.ru } nxt_list_loop; 682240Sigor@sysoev.ru 683240Sigor@sysoev.ru nxt_mp_destroy(mp); 684240Sigor@sysoev.ru return; 685240Sigor@sysoev.ru } 686240Sigor@sysoev.ru 687240Sigor@sysoev.ru fail: 688240Sigor@sysoev.ru 689240Sigor@sysoev.ru new_file = new_files->elts; 690240Sigor@sysoev.ru n = new_files->nelts; 691240Sigor@sysoev.ru 692240Sigor@sysoev.ru while (n != 0) { 693240Sigor@sysoev.ru if (new_file->fd != NXT_FILE_INVALID) { 694240Sigor@sysoev.ru nxt_file_close(task, new_file); 695240Sigor@sysoev.ru } 696240Sigor@sysoev.ru 697240Sigor@sysoev.ru new_file++; 698240Sigor@sysoev.ru n--; 699240Sigor@sysoev.ru } 700240Sigor@sysoev.ru 701240Sigor@sysoev.ru nxt_mp_destroy(mp); 702240Sigor@sysoev.ru } 703240Sigor@sysoev.ru 704240Sigor@sysoev.ru 705240Sigor@sysoev.ru static void 706240Sigor@sysoev.ru nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data) 707240Sigor@sysoev.ru { 708240Sigor@sysoev.ru int status; 709240Sigor@sysoev.ru nxt_err_t err; 710240Sigor@sysoev.ru nxt_pid_t pid; 711240Sigor@sysoev.ru 712240Sigor@sysoev.ru nxt_debug(task, "sigchld handler signo:%d (%s)", 713240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 714240Sigor@sysoev.ru 715240Sigor@sysoev.ru for ( ;; ) { 716240Sigor@sysoev.ru pid = waitpid(-1, &status, WNOHANG); 717240Sigor@sysoev.ru 718240Sigor@sysoev.ru if (pid == -1) { 719240Sigor@sysoev.ru 720240Sigor@sysoev.ru switch (err = nxt_errno) { 721240Sigor@sysoev.ru 722240Sigor@sysoev.ru case NXT_ECHILD: 723240Sigor@sysoev.ru return; 724240Sigor@sysoev.ru 725240Sigor@sysoev.ru case NXT_EINTR: 726240Sigor@sysoev.ru continue; 727240Sigor@sysoev.ru 728240Sigor@sysoev.ru default: 729240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "waitpid() failed: %E", err); 730240Sigor@sysoev.ru return; 731240Sigor@sysoev.ru } 732240Sigor@sysoev.ru } 733240Sigor@sysoev.ru 734240Sigor@sysoev.ru nxt_debug(task, "waitpid(): %PI", pid); 735240Sigor@sysoev.ru 736240Sigor@sysoev.ru if (pid == 0) { 737240Sigor@sysoev.ru return; 738240Sigor@sysoev.ru } 739240Sigor@sysoev.ru 740240Sigor@sysoev.ru if (WTERMSIG(status)) { 741240Sigor@sysoev.ru #ifdef WCOREDUMP 742240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d%s", 743240Sigor@sysoev.ru pid, WTERMSIG(status), 744240Sigor@sysoev.ru WCOREDUMP(status) ? " (core dumped)" : ""); 745240Sigor@sysoev.ru #else 746240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d", 747240Sigor@sysoev.ru pid, WTERMSIG(status)); 748240Sigor@sysoev.ru #endif 749240Sigor@sysoev.ru 750240Sigor@sysoev.ru } else { 751240Sigor@sysoev.ru nxt_trace(task, "process %PI exited with code %d", 752240Sigor@sysoev.ru pid, WEXITSTATUS(status)); 753240Sigor@sysoev.ru } 754240Sigor@sysoev.ru 755240Sigor@sysoev.ru nxt_main_cleanup_worker_process(task, pid); 756240Sigor@sysoev.ru } 757240Sigor@sysoev.ru } 758240Sigor@sysoev.ru 759240Sigor@sysoev.ru 760240Sigor@sysoev.ru static void 761240Sigor@sysoev.ru nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid) 762240Sigor@sysoev.ru { 763240Sigor@sysoev.ru nxt_buf_t *buf; 764240Sigor@sysoev.ru nxt_port_t *port; 765240Sigor@sysoev.ru nxt_runtime_t *rt; 766240Sigor@sysoev.ru nxt_process_t *process; 767240Sigor@sysoev.ru nxt_process_init_t *init; 768240Sigor@sysoev.ru 769240Sigor@sysoev.ru rt = task->thread->runtime; 770240Sigor@sysoev.ru 771240Sigor@sysoev.ru process = nxt_runtime_process_find(rt, pid); 772240Sigor@sysoev.ru 773240Sigor@sysoev.ru if (process) { 774240Sigor@sysoev.ru init = process->init; 775240Sigor@sysoev.ru 776349Smax.romanov@nginx.com nxt_process_close_ports(task, process); 777240Sigor@sysoev.ru 778240Sigor@sysoev.ru if (!nxt_exiting) { 779277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 780277Sigor@sysoev.ru 781277Sigor@sysoev.ru if (process->pid == nxt_pid 782277Sigor@sysoev.ru || process->pid == pid 783277Sigor@sysoev.ru || nxt_queue_is_empty(&process->ports)) 784277Sigor@sysoev.ru { 785240Sigor@sysoev.ru continue; 786240Sigor@sysoev.ru } 787240Sigor@sysoev.ru 788240Sigor@sysoev.ru port = nxt_process_port_first(process); 789240Sigor@sysoev.ru 790342Smax.romanov@nginx.com buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 791342Smax.romanov@nginx.com sizeof(pid)); 792240Sigor@sysoev.ru buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid)); 793240Sigor@sysoev.ru 794240Sigor@sysoev.ru nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, 795240Sigor@sysoev.ru -1, init->stream, 0, buf); 796277Sigor@sysoev.ru } nxt_runtime_process_loop; 797240Sigor@sysoev.ru } 798240Sigor@sysoev.ru 799240Sigor@sysoev.ru if (nxt_exiting) { 800240Sigor@sysoev.ru 801240Sigor@sysoev.ru if (rt->nprocesses == 2) { 802240Sigor@sysoev.ru nxt_runtime_quit(task); 803240Sigor@sysoev.ru } 804240Sigor@sysoev.ru 805240Sigor@sysoev.ru } else if (init != NULL) { 806240Sigor@sysoev.ru if (init->restart != 0) { 807240Sigor@sysoev.ru (void) nxt_main_create_worker_process(task, rt, init); 808240Sigor@sysoev.ru 809240Sigor@sysoev.ru } else { 810240Sigor@sysoev.ru nxt_free(init); 811240Sigor@sysoev.ru } 812240Sigor@sysoev.ru } 813240Sigor@sysoev.ru } 814240Sigor@sysoev.ru } 815240Sigor@sysoev.ru 816240Sigor@sysoev.ru 817240Sigor@sysoev.ru static void 818240Sigor@sysoev.ru nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 819240Sigor@sysoev.ru { 820240Sigor@sysoev.ru size_t size; 821240Sigor@sysoev.ru nxt_int_t ret; 822240Sigor@sysoev.ru nxt_buf_t *b, *out; 823240Sigor@sysoev.ru nxt_port_t *port; 824240Sigor@sysoev.ru nxt_sockaddr_t *sa; 825240Sigor@sysoev.ru nxt_port_msg_type_t type; 826240Sigor@sysoev.ru nxt_listening_socket_t ls; 827240Sigor@sysoev.ru u_char message[2048]; 828240Sigor@sysoev.ru 829240Sigor@sysoev.ru b = msg->buf; 830240Sigor@sysoev.ru sa = (nxt_sockaddr_t *) b->mem.pos; 831240Sigor@sysoev.ru 832*352Smax.romanov@nginx.com /* TODO check b size and make plain */ 833*352Smax.romanov@nginx.com 834240Sigor@sysoev.ru out = NULL; 835240Sigor@sysoev.ru 836240Sigor@sysoev.ru ls.socket = -1; 837240Sigor@sysoev.ru ls.error = NXT_SOCKET_ERROR_SYSTEM; 838240Sigor@sysoev.ru ls.start = message; 839240Sigor@sysoev.ru ls.end = message + sizeof(message); 840240Sigor@sysoev.ru 841240Sigor@sysoev.ru port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 842240Sigor@sysoev.ru msg->port_msg.reply_port); 843240Sigor@sysoev.ru 844240Sigor@sysoev.ru nxt_debug(task, "listening socket \"%*s\"", 845240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 846240Sigor@sysoev.ru 847240Sigor@sysoev.ru ret = nxt_main_listening_socket(sa, &ls); 848240Sigor@sysoev.ru 849240Sigor@sysoev.ru if (ret == NXT_OK) { 850240Sigor@sysoev.ru nxt_debug(task, "socket(\"%*s\"): %d", 851240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), ls.socket); 852240Sigor@sysoev.ru 853240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 854240Sigor@sysoev.ru 855240Sigor@sysoev.ru } else { 856240Sigor@sysoev.ru size = ls.end - ls.start; 857240Sigor@sysoev.ru 858240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "%*s", size, ls.start); 859240Sigor@sysoev.ru 860342Smax.romanov@nginx.com out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 861342Smax.romanov@nginx.com size + 1); 862240Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 863240Sigor@sysoev.ru return; 864240Sigor@sysoev.ru } 865240Sigor@sysoev.ru 866240Sigor@sysoev.ru *out->mem.free++ = (uint8_t) ls.error; 867240Sigor@sysoev.ru 868240Sigor@sysoev.ru out->mem.free = nxt_cpymem(out->mem.free, ls.start, size); 869240Sigor@sysoev.ru 870240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_ERROR; 871240Sigor@sysoev.ru } 872240Sigor@sysoev.ru 873240Sigor@sysoev.ru nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream, 874240Sigor@sysoev.ru 0, out); 875240Sigor@sysoev.ru } 876240Sigor@sysoev.ru 877240Sigor@sysoev.ru 878240Sigor@sysoev.ru static nxt_int_t 879240Sigor@sysoev.ru nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls) 880240Sigor@sysoev.ru { 881240Sigor@sysoev.ru nxt_err_t err; 882240Sigor@sysoev.ru nxt_socket_t s; 883240Sigor@sysoev.ru 884240Sigor@sysoev.ru const socklen_t length = sizeof(int); 885240Sigor@sysoev.ru static const int enable = 1; 886240Sigor@sysoev.ru 887240Sigor@sysoev.ru s = socket(sa->u.sockaddr.sa_family, sa->type, 0); 888240Sigor@sysoev.ru 889240Sigor@sysoev.ru if (nxt_slow_path(s == -1)) { 890240Sigor@sysoev.ru err = nxt_errno; 891240Sigor@sysoev.ru 892240Sigor@sysoev.ru #if (NXT_INET6) 893240Sigor@sysoev.ru 894240Sigor@sysoev.ru if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) { 895240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOINET6; 896240Sigor@sysoev.ru } 897240Sigor@sysoev.ru 898240Sigor@sysoev.ru #endif 899240Sigor@sysoev.ru 900240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 901240Sigor@sysoev.ru "socket(\\\"%*s\\\") failed %E", 902240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 903240Sigor@sysoev.ru 904240Sigor@sysoev.ru return NXT_ERROR; 905240Sigor@sysoev.ru } 906240Sigor@sysoev.ru 907240Sigor@sysoev.ru if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) { 908240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 909240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E", 910240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 911240Sigor@sysoev.ru goto fail; 912240Sigor@sysoev.ru } 913240Sigor@sysoev.ru 914240Sigor@sysoev.ru #if (NXT_INET6) 915240Sigor@sysoev.ru 916240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_INET6) { 917240Sigor@sysoev.ru 918240Sigor@sysoev.ru if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) { 919240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 920240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E", 921240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 922240Sigor@sysoev.ru goto fail; 923240Sigor@sysoev.ru } 924240Sigor@sysoev.ru } 925240Sigor@sysoev.ru 926240Sigor@sysoev.ru #endif 927240Sigor@sysoev.ru 928240Sigor@sysoev.ru if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) { 929240Sigor@sysoev.ru err = nxt_errno; 930240Sigor@sysoev.ru 931240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 932240Sigor@sysoev.ru 933240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 934240Sigor@sysoev.ru switch (err) { 935240Sigor@sysoev.ru 936240Sigor@sysoev.ru case EACCES: 937240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_ACCESS; 938240Sigor@sysoev.ru break; 939240Sigor@sysoev.ru 940240Sigor@sysoev.ru case ENOENT: 941240Sigor@sysoev.ru case ENOTDIR: 942240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PATH; 943240Sigor@sysoev.ru break; 944240Sigor@sysoev.ru } 945240Sigor@sysoev.ru 946240Sigor@sysoev.ru goto next; 947240Sigor@sysoev.ru } 948240Sigor@sysoev.ru 949240Sigor@sysoev.ru #endif 950240Sigor@sysoev.ru 951240Sigor@sysoev.ru switch (err) { 952240Sigor@sysoev.ru 953240Sigor@sysoev.ru case EACCES: 954240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PORT; 955240Sigor@sysoev.ru break; 956240Sigor@sysoev.ru 957240Sigor@sysoev.ru case EADDRINUSE: 958240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_INUSE; 959240Sigor@sysoev.ru break; 960240Sigor@sysoev.ru 961240Sigor@sysoev.ru case EADDRNOTAVAIL: 962240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOADDR; 963240Sigor@sysoev.ru break; 964240Sigor@sysoev.ru } 965240Sigor@sysoev.ru 966240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E", 967240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 968240Sigor@sysoev.ru goto fail; 969240Sigor@sysoev.ru } 970240Sigor@sysoev.ru 971240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 972240Sigor@sysoev.ru 973240Sigor@sysoev.ru next: 974240Sigor@sysoev.ru 975240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 976240Sigor@sysoev.ru char *filename; 977240Sigor@sysoev.ru mode_t access; 978240Sigor@sysoev.ru 979240Sigor@sysoev.ru filename = sa->u.sockaddr_un.sun_path; 980240Sigor@sysoev.ru access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 981240Sigor@sysoev.ru 982240Sigor@sysoev.ru if (chmod(filename, access) != 0) { 983240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 984240Sigor@sysoev.ru "chmod(\\\"%*s\\\") failed %E", 985240Sigor@sysoev.ru filename, nxt_errno); 986240Sigor@sysoev.ru goto fail; 987240Sigor@sysoev.ru } 988240Sigor@sysoev.ru } 989240Sigor@sysoev.ru 990240Sigor@sysoev.ru #endif 991240Sigor@sysoev.ru 992240Sigor@sysoev.ru ls->socket = s; 993240Sigor@sysoev.ru 994240Sigor@sysoev.ru return NXT_OK; 995240Sigor@sysoev.ru 996240Sigor@sysoev.ru fail: 997240Sigor@sysoev.ru 998240Sigor@sysoev.ru (void) close(s); 999240Sigor@sysoev.ru 1000240Sigor@sysoev.ru return NXT_ERROR; 1001240Sigor@sysoev.ru } 1002240Sigor@sysoev.ru 1003240Sigor@sysoev.ru 1004240Sigor@sysoev.ru static nxt_conf_map_t nxt_app_lang_module_map[] = { 1005240Sigor@sysoev.ru { 1006240Sigor@sysoev.ru nxt_string("type"), 1007240Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1008240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, type), 1009240Sigor@sysoev.ru }, 1010240Sigor@sysoev.ru 1011240Sigor@sysoev.ru { 1012240Sigor@sysoev.ru nxt_string("version"), 1013240Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1014240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, version), 1015240Sigor@sysoev.ru }, 1016240Sigor@sysoev.ru 1017240Sigor@sysoev.ru { 1018240Sigor@sysoev.ru nxt_string("file"), 1019240Sigor@sysoev.ru NXT_CONF_MAP_CSTRZ, 1020240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, file), 1021240Sigor@sysoev.ru }, 1022240Sigor@sysoev.ru }; 1023240Sigor@sysoev.ru 1024240Sigor@sysoev.ru 1025240Sigor@sysoev.ru static void 1026240Sigor@sysoev.ru nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1027240Sigor@sysoev.ru { 1028240Sigor@sysoev.ru uint32_t index; 1029240Sigor@sysoev.ru nxt_mp_t *mp; 1030240Sigor@sysoev.ru nxt_int_t ret; 1031240Sigor@sysoev.ru nxt_buf_t *b; 1032240Sigor@sysoev.ru nxt_runtime_t *rt; 1033240Sigor@sysoev.ru nxt_conf_value_t *conf, *root, *value; 1034240Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1035240Sigor@sysoev.ru 1036240Sigor@sysoev.ru static nxt_str_t root_path = nxt_string("/"); 1037240Sigor@sysoev.ru 1038240Sigor@sysoev.ru rt = task->thread->runtime; 1039240Sigor@sysoev.ru 1040240Sigor@sysoev.ru if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) { 1041240Sigor@sysoev.ru return; 1042240Sigor@sysoev.ru } 1043240Sigor@sysoev.ru 1044240Sigor@sysoev.ru b = msg->buf; 1045240Sigor@sysoev.ru 1046240Sigor@sysoev.ru if (b == NULL) { 1047240Sigor@sysoev.ru return; 1048240Sigor@sysoev.ru } 1049240Sigor@sysoev.ru 1050240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 1051240Sigor@sysoev.ru if (mp == NULL) { 1052240Sigor@sysoev.ru return; 1053240Sigor@sysoev.ru } 1054240Sigor@sysoev.ru 1055*352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(mp, b, msg->size); 1056*352Smax.romanov@nginx.com 1057*352Smax.romanov@nginx.com if (b == NULL) { 1058*352Smax.romanov@nginx.com return; 1059*352Smax.romanov@nginx.com } 1060*352Smax.romanov@nginx.com 1061*352Smax.romanov@nginx.com nxt_debug(task, "application languages: \"%*s\"", 1062*352Smax.romanov@nginx.com b->mem.free - b->mem.pos, b->mem.pos); 1063*352Smax.romanov@nginx.com 1064240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL); 1065240Sigor@sysoev.ru if (conf == NULL) { 1066240Sigor@sysoev.ru goto fail; 1067240Sigor@sysoev.ru } 1068240Sigor@sysoev.ru 1069240Sigor@sysoev.ru root = nxt_conf_get_path(conf, &root_path); 1070240Sigor@sysoev.ru if (root == NULL) { 1071240Sigor@sysoev.ru goto fail; 1072240Sigor@sysoev.ru } 1073240Sigor@sysoev.ru 1074240Sigor@sysoev.ru for (index = 0; /* void */ ; index++) { 1075240Sigor@sysoev.ru value = nxt_conf_get_array_element(root, index); 1076240Sigor@sysoev.ru if (value == NULL) { 1077240Sigor@sysoev.ru break; 1078240Sigor@sysoev.ru } 1079240Sigor@sysoev.ru 1080240Sigor@sysoev.ru lang = nxt_array_add(rt->languages); 1081240Sigor@sysoev.ru if (lang == NULL) { 1082240Sigor@sysoev.ru goto fail; 1083240Sigor@sysoev.ru } 1084240Sigor@sysoev.ru 1085240Sigor@sysoev.ru lang->module = NULL; 1086240Sigor@sysoev.ru 1087240Sigor@sysoev.ru ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map, 1088240Sigor@sysoev.ru nxt_nitems(nxt_app_lang_module_map), lang); 1089240Sigor@sysoev.ru 1090240Sigor@sysoev.ru if (ret != NXT_OK) { 1091240Sigor@sysoev.ru goto fail; 1092240Sigor@sysoev.ru } 1093240Sigor@sysoev.ru 1094240Sigor@sysoev.ru nxt_debug(task, "lang %V %V \"%s\"", 1095240Sigor@sysoev.ru &lang->type, &lang->version, lang->file); 1096240Sigor@sysoev.ru } 1097240Sigor@sysoev.ru 1098240Sigor@sysoev.ru qsort(rt->languages->elts, rt->languages->nelts, 1099240Sigor@sysoev.ru sizeof(nxt_app_lang_module_t), nxt_app_lang_compare); 1100240Sigor@sysoev.ru 1101240Sigor@sysoev.ru fail: 1102240Sigor@sysoev.ru 1103240Sigor@sysoev.ru nxt_mp_destroy(mp); 1104240Sigor@sysoev.ru 1105240Sigor@sysoev.ru ret = nxt_main_start_controller_process(task, rt); 1106240Sigor@sysoev.ru 1107240Sigor@sysoev.ru if (ret == NXT_OK) { 1108240Sigor@sysoev.ru (void) nxt_main_start_router_process(task, rt); 1109240Sigor@sysoev.ru } 1110240Sigor@sysoev.ru } 1111240Sigor@sysoev.ru 1112240Sigor@sysoev.ru 1113240Sigor@sysoev.ru static int nxt_cdecl 1114240Sigor@sysoev.ru nxt_app_lang_compare(const void *v1, const void *v2) 1115240Sigor@sysoev.ru { 1116240Sigor@sysoev.ru int n; 1117240Sigor@sysoev.ru size_t length; 1118240Sigor@sysoev.ru const nxt_app_lang_module_t *lang1, *lang2; 1119240Sigor@sysoev.ru 1120240Sigor@sysoev.ru lang1 = v1; 1121240Sigor@sysoev.ru lang2 = v2; 1122240Sigor@sysoev.ru 1123258Sigor@sysoev.ru if (lang1->type.length != lang2->type.length) { 1124258Sigor@sysoev.ru return lang1->type.length - lang2->type.length; 1125258Sigor@sysoev.ru } 1126258Sigor@sysoev.ru 1127258Sigor@sysoev.ru n = nxt_strncmp(lang1->type.start, lang2->type.start, lang1->type.length); 1128258Sigor@sysoev.ru 1129258Sigor@sysoev.ru if (n != 0) { 1130258Sigor@sysoev.ru return n; 1131258Sigor@sysoev.ru } 1132258Sigor@sysoev.ru 1133240Sigor@sysoev.ru length = nxt_min(lang1->version.length, lang2->version.length); 1134240Sigor@sysoev.ru 1135240Sigor@sysoev.ru n = nxt_strncmp(lang1->version.start, lang2->version.start, length); 1136240Sigor@sysoev.ru 1137240Sigor@sysoev.ru if (n == 0) { 1138240Sigor@sysoev.ru n = lang1->version.length - lang2->version.length; 1139240Sigor@sysoev.ru } 1140240Sigor@sysoev.ru 1141240Sigor@sysoev.ru /* Negate result to move higher versions to the beginning. */ 1142240Sigor@sysoev.ru 1143240Sigor@sysoev.ru return -n; 1144240Sigor@sysoev.ru } 1145314Svbart@nginx.com 1146314Svbart@nginx.com 1147314Svbart@nginx.com static void 1148314Svbart@nginx.com nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1149314Svbart@nginx.com { 1150*352Smax.romanov@nginx.com ssize_t n, size, offset; 1151314Svbart@nginx.com nxt_buf_t *b; 1152314Svbart@nginx.com nxt_int_t ret; 1153314Svbart@nginx.com nxt_file_t file; 1154314Svbart@nginx.com nxt_runtime_t *rt; 1155314Svbart@nginx.com 1156314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 1157314Svbart@nginx.com 1158314Svbart@nginx.com rt = task->thread->runtime; 1159314Svbart@nginx.com 1160314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf_tmp; 1161314Svbart@nginx.com 1162314Svbart@nginx.com if (nxt_slow_path(nxt_file_open(task, &file, NXT_FILE_WRONLY, 1163314Svbart@nginx.com NXT_FILE_TRUNCATE, NXT_FILE_OWNER_ACCESS) 1164314Svbart@nginx.com != NXT_OK)) 1165314Svbart@nginx.com { 1166314Svbart@nginx.com goto error; 1167314Svbart@nginx.com } 1168314Svbart@nginx.com 1169*352Smax.romanov@nginx.com offset = 0; 1170*352Smax.romanov@nginx.com 1171314Svbart@nginx.com for (b = msg->buf; b != NULL; b = b->next) { 1172314Svbart@nginx.com size = nxt_buf_mem_used_size(&b->mem); 1173314Svbart@nginx.com 1174*352Smax.romanov@nginx.com n = nxt_file_write(&file, b->mem.pos, size, offset); 1175314Svbart@nginx.com 1176314Svbart@nginx.com if (nxt_slow_path(n != size)) { 1177314Svbart@nginx.com nxt_file_close(task, &file); 1178314Svbart@nginx.com (void) nxt_file_delete(file.name); 1179314Svbart@nginx.com goto error; 1180314Svbart@nginx.com } 1181*352Smax.romanov@nginx.com 1182*352Smax.romanov@nginx.com offset += n; 1183314Svbart@nginx.com } 1184314Svbart@nginx.com 1185314Svbart@nginx.com nxt_file_close(task, &file); 1186314Svbart@nginx.com 1187314Svbart@nginx.com ret = nxt_file_rename(file.name, (nxt_file_name_t *) rt->conf); 1188314Svbart@nginx.com 1189314Svbart@nginx.com if (nxt_fast_path(ret == NXT_OK)) { 1190314Svbart@nginx.com return; 1191314Svbart@nginx.com } 1192314Svbart@nginx.com 1193314Svbart@nginx.com error: 1194314Svbart@nginx.com 1195314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, "failed to store current configuration"); 1196314Svbart@nginx.com } 1197