111Sigor@sysoev.ru 211Sigor@sysoev.ru /* 311Sigor@sysoev.ru * Copyright (C) Igor Sysoev 411Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 511Sigor@sysoev.ru */ 611Sigor@sysoev.ru 711Sigor@sysoev.ru #include <nxt_main.h> 820Sigor@sysoev.ru #include <nxt_runtime.h> 911Sigor@sysoev.ru #include <nxt_port.h> 1011Sigor@sysoev.ru 1111Sigor@sysoev.ru 1214Sigor@sysoev.ru static void nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 1311Sigor@sysoev.ru 1411Sigor@sysoev.ru 1511Sigor@sysoev.ru void 1677Smax.romanov@nginx.com nxt_port_create(nxt_task_t *task, nxt_port_t *port, 1714Sigor@sysoev.ru nxt_port_handler_t *handlers) 1811Sigor@sysoev.ru { 1914Sigor@sysoev.ru port->pid = nxt_pid; 2077Smax.romanov@nginx.com port->engine = task->thread->engine->id; 2114Sigor@sysoev.ru port->handler = nxt_port_handler; 2214Sigor@sysoev.ru port->data = handlers; 2311Sigor@sysoev.ru 2477Smax.romanov@nginx.com nxt_port_read_enable(task, port); 2511Sigor@sysoev.ru } 2611Sigor@sysoev.ru 2711Sigor@sysoev.ru 2811Sigor@sysoev.ru void 2920Sigor@sysoev.ru nxt_port_write(nxt_task_t *task, nxt_runtime_t *rt, nxt_uint_t type, 3011Sigor@sysoev.ru nxt_fd_t fd, uint32_t stream, nxt_buf_t *b) 3111Sigor@sysoev.ru { 3220Sigor@sysoev.ru nxt_port_t *port; 3320Sigor@sysoev.ru nxt_process_t *process; 3420Sigor@sysoev.ru 3542Smax.romanov@nginx.com nxt_runtime_process_each(rt, process) 3642Smax.romanov@nginx.com { 3742Smax.romanov@nginx.com if (nxt_pid != process->pid) { 3842Smax.romanov@nginx.com nxt_process_port_each(process, port) { 3911Sigor@sysoev.ru 4042Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, type, 4142Smax.romanov@nginx.com fd, stream, 0, b); 4211Sigor@sysoev.ru 4342Smax.romanov@nginx.com } nxt_process_port_loop; 4411Sigor@sysoev.ru } 4511Sigor@sysoev.ru } 4642Smax.romanov@nginx.com nxt_runtime_process_loop; 4711Sigor@sysoev.ru } 4811Sigor@sysoev.ru 4911Sigor@sysoev.ru 5011Sigor@sysoev.ru static void 5114Sigor@sysoev.ru nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 5211Sigor@sysoev.ru { 5314Sigor@sysoev.ru nxt_port_handler_t *handlers; 5411Sigor@sysoev.ru 55*125Smax.romanov@nginx.com if (nxt_fast_path(msg->port_msg.type < NXT_PORT_MSG_MAX)) { 5611Sigor@sysoev.ru 5711Sigor@sysoev.ru nxt_debug(task, "port %d: message type:%uD", 5842Smax.romanov@nginx.com msg->port->socket.fd, msg->port_msg.type); 5911Sigor@sysoev.ru 6011Sigor@sysoev.ru handlers = msg->port->data; 6142Smax.romanov@nginx.com handlers[msg->port_msg.type](task, msg); 6211Sigor@sysoev.ru 6311Sigor@sysoev.ru return; 6411Sigor@sysoev.ru } 6511Sigor@sysoev.ru 6611Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "port %d: unknown message type:%uD", 6742Smax.romanov@nginx.com msg->port->socket.fd, msg->port_msg.type); 6811Sigor@sysoev.ru } 6911Sigor@sysoev.ru 7011Sigor@sysoev.ru 7111Sigor@sysoev.ru void 7214Sigor@sysoev.ru nxt_port_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 7311Sigor@sysoev.ru { 7420Sigor@sysoev.ru nxt_runtime_quit(task); 7511Sigor@sysoev.ru } 7611Sigor@sysoev.ru 7711Sigor@sysoev.ru 7811Sigor@sysoev.ru void 7920Sigor@sysoev.ru nxt_port_send_new_port(nxt_task_t *task, nxt_runtime_t *rt, 8014Sigor@sysoev.ru nxt_port_t *new_port) 8111Sigor@sysoev.ru { 8281Smax.romanov@nginx.com nxt_process_t *process; 8311Sigor@sysoev.ru 8414Sigor@sysoev.ru nxt_debug(task, "new port %d for process %PI engine %uD", 8581Smax.romanov@nginx.com new_port->pair[1], new_port->pid, new_port->engine); 8611Sigor@sysoev.ru 8742Smax.romanov@nginx.com nxt_runtime_process_each(rt, process) 8842Smax.romanov@nginx.com { 8942Smax.romanov@nginx.com if (process->pid == new_port->pid || process->pid == nxt_pid) { 9011Sigor@sysoev.ru continue; 9111Sigor@sysoev.ru } 9211Sigor@sysoev.ru 9381Smax.romanov@nginx.com (void) nxt_port_send_port(task, nxt_process_port_first(process), 9481Smax.romanov@nginx.com new_port); 9511Sigor@sysoev.ru } 9642Smax.romanov@nginx.com nxt_runtime_process_loop; 9711Sigor@sysoev.ru } 9811Sigor@sysoev.ru 9911Sigor@sysoev.ru 10081Smax.romanov@nginx.com nxt_int_t 10181Smax.romanov@nginx.com nxt_port_send_port(nxt_task_t *task, nxt_port_t *port, nxt_port_t *new_port) 10281Smax.romanov@nginx.com { 10381Smax.romanov@nginx.com nxt_buf_t *b; 10481Smax.romanov@nginx.com nxt_port_msg_new_port_t *msg; 10581Smax.romanov@nginx.com 106122Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, port->mem_pool, sizeof(nxt_port_data_t)); 10781Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 10881Smax.romanov@nginx.com return NXT_ERROR; 10981Smax.romanov@nginx.com } 11081Smax.romanov@nginx.com 11181Smax.romanov@nginx.com nxt_debug(task, "send port %FD to process %PI", 11281Smax.romanov@nginx.com new_port->pair[1], port->pid); 11381Smax.romanov@nginx.com 11481Smax.romanov@nginx.com b->mem.free += sizeof(nxt_port_msg_new_port_t); 11581Smax.romanov@nginx.com msg = (nxt_port_msg_new_port_t *) b->mem.pos; 11681Smax.romanov@nginx.com 11781Smax.romanov@nginx.com msg->id = new_port->id; 11881Smax.romanov@nginx.com msg->pid = new_port->pid; 11981Smax.romanov@nginx.com msg->engine = new_port->engine; 12081Smax.romanov@nginx.com msg->max_size = port->max_size; 12181Smax.romanov@nginx.com msg->max_share = port->max_share; 12281Smax.romanov@nginx.com msg->type = new_port->type; 12381Smax.romanov@nginx.com 12481Smax.romanov@nginx.com return nxt_port_socket_write(task, port, NXT_PORT_MSG_NEW_PORT, 12581Smax.romanov@nginx.com new_port->pair[1], 0, 0, b); 12681Smax.romanov@nginx.com } 12781Smax.romanov@nginx.com 12881Smax.romanov@nginx.com 12911Sigor@sysoev.ru void 13014Sigor@sysoev.ru nxt_port_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 13111Sigor@sysoev.ru { 13265Sigor@sysoev.ru nxt_mp_t *mp; 13311Sigor@sysoev.ru nxt_port_t *port; 13420Sigor@sysoev.ru nxt_process_t *process; 13520Sigor@sysoev.ru nxt_runtime_t *rt; 13614Sigor@sysoev.ru nxt_port_msg_new_port_t *new_port_msg; 13711Sigor@sysoev.ru 13820Sigor@sysoev.ru rt = task->thread->runtime; 13911Sigor@sysoev.ru 14042Smax.romanov@nginx.com new_port_msg = (nxt_port_msg_new_port_t *) msg->buf->mem.pos; 14142Smax.romanov@nginx.com msg->buf->mem.pos = msg->buf->mem.free; 14242Smax.romanov@nginx.com 14342Smax.romanov@nginx.com process = nxt_runtime_process_get(rt, new_port_msg->pid); 14420Sigor@sysoev.ru if (nxt_slow_path(process == NULL)) { 14520Sigor@sysoev.ru return; 14620Sigor@sysoev.ru } 14720Sigor@sysoev.ru 14842Smax.romanov@nginx.com port = nxt_process_port_new(process); 14911Sigor@sysoev.ru if (nxt_slow_path(port == NULL)) { 15011Sigor@sysoev.ru return; 15111Sigor@sysoev.ru } 15211Sigor@sysoev.ru 15365Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 15414Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 15514Sigor@sysoev.ru return; 15614Sigor@sysoev.ru } 15711Sigor@sysoev.ru 15814Sigor@sysoev.ru port->mem_pool = mp; 15914Sigor@sysoev.ru 16011Sigor@sysoev.ru nxt_debug(task, "new port %d received for process %PI engine %uD", 16114Sigor@sysoev.ru msg->fd, new_port_msg->pid, new_port_msg->engine); 16211Sigor@sysoev.ru 16342Smax.romanov@nginx.com port->id = new_port_msg->id; 16414Sigor@sysoev.ru port->engine = new_port_msg->engine; 16514Sigor@sysoev.ru port->pair[0] = -1; 16611Sigor@sysoev.ru port->pair[1] = msg->fd; 16714Sigor@sysoev.ru port->max_size = new_port_msg->max_size; 16814Sigor@sysoev.ru port->max_share = new_port_msg->max_share; 16942Smax.romanov@nginx.com port->type = new_port_msg->type; 17011Sigor@sysoev.ru 17114Sigor@sysoev.ru nxt_queue_init(&port->messages); 17214Sigor@sysoev.ru 17314Sigor@sysoev.ru port->socket.task = task; 17414Sigor@sysoev.ru 17542Smax.romanov@nginx.com nxt_runtime_port_add(rt, port); 17642Smax.romanov@nginx.com 17711Sigor@sysoev.ru nxt_port_write_enable(task, port); 17811Sigor@sysoev.ru } 17911Sigor@sysoev.ru 18011Sigor@sysoev.ru 18111Sigor@sysoev.ru void 18242Smax.romanov@nginx.com nxt_port_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 18342Smax.romanov@nginx.com { 18442Smax.romanov@nginx.com nxt_runtime_t *rt; 18542Smax.romanov@nginx.com nxt_process_t *process; 18642Smax.romanov@nginx.com 18742Smax.romanov@nginx.com rt = task->thread->runtime; 18842Smax.romanov@nginx.com 18942Smax.romanov@nginx.com if (nxt_slow_path(msg->fd == -1)) { 19042Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "invalid fd passed with mmap message"); 19142Smax.romanov@nginx.com 19242Smax.romanov@nginx.com return; 19342Smax.romanov@nginx.com } 19442Smax.romanov@nginx.com 19542Smax.romanov@nginx.com process = nxt_runtime_process_get(rt, msg->port_msg.pid); 19642Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 19742Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to get process #%PI", 19842Smax.romanov@nginx.com msg->port_msg.pid); 19942Smax.romanov@nginx.com 20042Smax.romanov@nginx.com goto fail_close; 20142Smax.romanov@nginx.com } 20242Smax.romanov@nginx.com 20342Smax.romanov@nginx.com nxt_port_incoming_port_mmap(task, process, msg->fd); 20442Smax.romanov@nginx.com 20542Smax.romanov@nginx.com fail_close: 20642Smax.romanov@nginx.com 20742Smax.romanov@nginx.com close(msg->fd); 20842Smax.romanov@nginx.com } 20942Smax.romanov@nginx.com 21042Smax.romanov@nginx.com 21142Smax.romanov@nginx.com void 21220Sigor@sysoev.ru nxt_port_change_log_file(nxt_task_t *task, nxt_runtime_t *rt, nxt_uint_t slot, 21320Sigor@sysoev.ru nxt_fd_t fd) 21411Sigor@sysoev.ru { 21520Sigor@sysoev.ru nxt_buf_t *b; 21620Sigor@sysoev.ru nxt_port_t *port; 21720Sigor@sysoev.ru nxt_process_t *process; 21811Sigor@sysoev.ru 21914Sigor@sysoev.ru nxt_debug(task, "change log file #%ui fd:%FD", slot, fd); 22011Sigor@sysoev.ru 22142Smax.romanov@nginx.com nxt_runtime_process_each(rt, process) 22242Smax.romanov@nginx.com { 22342Smax.romanov@nginx.com if (nxt_pid == process->pid) { 22442Smax.romanov@nginx.com continue; 22542Smax.romanov@nginx.com } 22611Sigor@sysoev.ru 22742Smax.romanov@nginx.com port = nxt_process_port_first(process); 22811Sigor@sysoev.ru 22920Sigor@sysoev.ru b = nxt_buf_mem_alloc(port->mem_pool, sizeof(nxt_port_data_t), 0); 23011Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 23111Sigor@sysoev.ru continue; 23211Sigor@sysoev.ru } 23311Sigor@sysoev.ru 23411Sigor@sysoev.ru *(nxt_uint_t *) b->mem.pos = slot; 23511Sigor@sysoev.ru b->mem.free += sizeof(nxt_uint_t); 23611Sigor@sysoev.ru 23720Sigor@sysoev.ru (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_CHANGE_FILE, 23842Smax.romanov@nginx.com fd, 0, 0, b); 23911Sigor@sysoev.ru } 24042Smax.romanov@nginx.com nxt_runtime_process_loop; 24111Sigor@sysoev.ru } 24211Sigor@sysoev.ru 24311Sigor@sysoev.ru 24411Sigor@sysoev.ru void 24514Sigor@sysoev.ru nxt_port_change_log_file_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 24611Sigor@sysoev.ru { 24720Sigor@sysoev.ru nxt_buf_t *b; 24820Sigor@sysoev.ru nxt_uint_t slot; 24920Sigor@sysoev.ru nxt_file_t *log_file; 25020Sigor@sysoev.ru nxt_runtime_t *rt; 25111Sigor@sysoev.ru 25220Sigor@sysoev.ru rt = task->thread->runtime; 25311Sigor@sysoev.ru 25411Sigor@sysoev.ru b = msg->buf; 25511Sigor@sysoev.ru slot = *(nxt_uint_t *) b->mem.pos; 25611Sigor@sysoev.ru 25720Sigor@sysoev.ru log_file = nxt_list_elt(rt->log_files, slot); 25811Sigor@sysoev.ru 25911Sigor@sysoev.ru nxt_debug(task, "change log file %FD:%FD", msg->fd, log_file->fd); 26011Sigor@sysoev.ru 26111Sigor@sysoev.ru /* 26211Sigor@sysoev.ru * The old log file descriptor must be closed at the moment when no 26311Sigor@sysoev.ru * other threads use it. dup2() allows to use the old file descriptor 26411Sigor@sysoev.ru * for new log file. This change is performed atomically in the kernel. 26511Sigor@sysoev.ru */ 26611Sigor@sysoev.ru if (nxt_file_redirect(log_file, msg->fd) == NXT_OK) { 26711Sigor@sysoev.ru 26811Sigor@sysoev.ru if (slot == 0) { 26911Sigor@sysoev.ru (void) nxt_file_stderr(log_file); 27011Sigor@sysoev.ru } 27111Sigor@sysoev.ru } 27211Sigor@sysoev.ru } 27311Sigor@sysoev.ru 27411Sigor@sysoev.ru 27511Sigor@sysoev.ru void 27614Sigor@sysoev.ru nxt_port_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 27711Sigor@sysoev.ru { 27842Smax.romanov@nginx.com size_t dump_size; 27911Sigor@sysoev.ru nxt_buf_t *b; 28011Sigor@sysoev.ru 28111Sigor@sysoev.ru b = msg->buf; 28242Smax.romanov@nginx.com dump_size = b->mem.free - b->mem.pos; 28311Sigor@sysoev.ru 28442Smax.romanov@nginx.com if (dump_size > 300) { 28542Smax.romanov@nginx.com dump_size = 300; 28642Smax.romanov@nginx.com } 28742Smax.romanov@nginx.com 28842Smax.romanov@nginx.com nxt_debug(task, "data: %*s", dump_size, b->mem.pos); 28911Sigor@sysoev.ru 29011Sigor@sysoev.ru b->mem.pos = b->mem.free; 29111Sigor@sysoev.ru } 29211Sigor@sysoev.ru 29311Sigor@sysoev.ru 29411Sigor@sysoev.ru void 295*125Smax.romanov@nginx.com nxt_port_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 296*125Smax.romanov@nginx.com { 297*125Smax.romanov@nginx.com nxt_pid_t pid; 298*125Smax.romanov@nginx.com nxt_runtime_t *rt; 299*125Smax.romanov@nginx.com nxt_process_t *process; 300*125Smax.romanov@nginx.com 301*125Smax.romanov@nginx.com nxt_debug(task, "port remove pid handler"); 302*125Smax.romanov@nginx.com 303*125Smax.romanov@nginx.com rt = task->thread->runtime; 304*125Smax.romanov@nginx.com pid = msg->port_msg.stream; 305*125Smax.romanov@nginx.com 306*125Smax.romanov@nginx.com process = nxt_runtime_process_find(rt, pid); 307*125Smax.romanov@nginx.com 308*125Smax.romanov@nginx.com if (process) { 309*125Smax.romanov@nginx.com nxt_runtime_process_remove(rt, process); 310*125Smax.romanov@nginx.com } 311*125Smax.romanov@nginx.com } 312*125Smax.romanov@nginx.com 313*125Smax.romanov@nginx.com 314*125Smax.romanov@nginx.com void 31514Sigor@sysoev.ru nxt_port_empty_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 31611Sigor@sysoev.ru { 31711Sigor@sysoev.ru nxt_debug(task, "port empty handler"); 31811Sigor@sysoev.ru } 319