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; 174*318Smax.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 180*318Smax.romanov@nginx.com ret = NXT_ERROR; 181*318Smax.romanov@nginx.com 182240Sigor@sysoev.ru b = msg->buf; 183240Sigor@sysoev.ru 184240Sigor@sysoev.ru nxt_debug(task, "main start worker: %*s", b->mem.free - b->mem.pos, 185240Sigor@sysoev.ru b->mem.pos); 186240Sigor@sysoev.ru 187240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 188240Sigor@sysoev.ru 189240Sigor@sysoev.ru nxt_memzero(&app_conf, sizeof(nxt_common_app_conf_t)); 190240Sigor@sysoev.ru 191240Sigor@sysoev.ru start = b->mem.pos; 192240Sigor@sysoev.ru 193240Sigor@sysoev.ru app_conf.name.start = start; 194240Sigor@sysoev.ru app_conf.name.length = nxt_strlen(start); 195240Sigor@sysoev.ru 196240Sigor@sysoev.ru start += app_conf.name.length + 1; 197240Sigor@sysoev.ru 198240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, start, b->mem.free, NULL); 199240Sigor@sysoev.ru 200240Sigor@sysoev.ru if (conf == NULL) { 201240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 202*318Smax.romanov@nginx.com 203*318Smax.romanov@nginx.com goto failed; 204240Sigor@sysoev.ru } 205240Sigor@sysoev.ru 206240Sigor@sysoev.ru app_conf.user = nobody; 207240Sigor@sysoev.ru 208240Sigor@sysoev.ru ret = nxt_conf_map_object(mp, conf, nxt_common_app_conf, 209240Sigor@sysoev.ru nxt_nitems(nxt_common_app_conf), &app_conf); 210240Sigor@sysoev.ru if (ret != NXT_OK) { 211240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 212*318Smax.romanov@nginx.com 213*318Smax.romanov@nginx.com goto failed; 214240Sigor@sysoev.ru } 215240Sigor@sysoev.ru 216240Sigor@sysoev.ru ret = nxt_main_start_worker_process(task, task->thread->runtime, 217240Sigor@sysoev.ru &app_conf, msg->port_msg.stream); 218240Sigor@sysoev.ru 219*318Smax.romanov@nginx.com failed: 220*318Smax.romanov@nginx.com 221*318Smax.romanov@nginx.com if (ret == NXT_ERROR) { 222*318Smax.romanov@nginx.com port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 223*318Smax.romanov@nginx.com msg->port_msg.reply_port); 224*318Smax.romanov@nginx.com if (nxt_fast_path(port != NULL)) { 225*318Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 226*318Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 227*318Smax.romanov@nginx.com } 228*318Smax.romanov@nginx.com } 229*318Smax.romanov@nginx.com 230240Sigor@sysoev.ru nxt_mp_destroy(mp); 231240Sigor@sysoev.ru } 232240Sigor@sysoev.ru 233240Sigor@sysoev.ru 234240Sigor@sysoev.ru static nxt_port_handler_t nxt_main_process_port_handlers[] = { 235240Sigor@sysoev.ru NULL, /* NXT_PORT_MSG_QUIT */ 236240Sigor@sysoev.ru NULL, /* NXT_PORT_MSG_NEW_PORT */ 237240Sigor@sysoev.ru NULL, /* NXT_PORT_MSG_CHANGE_FILE */ 238240Sigor@sysoev.ru NULL, /* NXT_PORT_MSG_MMAP */ 239240Sigor@sysoev.ru nxt_port_main_data_handler, 240240Sigor@sysoev.ru NULL, /* NXT_PORT_MSG_REMOVE_PID */ 241240Sigor@sysoev.ru nxt_port_ready_handler, 242240Sigor@sysoev.ru nxt_port_main_start_worker_handler, 243240Sigor@sysoev.ru nxt_main_port_socket_handler, 244240Sigor@sysoev.ru nxt_main_port_modules_handler, 245314Svbart@nginx.com nxt_main_port_conf_store_handler, 246240Sigor@sysoev.ru nxt_port_rpc_handler, 247240Sigor@sysoev.ru nxt_port_rpc_handler, 248240Sigor@sysoev.ru }; 249240Sigor@sysoev.ru 250240Sigor@sysoev.ru 251240Sigor@sysoev.ru static nxt_int_t 252240Sigor@sysoev.ru nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt) 253240Sigor@sysoev.ru { 254240Sigor@sysoev.ru nxt_int_t ret; 255240Sigor@sysoev.ru nxt_port_t *port; 256240Sigor@sysoev.ru nxt_process_t *process; 257240Sigor@sysoev.ru 258240Sigor@sysoev.ru process = nxt_runtime_process_get(rt, nxt_pid); 259240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 260240Sigor@sysoev.ru return NXT_ERROR; 261240Sigor@sysoev.ru } 262240Sigor@sysoev.ru 263240Sigor@sysoev.ru port = nxt_port_new(task, 0, nxt_pid, NXT_PROCESS_MAIN); 264240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 265240Sigor@sysoev.ru return NXT_ERROR; 266240Sigor@sysoev.ru } 267240Sigor@sysoev.ru 268240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 269240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 270240Sigor@sysoev.ru return ret; 271240Sigor@sysoev.ru } 272240Sigor@sysoev.ru 273240Sigor@sysoev.ru nxt_process_port_add(task, process, port); 274240Sigor@sysoev.ru 275240Sigor@sysoev.ru nxt_runtime_port_add(rt, port); 276240Sigor@sysoev.ru 277240Sigor@sysoev.ru /* 278240Sigor@sysoev.ru * A main process port. A write port is not closed 279240Sigor@sysoev.ru * since it should be inherited by worker processes. 280240Sigor@sysoev.ru */ 281240Sigor@sysoev.ru nxt_port_enable(task, port, nxt_main_process_port_handlers); 282240Sigor@sysoev.ru 283240Sigor@sysoev.ru process->ready = 1; 284240Sigor@sysoev.ru 285240Sigor@sysoev.ru return NXT_OK; 286240Sigor@sysoev.ru } 287240Sigor@sysoev.ru 288240Sigor@sysoev.ru 289240Sigor@sysoev.ru static void 290240Sigor@sysoev.ru nxt_main_process_title(nxt_task_t *task) 291240Sigor@sysoev.ru { 292240Sigor@sysoev.ru u_char *p, *end; 293240Sigor@sysoev.ru nxt_uint_t i; 294240Sigor@sysoev.ru u_char title[2048]; 295240Sigor@sysoev.ru 296240Sigor@sysoev.ru end = title + sizeof(title) - 1; 297240Sigor@sysoev.ru 298259Sigor@sysoev.ru p = nxt_sprintf(title, end, "unit: main [%s", nxt_process_argv[0]); 299240Sigor@sysoev.ru 300240Sigor@sysoev.ru for (i = 1; nxt_process_argv[i] != NULL; i++) { 301240Sigor@sysoev.ru p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]); 302240Sigor@sysoev.ru } 303240Sigor@sysoev.ru 304240Sigor@sysoev.ru if (p < end) { 305240Sigor@sysoev.ru *p++ = ']'; 306240Sigor@sysoev.ru } 307240Sigor@sysoev.ru 308240Sigor@sysoev.ru *p = '\0'; 309240Sigor@sysoev.ru 310240Sigor@sysoev.ru nxt_process_title(task, "%s", title); 311240Sigor@sysoev.ru } 312240Sigor@sysoev.ru 313240Sigor@sysoev.ru 314240Sigor@sysoev.ru static nxt_int_t 315240Sigor@sysoev.ru nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt) 316240Sigor@sysoev.ru { 317314Svbart@nginx.com ssize_t n; 318314Svbart@nginx.com nxt_int_t ret; 319314Svbart@nginx.com nxt_str_t conf; 320314Svbart@nginx.com nxt_file_t file; 321314Svbart@nginx.com nxt_file_info_t fi; 322240Sigor@sysoev.ru nxt_process_init_t *init; 323240Sigor@sysoev.ru 324314Svbart@nginx.com conf.length = 0; 325314Svbart@nginx.com 326314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 327314Svbart@nginx.com 328314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf; 329314Svbart@nginx.com 330314Svbart@nginx.com if (nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0) == NXT_OK) { 331314Svbart@nginx.com 332314Svbart@nginx.com if (nxt_fast_path(nxt_file_info(&file, &fi) == NXT_OK 333314Svbart@nginx.com && nxt_is_file(&fi))) 334314Svbart@nginx.com { 335314Svbart@nginx.com conf.length = nxt_file_size(&fi); 336314Svbart@nginx.com conf.start = nxt_malloc(conf.length); 337314Svbart@nginx.com 338314Svbart@nginx.com if (nxt_slow_path(conf.start == NULL)) { 339314Svbart@nginx.com nxt_file_close(task, &file); 340314Svbart@nginx.com return NXT_ERROR; 341314Svbart@nginx.com } 342314Svbart@nginx.com 343314Svbart@nginx.com n = nxt_file_read(&file, conf.start, conf.length, 0); 344314Svbart@nginx.com 345314Svbart@nginx.com if (nxt_slow_path(n != (ssize_t) conf.length)) { 346314Svbart@nginx.com conf.length = 0; 347314Svbart@nginx.com nxt_free(conf.start); 348314Svbart@nginx.com 349314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, 350314Svbart@nginx.com "failed to restore previous configuration: " 351314Svbart@nginx.com "cannot read the file"); 352314Svbart@nginx.com } 353314Svbart@nginx.com } 354314Svbart@nginx.com 355314Svbart@nginx.com nxt_file_close(task, &file); 356314Svbart@nginx.com } 357314Svbart@nginx.com 358240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 359240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 360240Sigor@sysoev.ru return NXT_ERROR; 361240Sigor@sysoev.ru } 362240Sigor@sysoev.ru 363240Sigor@sysoev.ru init->start = nxt_controller_start; 364240Sigor@sysoev.ru init->name = "controller"; 365240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 366240Sigor@sysoev.ru init->port_handlers = nxt_controller_process_port_handlers; 367240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 368240Sigor@sysoev.ru init->type = NXT_PROCESS_CONTROLLER; 369314Svbart@nginx.com init->data = &conf; 370240Sigor@sysoev.ru init->stream = 0; 371240Sigor@sysoev.ru init->restart = 1; 372240Sigor@sysoev.ru 373314Svbart@nginx.com ret = nxt_main_create_worker_process(task, rt, init); 374314Svbart@nginx.com 375314Svbart@nginx.com if (ret == NXT_OK && conf.length != 0) { 376314Svbart@nginx.com nxt_free(conf.start); 377314Svbart@nginx.com } 378314Svbart@nginx.com 379314Svbart@nginx.com return ret; 380240Sigor@sysoev.ru } 381240Sigor@sysoev.ru 382240Sigor@sysoev.ru 383240Sigor@sysoev.ru static nxt_int_t 384240Sigor@sysoev.ru nxt_main_start_discovery_process(nxt_task_t *task, nxt_runtime_t *rt) 385240Sigor@sysoev.ru { 386240Sigor@sysoev.ru nxt_process_init_t *init; 387240Sigor@sysoev.ru 388240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 389240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 390240Sigor@sysoev.ru return NXT_ERROR; 391240Sigor@sysoev.ru } 392240Sigor@sysoev.ru 393240Sigor@sysoev.ru init->start = nxt_discovery_start; 394240Sigor@sysoev.ru init->name = "discovery"; 395240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 396240Sigor@sysoev.ru init->port_handlers = nxt_discovery_process_port_handlers; 397240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 398240Sigor@sysoev.ru init->type = NXT_PROCESS_DISCOVERY; 399240Sigor@sysoev.ru init->data = rt; 400240Sigor@sysoev.ru init->stream = 0; 401240Sigor@sysoev.ru init->restart = 0; 402240Sigor@sysoev.ru 403240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 404240Sigor@sysoev.ru } 405240Sigor@sysoev.ru 406240Sigor@sysoev.ru 407240Sigor@sysoev.ru static nxt_int_t 408240Sigor@sysoev.ru nxt_main_start_router_process(nxt_task_t *task, nxt_runtime_t *rt) 409240Sigor@sysoev.ru { 410240Sigor@sysoev.ru nxt_process_init_t *init; 411240Sigor@sysoev.ru 412240Sigor@sysoev.ru init = nxt_malloc(sizeof(nxt_process_init_t)); 413240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 414240Sigor@sysoev.ru return NXT_ERROR; 415240Sigor@sysoev.ru } 416240Sigor@sysoev.ru 417240Sigor@sysoev.ru init->start = nxt_router_start; 418240Sigor@sysoev.ru init->name = "router"; 419240Sigor@sysoev.ru init->user_cred = &rt->user_cred; 420240Sigor@sysoev.ru init->port_handlers = nxt_router_process_port_handlers; 421240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 422240Sigor@sysoev.ru init->type = NXT_PROCESS_ROUTER; 423240Sigor@sysoev.ru init->data = rt; 424240Sigor@sysoev.ru init->stream = 0; 425240Sigor@sysoev.ru init->restart = 1; 426240Sigor@sysoev.ru 427240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 428240Sigor@sysoev.ru } 429240Sigor@sysoev.ru 430240Sigor@sysoev.ru 431240Sigor@sysoev.ru static nxt_int_t 432240Sigor@sysoev.ru nxt_main_start_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 433240Sigor@sysoev.ru nxt_common_app_conf_t *app_conf, uint32_t stream) 434240Sigor@sysoev.ru { 435240Sigor@sysoev.ru char *user, *group; 436240Sigor@sysoev.ru u_char *title, *last, *end; 437240Sigor@sysoev.ru size_t size; 438240Sigor@sysoev.ru nxt_process_init_t *init; 439240Sigor@sysoev.ru 440240Sigor@sysoev.ru size = sizeof(nxt_process_init_t) 441240Sigor@sysoev.ru + sizeof(nxt_user_cred_t) 442240Sigor@sysoev.ru + app_conf->user.length + 1 443240Sigor@sysoev.ru + app_conf->group.length + 1 444240Sigor@sysoev.ru + app_conf->name.length + sizeof("\"\" application"); 445240Sigor@sysoev.ru 446240Sigor@sysoev.ru init = nxt_malloc(size); 447240Sigor@sysoev.ru if (nxt_slow_path(init == NULL)) { 448240Sigor@sysoev.ru return NXT_ERROR; 449240Sigor@sysoev.ru } 450240Sigor@sysoev.ru 451240Sigor@sysoev.ru init->user_cred = nxt_pointer_to(init, sizeof(nxt_process_init_t)); 452240Sigor@sysoev.ru user = nxt_pointer_to(init->user_cred, sizeof(nxt_user_cred_t)); 453240Sigor@sysoev.ru 454240Sigor@sysoev.ru nxt_memcpy(user, app_conf->user.start, app_conf->user.length); 455240Sigor@sysoev.ru last = nxt_pointer_to(user, app_conf->user.length); 456240Sigor@sysoev.ru *last++ = '\0'; 457240Sigor@sysoev.ru 458240Sigor@sysoev.ru init->user_cred->user = user; 459240Sigor@sysoev.ru 460240Sigor@sysoev.ru if (app_conf->group.start != NULL) { 461240Sigor@sysoev.ru group = (char *) last; 462240Sigor@sysoev.ru 463240Sigor@sysoev.ru nxt_memcpy(group, app_conf->group.start, app_conf->group.length); 464240Sigor@sysoev.ru last = nxt_pointer_to(group, app_conf->group.length); 465240Sigor@sysoev.ru *last++ = '\0'; 466240Sigor@sysoev.ru 467240Sigor@sysoev.ru } else { 468240Sigor@sysoev.ru group = NULL; 469240Sigor@sysoev.ru } 470240Sigor@sysoev.ru 471240Sigor@sysoev.ru if (nxt_user_cred_get(task, init->user_cred, group) != NXT_OK) { 472240Sigor@sysoev.ru return NXT_ERROR; 473240Sigor@sysoev.ru } 474240Sigor@sysoev.ru 475240Sigor@sysoev.ru title = last; 476240Sigor@sysoev.ru end = title + app_conf->name.length + sizeof("\"\" application"); 477240Sigor@sysoev.ru 478240Sigor@sysoev.ru nxt_sprintf(title, end, "\"%V\" application%Z", &app_conf->name); 479240Sigor@sysoev.ru 480240Sigor@sysoev.ru init->start = nxt_app_start; 481240Sigor@sysoev.ru init->name = (char *) title; 482240Sigor@sysoev.ru init->port_handlers = nxt_app_process_port_handlers; 483240Sigor@sysoev.ru init->signals = nxt_worker_process_signals; 484240Sigor@sysoev.ru init->type = NXT_PROCESS_WORKER; 485240Sigor@sysoev.ru init->data = app_conf; 486240Sigor@sysoev.ru init->stream = stream; 487240Sigor@sysoev.ru init->restart = 0; 488240Sigor@sysoev.ru 489240Sigor@sysoev.ru return nxt_main_create_worker_process(task, rt, init); 490240Sigor@sysoev.ru } 491240Sigor@sysoev.ru 492240Sigor@sysoev.ru 493240Sigor@sysoev.ru static nxt_int_t 494240Sigor@sysoev.ru nxt_main_create_worker_process(nxt_task_t *task, nxt_runtime_t *rt, 495240Sigor@sysoev.ru nxt_process_init_t *init) 496240Sigor@sysoev.ru { 497240Sigor@sysoev.ru nxt_int_t ret; 498240Sigor@sysoev.ru nxt_pid_t pid; 499240Sigor@sysoev.ru nxt_port_t *port; 500240Sigor@sysoev.ru nxt_process_t *process; 501240Sigor@sysoev.ru 502240Sigor@sysoev.ru /* 503240Sigor@sysoev.ru * TODO: remove process, init, ports from array on memory and fork failures. 504240Sigor@sysoev.ru */ 505240Sigor@sysoev.ru 506240Sigor@sysoev.ru process = nxt_runtime_process_new(rt); 507240Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 508240Sigor@sysoev.ru return NXT_ERROR; 509240Sigor@sysoev.ru } 510240Sigor@sysoev.ru 511240Sigor@sysoev.ru process->init = init; 512240Sigor@sysoev.ru 513240Sigor@sysoev.ru port = nxt_port_new(task, 0, 0, init->type); 514240Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 515240Sigor@sysoev.ru nxt_runtime_process_remove(rt, process); 516240Sigor@sysoev.ru return NXT_ERROR; 517240Sigor@sysoev.ru } 518240Sigor@sysoev.ru 519240Sigor@sysoev.ru nxt_process_port_add(task, process, port); 520240Sigor@sysoev.ru 521240Sigor@sysoev.ru ret = nxt_port_socket_init(task, port, 0); 522240Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 523240Sigor@sysoev.ru nxt_mp_release(port->mem_pool, port); 524240Sigor@sysoev.ru return ret; 525240Sigor@sysoev.ru } 526240Sigor@sysoev.ru 527240Sigor@sysoev.ru pid = nxt_process_create(task, process); 528240Sigor@sysoev.ru 529240Sigor@sysoev.ru switch (pid) { 530240Sigor@sysoev.ru 531240Sigor@sysoev.ru case -1: 532240Sigor@sysoev.ru return NXT_ERROR; 533240Sigor@sysoev.ru 534240Sigor@sysoev.ru case 0: 535240Sigor@sysoev.ru /* A worker process, return to the event engine work queue loop. */ 536240Sigor@sysoev.ru return NXT_AGAIN; 537240Sigor@sysoev.ru 538240Sigor@sysoev.ru default: 539240Sigor@sysoev.ru /* The main process created a new process. */ 540240Sigor@sysoev.ru 541240Sigor@sysoev.ru nxt_port_read_close(port); 542240Sigor@sysoev.ru nxt_port_write_enable(task, port); 543240Sigor@sysoev.ru 544240Sigor@sysoev.ru return NXT_OK; 545240Sigor@sysoev.ru } 546240Sigor@sysoev.ru } 547240Sigor@sysoev.ru 548240Sigor@sysoev.ru 549240Sigor@sysoev.ru void 550240Sigor@sysoev.ru nxt_main_stop_worker_processes(nxt_task_t *task, nxt_runtime_t *rt) 551240Sigor@sysoev.ru { 552240Sigor@sysoev.ru nxt_port_t *port; 553240Sigor@sysoev.ru nxt_process_t *process; 554240Sigor@sysoev.ru 555277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 556277Sigor@sysoev.ru 557240Sigor@sysoev.ru if (nxt_pid != process->pid) { 558240Sigor@sysoev.ru process->init = NULL; 559240Sigor@sysoev.ru 560240Sigor@sysoev.ru nxt_process_port_each(process, port) { 561240Sigor@sysoev.ru 562240Sigor@sysoev.ru (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 563240Sigor@sysoev.ru -1, 0, 0, NULL); 564240Sigor@sysoev.ru 565240Sigor@sysoev.ru } nxt_process_port_loop; 566240Sigor@sysoev.ru } 567277Sigor@sysoev.ru 568277Sigor@sysoev.ru } nxt_runtime_process_loop; 569240Sigor@sysoev.ru } 570240Sigor@sysoev.ru 571240Sigor@sysoev.ru 572240Sigor@sysoev.ru 573240Sigor@sysoev.ru static void 574240Sigor@sysoev.ru nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data) 575240Sigor@sysoev.ru { 576240Sigor@sysoev.ru nxt_debug(task, "sigterm handler signo:%d (%s)", 577240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 578240Sigor@sysoev.ru 579240Sigor@sysoev.ru /* TODO: fast exit. */ 580240Sigor@sysoev.ru 581240Sigor@sysoev.ru nxt_exiting = 1; 582240Sigor@sysoev.ru 583240Sigor@sysoev.ru nxt_runtime_quit(task); 584240Sigor@sysoev.ru } 585240Sigor@sysoev.ru 586240Sigor@sysoev.ru 587240Sigor@sysoev.ru static void 588240Sigor@sysoev.ru nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data) 589240Sigor@sysoev.ru { 590240Sigor@sysoev.ru nxt_debug(task, "sigquit handler signo:%d (%s)", 591240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 592240Sigor@sysoev.ru 593240Sigor@sysoev.ru /* TODO: graceful 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_sigusr1_handler(nxt_task_t *task, void *obj, void *data) 603240Sigor@sysoev.ru { 604240Sigor@sysoev.ru nxt_mp_t *mp; 605240Sigor@sysoev.ru nxt_int_t ret; 606240Sigor@sysoev.ru nxt_uint_t n; 607240Sigor@sysoev.ru nxt_file_t *file, *new_file; 608240Sigor@sysoev.ru nxt_runtime_t *rt; 609240Sigor@sysoev.ru nxt_array_t *new_files; 610240Sigor@sysoev.ru 611240Sigor@sysoev.ru nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s", 612240Sigor@sysoev.ru (int) (uintptr_t) obj, data, "log files rotation"); 613240Sigor@sysoev.ru 614240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 615240Sigor@sysoev.ru if (mp == NULL) { 616240Sigor@sysoev.ru return; 617240Sigor@sysoev.ru } 618240Sigor@sysoev.ru 619240Sigor@sysoev.ru rt = task->thread->runtime; 620240Sigor@sysoev.ru 621240Sigor@sysoev.ru n = nxt_list_nelts(rt->log_files); 622240Sigor@sysoev.ru 623240Sigor@sysoev.ru new_files = nxt_array_create(mp, n, sizeof(nxt_file_t)); 624240Sigor@sysoev.ru if (new_files == NULL) { 625240Sigor@sysoev.ru nxt_mp_destroy(mp); 626240Sigor@sysoev.ru return; 627240Sigor@sysoev.ru } 628240Sigor@sysoev.ru 629240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 630240Sigor@sysoev.ru 631240Sigor@sysoev.ru /* This allocation cannot fail. */ 632240Sigor@sysoev.ru new_file = nxt_array_add(new_files); 633240Sigor@sysoev.ru 634240Sigor@sysoev.ru new_file->name = file->name; 635240Sigor@sysoev.ru new_file->fd = NXT_FILE_INVALID; 636240Sigor@sysoev.ru new_file->log_level = NXT_LOG_CRIT; 637240Sigor@sysoev.ru 638240Sigor@sysoev.ru ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT, 639240Sigor@sysoev.ru NXT_FILE_OWNER_ACCESS); 640240Sigor@sysoev.ru 641240Sigor@sysoev.ru if (ret != NXT_OK) { 642240Sigor@sysoev.ru goto fail; 643240Sigor@sysoev.ru } 644240Sigor@sysoev.ru 645240Sigor@sysoev.ru } nxt_list_loop; 646240Sigor@sysoev.ru 647240Sigor@sysoev.ru new_file = new_files->elts; 648240Sigor@sysoev.ru 649240Sigor@sysoev.ru ret = nxt_file_stderr(&new_file[0]); 650240Sigor@sysoev.ru 651240Sigor@sysoev.ru if (ret == NXT_OK) { 652240Sigor@sysoev.ru n = 0; 653240Sigor@sysoev.ru 654240Sigor@sysoev.ru nxt_list_each(file, rt->log_files) { 655240Sigor@sysoev.ru 656240Sigor@sysoev.ru nxt_port_change_log_file(task, rt, n, new_file[n].fd); 657240Sigor@sysoev.ru /* 658240Sigor@sysoev.ru * The old log file descriptor must be closed at the moment 659240Sigor@sysoev.ru * when no other threads use it. dup2() allows to use the 660240Sigor@sysoev.ru * old file descriptor for new log file. This change is 661240Sigor@sysoev.ru * performed atomically in the kernel. 662240Sigor@sysoev.ru */ 663240Sigor@sysoev.ru (void) nxt_file_redirect(file, new_file[n].fd); 664240Sigor@sysoev.ru 665240Sigor@sysoev.ru n++; 666240Sigor@sysoev.ru 667240Sigor@sysoev.ru } nxt_list_loop; 668240Sigor@sysoev.ru 669240Sigor@sysoev.ru nxt_mp_destroy(mp); 670240Sigor@sysoev.ru return; 671240Sigor@sysoev.ru } 672240Sigor@sysoev.ru 673240Sigor@sysoev.ru fail: 674240Sigor@sysoev.ru 675240Sigor@sysoev.ru new_file = new_files->elts; 676240Sigor@sysoev.ru n = new_files->nelts; 677240Sigor@sysoev.ru 678240Sigor@sysoev.ru while (n != 0) { 679240Sigor@sysoev.ru if (new_file->fd != NXT_FILE_INVALID) { 680240Sigor@sysoev.ru nxt_file_close(task, new_file); 681240Sigor@sysoev.ru } 682240Sigor@sysoev.ru 683240Sigor@sysoev.ru new_file++; 684240Sigor@sysoev.ru n--; 685240Sigor@sysoev.ru } 686240Sigor@sysoev.ru 687240Sigor@sysoev.ru nxt_mp_destroy(mp); 688240Sigor@sysoev.ru } 689240Sigor@sysoev.ru 690240Sigor@sysoev.ru 691240Sigor@sysoev.ru static void 692240Sigor@sysoev.ru nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data) 693240Sigor@sysoev.ru { 694240Sigor@sysoev.ru int status; 695240Sigor@sysoev.ru nxt_err_t err; 696240Sigor@sysoev.ru nxt_pid_t pid; 697240Sigor@sysoev.ru 698240Sigor@sysoev.ru nxt_debug(task, "sigchld handler signo:%d (%s)", 699240Sigor@sysoev.ru (int) (uintptr_t) obj, data); 700240Sigor@sysoev.ru 701240Sigor@sysoev.ru for ( ;; ) { 702240Sigor@sysoev.ru pid = waitpid(-1, &status, WNOHANG); 703240Sigor@sysoev.ru 704240Sigor@sysoev.ru if (pid == -1) { 705240Sigor@sysoev.ru 706240Sigor@sysoev.ru switch (err = nxt_errno) { 707240Sigor@sysoev.ru 708240Sigor@sysoev.ru case NXT_ECHILD: 709240Sigor@sysoev.ru return; 710240Sigor@sysoev.ru 711240Sigor@sysoev.ru case NXT_EINTR: 712240Sigor@sysoev.ru continue; 713240Sigor@sysoev.ru 714240Sigor@sysoev.ru default: 715240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "waitpid() failed: %E", err); 716240Sigor@sysoev.ru return; 717240Sigor@sysoev.ru } 718240Sigor@sysoev.ru } 719240Sigor@sysoev.ru 720240Sigor@sysoev.ru nxt_debug(task, "waitpid(): %PI", pid); 721240Sigor@sysoev.ru 722240Sigor@sysoev.ru if (pid == 0) { 723240Sigor@sysoev.ru return; 724240Sigor@sysoev.ru } 725240Sigor@sysoev.ru 726240Sigor@sysoev.ru if (WTERMSIG(status)) { 727240Sigor@sysoev.ru #ifdef WCOREDUMP 728240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d%s", 729240Sigor@sysoev.ru pid, WTERMSIG(status), 730240Sigor@sysoev.ru WCOREDUMP(status) ? " (core dumped)" : ""); 731240Sigor@sysoev.ru #else 732240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d", 733240Sigor@sysoev.ru pid, WTERMSIG(status)); 734240Sigor@sysoev.ru #endif 735240Sigor@sysoev.ru 736240Sigor@sysoev.ru } else { 737240Sigor@sysoev.ru nxt_trace(task, "process %PI exited with code %d", 738240Sigor@sysoev.ru pid, WEXITSTATUS(status)); 739240Sigor@sysoev.ru } 740240Sigor@sysoev.ru 741240Sigor@sysoev.ru nxt_main_cleanup_worker_process(task, pid); 742240Sigor@sysoev.ru } 743240Sigor@sysoev.ru } 744240Sigor@sysoev.ru 745240Sigor@sysoev.ru 746240Sigor@sysoev.ru static void 747240Sigor@sysoev.ru nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid) 748240Sigor@sysoev.ru { 749240Sigor@sysoev.ru nxt_buf_t *buf; 750240Sigor@sysoev.ru nxt_port_t *port; 751240Sigor@sysoev.ru nxt_runtime_t *rt; 752240Sigor@sysoev.ru nxt_process_t *process; 753240Sigor@sysoev.ru nxt_process_init_t *init; 754240Sigor@sysoev.ru 755240Sigor@sysoev.ru rt = task->thread->runtime; 756240Sigor@sysoev.ru 757240Sigor@sysoev.ru process = nxt_runtime_process_find(rt, pid); 758240Sigor@sysoev.ru 759240Sigor@sysoev.ru if (process) { 760240Sigor@sysoev.ru init = process->init; 761240Sigor@sysoev.ru 762240Sigor@sysoev.ru nxt_runtime_process_remove(rt, process); 763240Sigor@sysoev.ru 764240Sigor@sysoev.ru if (!nxt_exiting) { 765277Sigor@sysoev.ru nxt_runtime_process_each(rt, process) { 766277Sigor@sysoev.ru 767277Sigor@sysoev.ru if (process->pid == nxt_pid 768277Sigor@sysoev.ru || process->pid == pid 769277Sigor@sysoev.ru || nxt_queue_is_empty(&process->ports)) 770277Sigor@sysoev.ru { 771240Sigor@sysoev.ru continue; 772240Sigor@sysoev.ru } 773240Sigor@sysoev.ru 774240Sigor@sysoev.ru port = nxt_process_port_first(process); 775240Sigor@sysoev.ru 776240Sigor@sysoev.ru buf = nxt_buf_mem_alloc(port->mem_pool, sizeof(pid), 0); 777240Sigor@sysoev.ru buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid)); 778240Sigor@sysoev.ru 779240Sigor@sysoev.ru nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, 780240Sigor@sysoev.ru -1, init->stream, 0, buf); 781277Sigor@sysoev.ru } nxt_runtime_process_loop; 782240Sigor@sysoev.ru } 783240Sigor@sysoev.ru 784240Sigor@sysoev.ru if (nxt_exiting) { 785240Sigor@sysoev.ru 786240Sigor@sysoev.ru if (rt->nprocesses == 2) { 787240Sigor@sysoev.ru nxt_runtime_quit(task); 788240Sigor@sysoev.ru } 789240Sigor@sysoev.ru 790240Sigor@sysoev.ru } else if (init != NULL) { 791240Sigor@sysoev.ru if (init->restart != 0) { 792240Sigor@sysoev.ru (void) nxt_main_create_worker_process(task, rt, init); 793240Sigor@sysoev.ru 794240Sigor@sysoev.ru } else { 795240Sigor@sysoev.ru nxt_free(init); 796240Sigor@sysoev.ru } 797240Sigor@sysoev.ru } 798240Sigor@sysoev.ru } 799240Sigor@sysoev.ru } 800240Sigor@sysoev.ru 801240Sigor@sysoev.ru 802240Sigor@sysoev.ru static void 803240Sigor@sysoev.ru nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 804240Sigor@sysoev.ru { 805240Sigor@sysoev.ru size_t size; 806240Sigor@sysoev.ru nxt_int_t ret; 807240Sigor@sysoev.ru nxt_buf_t *b, *out; 808240Sigor@sysoev.ru nxt_port_t *port; 809240Sigor@sysoev.ru nxt_sockaddr_t *sa; 810240Sigor@sysoev.ru nxt_port_msg_type_t type; 811240Sigor@sysoev.ru nxt_listening_socket_t ls; 812240Sigor@sysoev.ru u_char message[2048]; 813240Sigor@sysoev.ru 814240Sigor@sysoev.ru b = msg->buf; 815240Sigor@sysoev.ru sa = (nxt_sockaddr_t *) b->mem.pos; 816240Sigor@sysoev.ru 817240Sigor@sysoev.ru out = NULL; 818240Sigor@sysoev.ru 819240Sigor@sysoev.ru ls.socket = -1; 820240Sigor@sysoev.ru ls.error = NXT_SOCKET_ERROR_SYSTEM; 821240Sigor@sysoev.ru ls.start = message; 822240Sigor@sysoev.ru ls.end = message + sizeof(message); 823240Sigor@sysoev.ru 824240Sigor@sysoev.ru port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, 825240Sigor@sysoev.ru msg->port_msg.reply_port); 826240Sigor@sysoev.ru 827240Sigor@sysoev.ru nxt_debug(task, "listening socket \"%*s\"", 828240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 829240Sigor@sysoev.ru 830240Sigor@sysoev.ru ret = nxt_main_listening_socket(sa, &ls); 831240Sigor@sysoev.ru 832240Sigor@sysoev.ru if (ret == NXT_OK) { 833240Sigor@sysoev.ru nxt_debug(task, "socket(\"%*s\"): %d", 834240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), ls.socket); 835240Sigor@sysoev.ru 836240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD; 837240Sigor@sysoev.ru 838240Sigor@sysoev.ru } else { 839240Sigor@sysoev.ru size = ls.end - ls.start; 840240Sigor@sysoev.ru 841240Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "%*s", size, ls.start); 842240Sigor@sysoev.ru 843240Sigor@sysoev.ru out = nxt_buf_mem_alloc(port->mem_pool, size + 1, 0); 844240Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 845240Sigor@sysoev.ru return; 846240Sigor@sysoev.ru } 847240Sigor@sysoev.ru 848240Sigor@sysoev.ru *out->mem.free++ = (uint8_t) ls.error; 849240Sigor@sysoev.ru 850240Sigor@sysoev.ru out->mem.free = nxt_cpymem(out->mem.free, ls.start, size); 851240Sigor@sysoev.ru 852240Sigor@sysoev.ru type = NXT_PORT_MSG_RPC_ERROR; 853240Sigor@sysoev.ru } 854240Sigor@sysoev.ru 855240Sigor@sysoev.ru nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream, 856240Sigor@sysoev.ru 0, out); 857240Sigor@sysoev.ru } 858240Sigor@sysoev.ru 859240Sigor@sysoev.ru 860240Sigor@sysoev.ru static nxt_int_t 861240Sigor@sysoev.ru nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls) 862240Sigor@sysoev.ru { 863240Sigor@sysoev.ru nxt_err_t err; 864240Sigor@sysoev.ru nxt_socket_t s; 865240Sigor@sysoev.ru 866240Sigor@sysoev.ru const socklen_t length = sizeof(int); 867240Sigor@sysoev.ru static const int enable = 1; 868240Sigor@sysoev.ru 869240Sigor@sysoev.ru s = socket(sa->u.sockaddr.sa_family, sa->type, 0); 870240Sigor@sysoev.ru 871240Sigor@sysoev.ru if (nxt_slow_path(s == -1)) { 872240Sigor@sysoev.ru err = nxt_errno; 873240Sigor@sysoev.ru 874240Sigor@sysoev.ru #if (NXT_INET6) 875240Sigor@sysoev.ru 876240Sigor@sysoev.ru if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) { 877240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOINET6; 878240Sigor@sysoev.ru } 879240Sigor@sysoev.ru 880240Sigor@sysoev.ru #endif 881240Sigor@sysoev.ru 882240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 883240Sigor@sysoev.ru "socket(\\\"%*s\\\") failed %E", 884240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 885240Sigor@sysoev.ru 886240Sigor@sysoev.ru return NXT_ERROR; 887240Sigor@sysoev.ru } 888240Sigor@sysoev.ru 889240Sigor@sysoev.ru if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) { 890240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 891240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E", 892240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 893240Sigor@sysoev.ru goto fail; 894240Sigor@sysoev.ru } 895240Sigor@sysoev.ru 896240Sigor@sysoev.ru #if (NXT_INET6) 897240Sigor@sysoev.ru 898240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_INET6) { 899240Sigor@sysoev.ru 900240Sigor@sysoev.ru if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) { 901240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 902240Sigor@sysoev.ru "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E", 903240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), nxt_errno); 904240Sigor@sysoev.ru goto fail; 905240Sigor@sysoev.ru } 906240Sigor@sysoev.ru } 907240Sigor@sysoev.ru 908240Sigor@sysoev.ru #endif 909240Sigor@sysoev.ru 910240Sigor@sysoev.ru if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) { 911240Sigor@sysoev.ru err = nxt_errno; 912240Sigor@sysoev.ru 913240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 914240Sigor@sysoev.ru 915240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 916240Sigor@sysoev.ru switch (err) { 917240Sigor@sysoev.ru 918240Sigor@sysoev.ru case EACCES: 919240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_ACCESS; 920240Sigor@sysoev.ru break; 921240Sigor@sysoev.ru 922240Sigor@sysoev.ru case ENOENT: 923240Sigor@sysoev.ru case ENOTDIR: 924240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PATH; 925240Sigor@sysoev.ru break; 926240Sigor@sysoev.ru } 927240Sigor@sysoev.ru 928240Sigor@sysoev.ru goto next; 929240Sigor@sysoev.ru } 930240Sigor@sysoev.ru 931240Sigor@sysoev.ru #endif 932240Sigor@sysoev.ru 933240Sigor@sysoev.ru switch (err) { 934240Sigor@sysoev.ru 935240Sigor@sysoev.ru case EACCES: 936240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_PORT; 937240Sigor@sysoev.ru break; 938240Sigor@sysoev.ru 939240Sigor@sysoev.ru case EADDRINUSE: 940240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_INUSE; 941240Sigor@sysoev.ru break; 942240Sigor@sysoev.ru 943240Sigor@sysoev.ru case EADDRNOTAVAIL: 944240Sigor@sysoev.ru ls->error = NXT_SOCKET_ERROR_NOADDR; 945240Sigor@sysoev.ru break; 946240Sigor@sysoev.ru } 947240Sigor@sysoev.ru 948240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E", 949240Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), err); 950240Sigor@sysoev.ru goto fail; 951240Sigor@sysoev.ru } 952240Sigor@sysoev.ru 953240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 954240Sigor@sysoev.ru 955240Sigor@sysoev.ru next: 956240Sigor@sysoev.ru 957240Sigor@sysoev.ru if (sa->u.sockaddr.sa_family == AF_UNIX) { 958240Sigor@sysoev.ru char *filename; 959240Sigor@sysoev.ru mode_t access; 960240Sigor@sysoev.ru 961240Sigor@sysoev.ru filename = sa->u.sockaddr_un.sun_path; 962240Sigor@sysoev.ru access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 963240Sigor@sysoev.ru 964240Sigor@sysoev.ru if (chmod(filename, access) != 0) { 965240Sigor@sysoev.ru ls->end = nxt_sprintf(ls->start, ls->end, 966240Sigor@sysoev.ru "chmod(\\\"%*s\\\") failed %E", 967240Sigor@sysoev.ru filename, nxt_errno); 968240Sigor@sysoev.ru goto fail; 969240Sigor@sysoev.ru } 970240Sigor@sysoev.ru } 971240Sigor@sysoev.ru 972240Sigor@sysoev.ru #endif 973240Sigor@sysoev.ru 974240Sigor@sysoev.ru ls->socket = s; 975240Sigor@sysoev.ru 976240Sigor@sysoev.ru return NXT_OK; 977240Sigor@sysoev.ru 978240Sigor@sysoev.ru fail: 979240Sigor@sysoev.ru 980240Sigor@sysoev.ru (void) close(s); 981240Sigor@sysoev.ru 982240Sigor@sysoev.ru return NXT_ERROR; 983240Sigor@sysoev.ru } 984240Sigor@sysoev.ru 985240Sigor@sysoev.ru 986240Sigor@sysoev.ru static nxt_conf_map_t nxt_app_lang_module_map[] = { 987240Sigor@sysoev.ru { 988240Sigor@sysoev.ru nxt_string("type"), 989240Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 990240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, type), 991240Sigor@sysoev.ru }, 992240Sigor@sysoev.ru 993240Sigor@sysoev.ru { 994240Sigor@sysoev.ru nxt_string("version"), 995240Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 996240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, version), 997240Sigor@sysoev.ru }, 998240Sigor@sysoev.ru 999240Sigor@sysoev.ru { 1000240Sigor@sysoev.ru nxt_string("file"), 1001240Sigor@sysoev.ru NXT_CONF_MAP_CSTRZ, 1002240Sigor@sysoev.ru offsetof(nxt_app_lang_module_t, file), 1003240Sigor@sysoev.ru }, 1004240Sigor@sysoev.ru }; 1005240Sigor@sysoev.ru 1006240Sigor@sysoev.ru 1007240Sigor@sysoev.ru static void 1008240Sigor@sysoev.ru nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1009240Sigor@sysoev.ru { 1010240Sigor@sysoev.ru uint32_t index; 1011240Sigor@sysoev.ru nxt_mp_t *mp; 1012240Sigor@sysoev.ru nxt_int_t ret; 1013240Sigor@sysoev.ru nxt_buf_t *b; 1014240Sigor@sysoev.ru nxt_runtime_t *rt; 1015240Sigor@sysoev.ru nxt_conf_value_t *conf, *root, *value; 1016240Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1017240Sigor@sysoev.ru 1018240Sigor@sysoev.ru static nxt_str_t root_path = nxt_string("/"); 1019240Sigor@sysoev.ru 1020240Sigor@sysoev.ru rt = task->thread->runtime; 1021240Sigor@sysoev.ru 1022240Sigor@sysoev.ru if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) { 1023240Sigor@sysoev.ru return; 1024240Sigor@sysoev.ru } 1025240Sigor@sysoev.ru 1026240Sigor@sysoev.ru b = msg->buf; 1027240Sigor@sysoev.ru 1028240Sigor@sysoev.ru if (b == NULL) { 1029240Sigor@sysoev.ru return; 1030240Sigor@sysoev.ru } 1031240Sigor@sysoev.ru 1032240Sigor@sysoev.ru nxt_debug(task, "application languages: \"%*s\"", 1033240Sigor@sysoev.ru b->mem.free - b->mem.pos, b->mem.pos); 1034240Sigor@sysoev.ru 1035240Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 1036240Sigor@sysoev.ru if (mp == NULL) { 1037240Sigor@sysoev.ru return; 1038240Sigor@sysoev.ru } 1039240Sigor@sysoev.ru 1040240Sigor@sysoev.ru conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL); 1041240Sigor@sysoev.ru if (conf == NULL) { 1042240Sigor@sysoev.ru goto fail; 1043240Sigor@sysoev.ru } 1044240Sigor@sysoev.ru 1045240Sigor@sysoev.ru root = nxt_conf_get_path(conf, &root_path); 1046240Sigor@sysoev.ru if (root == NULL) { 1047240Sigor@sysoev.ru goto fail; 1048240Sigor@sysoev.ru } 1049240Sigor@sysoev.ru 1050240Sigor@sysoev.ru for (index = 0; /* void */ ; index++) { 1051240Sigor@sysoev.ru value = nxt_conf_get_array_element(root, index); 1052240Sigor@sysoev.ru if (value == NULL) { 1053240Sigor@sysoev.ru break; 1054240Sigor@sysoev.ru } 1055240Sigor@sysoev.ru 1056240Sigor@sysoev.ru lang = nxt_array_add(rt->languages); 1057240Sigor@sysoev.ru if (lang == NULL) { 1058240Sigor@sysoev.ru goto fail; 1059240Sigor@sysoev.ru } 1060240Sigor@sysoev.ru 1061240Sigor@sysoev.ru lang->module = NULL; 1062240Sigor@sysoev.ru 1063240Sigor@sysoev.ru ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map, 1064240Sigor@sysoev.ru nxt_nitems(nxt_app_lang_module_map), lang); 1065240Sigor@sysoev.ru 1066240Sigor@sysoev.ru if (ret != NXT_OK) { 1067240Sigor@sysoev.ru goto fail; 1068240Sigor@sysoev.ru } 1069240Sigor@sysoev.ru 1070240Sigor@sysoev.ru nxt_debug(task, "lang %V %V \"%s\"", 1071240Sigor@sysoev.ru &lang->type, &lang->version, lang->file); 1072240Sigor@sysoev.ru } 1073240Sigor@sysoev.ru 1074240Sigor@sysoev.ru qsort(rt->languages->elts, rt->languages->nelts, 1075240Sigor@sysoev.ru sizeof(nxt_app_lang_module_t), nxt_app_lang_compare); 1076240Sigor@sysoev.ru 1077240Sigor@sysoev.ru fail: 1078240Sigor@sysoev.ru 1079240Sigor@sysoev.ru nxt_mp_destroy(mp); 1080240Sigor@sysoev.ru 1081240Sigor@sysoev.ru ret = nxt_main_start_controller_process(task, rt); 1082240Sigor@sysoev.ru 1083240Sigor@sysoev.ru if (ret == NXT_OK) { 1084240Sigor@sysoev.ru (void) nxt_main_start_router_process(task, rt); 1085240Sigor@sysoev.ru } 1086240Sigor@sysoev.ru } 1087240Sigor@sysoev.ru 1088240Sigor@sysoev.ru 1089240Sigor@sysoev.ru static int nxt_cdecl 1090240Sigor@sysoev.ru nxt_app_lang_compare(const void *v1, const void *v2) 1091240Sigor@sysoev.ru { 1092240Sigor@sysoev.ru int n; 1093240Sigor@sysoev.ru size_t length; 1094240Sigor@sysoev.ru const nxt_app_lang_module_t *lang1, *lang2; 1095240Sigor@sysoev.ru 1096240Sigor@sysoev.ru lang1 = v1; 1097240Sigor@sysoev.ru lang2 = v2; 1098240Sigor@sysoev.ru 1099258Sigor@sysoev.ru if (lang1->type.length != lang2->type.length) { 1100258Sigor@sysoev.ru return lang1->type.length - lang2->type.length; 1101258Sigor@sysoev.ru } 1102258Sigor@sysoev.ru 1103258Sigor@sysoev.ru n = nxt_strncmp(lang1->type.start, lang2->type.start, lang1->type.length); 1104258Sigor@sysoev.ru 1105258Sigor@sysoev.ru if (n != 0) { 1106258Sigor@sysoev.ru return n; 1107258Sigor@sysoev.ru } 1108258Sigor@sysoev.ru 1109240Sigor@sysoev.ru length = nxt_min(lang1->version.length, lang2->version.length); 1110240Sigor@sysoev.ru 1111240Sigor@sysoev.ru n = nxt_strncmp(lang1->version.start, lang2->version.start, length); 1112240Sigor@sysoev.ru 1113240Sigor@sysoev.ru if (n == 0) { 1114240Sigor@sysoev.ru n = lang1->version.length - lang2->version.length; 1115240Sigor@sysoev.ru } 1116240Sigor@sysoev.ru 1117240Sigor@sysoev.ru /* Negate result to move higher versions to the beginning. */ 1118240Sigor@sysoev.ru 1119240Sigor@sysoev.ru return -n; 1120240Sigor@sysoev.ru } 1121314Svbart@nginx.com 1122314Svbart@nginx.com 1123314Svbart@nginx.com static void 1124314Svbart@nginx.com nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 1125314Svbart@nginx.com { 1126314Svbart@nginx.com ssize_t n, size; 1127314Svbart@nginx.com nxt_buf_t *b; 1128314Svbart@nginx.com nxt_int_t ret; 1129314Svbart@nginx.com nxt_file_t file; 1130314Svbart@nginx.com nxt_runtime_t *rt; 1131314Svbart@nginx.com 1132314Svbart@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 1133314Svbart@nginx.com 1134314Svbart@nginx.com rt = task->thread->runtime; 1135314Svbart@nginx.com 1136314Svbart@nginx.com file.name = (nxt_file_name_t *) rt->conf_tmp; 1137314Svbart@nginx.com 1138314Svbart@nginx.com if (nxt_slow_path(nxt_file_open(task, &file, NXT_FILE_WRONLY, 1139314Svbart@nginx.com NXT_FILE_TRUNCATE, NXT_FILE_OWNER_ACCESS) 1140314Svbart@nginx.com != NXT_OK)) 1141314Svbart@nginx.com { 1142314Svbart@nginx.com goto error; 1143314Svbart@nginx.com } 1144314Svbart@nginx.com 1145314Svbart@nginx.com for (b = msg->buf; b != NULL; b = b->next) { 1146314Svbart@nginx.com size = nxt_buf_mem_used_size(&b->mem); 1147314Svbart@nginx.com 1148314Svbart@nginx.com n = nxt_file_write(&file, b->mem.pos, size, 0); 1149314Svbart@nginx.com 1150314Svbart@nginx.com if (nxt_slow_path(n != size)) { 1151314Svbart@nginx.com nxt_file_close(task, &file); 1152314Svbart@nginx.com (void) nxt_file_delete(file.name); 1153314Svbart@nginx.com goto error; 1154314Svbart@nginx.com } 1155314Svbart@nginx.com } 1156314Svbart@nginx.com 1157314Svbart@nginx.com nxt_file_close(task, &file); 1158314Svbart@nginx.com 1159314Svbart@nginx.com ret = nxt_file_rename(file.name, (nxt_file_name_t *) rt->conf); 1160314Svbart@nginx.com 1161314Svbart@nginx.com if (nxt_fast_path(ret == NXT_OK)) { 1162314Svbart@nginx.com return; 1163314Svbart@nginx.com } 1164314Svbart@nginx.com 1165314Svbart@nginx.com error: 1166314Svbart@nginx.com 1167314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, "failed to store current configuration"); 1168314Svbart@nginx.com } 1169