120Sigor@sysoev.ru 220Sigor@sysoev.ru /* 320Sigor@sysoev.ru * Copyright (C) Igor Sysoev 420Sigor@sysoev.ru * Copyright (C) Valentin V. Bartenev 520Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 620Sigor@sysoev.ru */ 720Sigor@sysoev.ru 853Sigor@sysoev.ru #include <nxt_router.h> 9115Sigor@sysoev.ru #include <nxt_conf.h> 10774Svbart@nginx.com #if (NXT_TLS) 11774Svbart@nginx.com #include <nxt_cert.h> 12774Svbart@nginx.com #endif 13431Sigor@sysoev.ru #include <nxt_http.h> 14743Smax.romanov@nginx.com #include <nxt_port_memory_int.h> 15743Smax.romanov@nginx.com #include <nxt_unit_request.h> 16743Smax.romanov@nginx.com #include <nxt_unit_response.h> 171131Smax.romanov@nginx.com #include <nxt_router_request.h> 181555Smax.romanov@nginx.com #include <nxt_app_queue.h> 191555Smax.romanov@nginx.com #include <nxt_port_queue.h> 2020Sigor@sysoev.ru 21115Sigor@sysoev.ru typedef struct { 22318Smax.romanov@nginx.com nxt_str_t type; 23507Smax.romanov@nginx.com uint32_t processes; 24507Smax.romanov@nginx.com uint32_t max_processes; 25507Smax.romanov@nginx.com uint32_t spare_processes; 26318Smax.romanov@nginx.com nxt_msec_t timeout; 27427Smax.romanov@nginx.com nxt_msec_t res_timeout; 28507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 29318Smax.romanov@nginx.com uint32_t requests; 30318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 31507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 321473Svbart@nginx.com nxt_conf_value_t *targets_value; 33133Sigor@sysoev.ru } nxt_router_app_conf_t; 34133Sigor@sysoev.ru 35133Sigor@sysoev.ru 36133Sigor@sysoev.ru typedef struct { 37964Sigor@sysoev.ru nxt_str_t pass; 38964Sigor@sysoev.ru nxt_str_t application; 39115Sigor@sysoev.ru } nxt_router_listener_conf_t; 40115Sigor@sysoev.ru 41115Sigor@sysoev.ru 42774Svbart@nginx.com #if (NXT_TLS) 43774Svbart@nginx.com 44774Svbart@nginx.com typedef struct { 45774Svbart@nginx.com nxt_str_t name; 46774Svbart@nginx.com nxt_socket_conf_t *conf; 47774Svbart@nginx.com 48774Svbart@nginx.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 49774Svbart@nginx.com } nxt_router_tlssock_t; 50774Svbart@nginx.com 51774Svbart@nginx.com #endif 52774Svbart@nginx.com 53774Svbart@nginx.com 54198Sigor@sysoev.ru typedef struct { 55198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 56198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 57198Sigor@sysoev.ru } nxt_socket_rpc_t; 58198Sigor@sysoev.ru 59198Sigor@sysoev.ru 60507Smax.romanov@nginx.com typedef struct { 61507Smax.romanov@nginx.com nxt_app_t *app; 62507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 63507Smax.romanov@nginx.com } nxt_app_rpc_t; 64507Smax.romanov@nginx.com 65507Smax.romanov@nginx.com 661488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, 671488St.nateldemoura@f5.com nxt_mp_t *mp); 681488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data); 69662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 70662Smax.romanov@nginx.com nxt_port_t *controller_port); 71662Smax.romanov@nginx.com 72507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 73425Smax.romanov@nginx.com 741552Smax.romanov@nginx.com static void nxt_router_new_port_handler(nxt_task_t *task, 751552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 761552Smax.romanov@nginx.com static void nxt_router_conf_data_handler(nxt_task_t *task, 771552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 781552Smax.romanov@nginx.com static void nxt_router_remove_pid_handler(nxt_task_t *task, 791552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 801552Smax.romanov@nginx.com static void nxt_router_access_log_reopen_handler(nxt_task_t *task, 811552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 821552Smax.romanov@nginx.com 83139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 84198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 85198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 86139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 87139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 88139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 89139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 90193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 9153Sigor@sysoev.ru 92115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 93115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 941183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 951183Svbart@nginx.com nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); 96133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 971555Smax.romanov@nginx.com static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task, 981555Smax.romanov@nginx.com nxt_port_t *port); 991555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task, 1001555Smax.romanov@nginx.com nxt_port_t *port); 1011555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task, 1021555Smax.romanov@nginx.com nxt_port_t *port, nxt_fd_t fd); 103198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 104198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 105198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 106198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 107198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 108198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 109774Svbart@nginx.com #if (NXT_TLS) 110774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task, 111774Svbart@nginx.com nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls); 112774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task, 113774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 114774Svbart@nginx.com #endif 115507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 116507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 117507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 118507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 119507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 120507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 121359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 122359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 123359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 124359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 12553Sigor@sysoev.ru 12653Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 12753Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 12853Sigor@sysoev.ru const nxt_event_interface_t *interface); 129115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 130115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 131115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 132115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 133115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 134115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 135154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 136154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 137154Sigor@sysoev.ru nxt_work_handler_t handler); 138313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 139313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 140139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 141139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 14253Sigor@sysoev.ru 14353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 14453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 14553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 14653Sigor@sysoev.ru nxt_event_engine_t *engine); 147343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 148133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 14953Sigor@sysoev.ru 150315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 151315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 152315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 153315Sigor@sysoev.ru nxt_work_t *jobs); 15453Sigor@sysoev.ru 15553Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 1561545Smax.romanov@nginx.com static void nxt_router_rt_add_port(nxt_task_t *task, void *obj, 1571545Smax.romanov@nginx.com void *data); 15853Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 15953Sigor@sysoev.ru void *data); 16053Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 16153Sigor@sysoev.ru void *data); 16253Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 16353Sigor@sysoev.ru void *data); 164313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 165313Sigor@sysoev.ru void *data); 16653Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 16753Sigor@sysoev.ru void *data); 16853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 16953Sigor@sysoev.ru void *data); 1701547Smax.romanov@nginx.com static void nxt_router_req_headers_ack_handler(nxt_task_t *task, 1711547Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data); 172359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 173359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 17453Sigor@sysoev.ru 175630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 176630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 177630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 178630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 179630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 180630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 181630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 182630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 183630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 184630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 185630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 186630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 187651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 188651Svbart@nginx.com void *data); 189631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 190631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 191631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 192631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 193630Svbart@nginx.com 194343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 195343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 1961547Smax.romanov@nginx.com static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task, 1971547Smax.romanov@nginx.com nxt_port_t *app_port); 198343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 199343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 200343Smax.romanov@nginx.com 201753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 2021123Smax.romanov@nginx.com 203343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2041123Smax.romanov@nginx.com nxt_apr_action_t action); 2051547Smax.romanov@nginx.com static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, 2061547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2071547Smax.romanov@nginx.com static void nxt_router_http_request_done(nxt_task_t *task, void *obj, 2081547Smax.romanov@nginx.com void *data); 209141Smax.romanov@nginx.com 210425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 2111547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2121007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 2131547Smax.romanov@nginx.com nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix); 214510Salexander.borisov@nginx.com 215318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 216507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 217507Smax.romanov@nginx.com void *data); 218507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 219507Smax.romanov@nginx.com void *data); 220753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 221507Smax.romanov@nginx.com void *data); 222753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 223431Sigor@sysoev.ru 224431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 225431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 226141Smax.romanov@nginx.com 227753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 228753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 229753Smax.romanov@nginx.com 2301547Smax.romanov@nginx.com static void nxt_router_http_request_release_post(nxt_task_t *task, 2311007Salexander.borisov@nginx.com nxt_http_request_t *r); 2321007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 2331007Salexander.borisov@nginx.com void *data); 2341321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 2351545Smax.romanov@nginx.com static void nxt_router_get_port_handler(nxt_task_t *task, 2361545Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2371546Smax.romanov@nginx.com static void nxt_router_get_mmap_handler(nxt_task_t *task, 2381546Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2391007Salexander.borisov@nginx.com 2401149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2411131Smax.romanov@nginx.com 242119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 24320Sigor@sysoev.ru 244743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 245743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 246743Smax.romanov@nginx.com 247743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 248804Svbart@nginx.com &empty_prefix, 249743Smax.romanov@nginx.com &http_prefix, 250743Smax.romanov@nginx.com &http_prefix, 251743Smax.romanov@nginx.com &http_prefix, 252743Smax.romanov@nginx.com &http_prefix, 253977Smax.romanov@gmail.com &empty_prefix, 254216Sigor@sysoev.ru }; 255216Sigor@sysoev.ru 256216Sigor@sysoev.ru 2571488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_router_process_port_handlers = { 2581488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 259662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 2601545Smax.romanov@nginx.com .get_port = nxt_router_get_port_handler, 261662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 262662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2631546Smax.romanov@nginx.com .get_mmap = nxt_router_get_mmap_handler, 264662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 265662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 266662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 267662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 268662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2691321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 270662Smax.romanov@nginx.com }; 271662Smax.romanov@nginx.com 272662Smax.romanov@nginx.com 2731488St.nateldemoura@f5.com const nxt_process_init_t nxt_router_process = { 2741488St.nateldemoura@f5.com .name = "router", 2751488St.nateldemoura@f5.com .type = NXT_PROCESS_ROUTER, 2761488St.nateldemoura@f5.com .prefork = nxt_router_prefork, 2771488St.nateldemoura@f5.com .restart = 1, 2781488St.nateldemoura@f5.com .setup = nxt_process_core_setup, 2791488St.nateldemoura@f5.com .start = nxt_router_start, 2801488St.nateldemoura@f5.com .port_handlers = &nxt_router_process_port_handlers, 2811488St.nateldemoura@f5.com .signals = nxt_process_signals, 2821488St.nateldemoura@f5.com }; 2831488St.nateldemoura@f5.com 2841488St.nateldemoura@f5.com 2851509Sigor@sysoev.ru /* Queues of nxt_socket_conf_t */ 2861509Sigor@sysoev.ru nxt_queue_t creating_sockets; 2871509Sigor@sysoev.ru nxt_queue_t pending_sockets; 2881509Sigor@sysoev.ru nxt_queue_t updating_sockets; 2891509Sigor@sysoev.ru nxt_queue_t keeping_sockets; 2901509Sigor@sysoev.ru nxt_queue_t deleting_sockets; 2911509Sigor@sysoev.ru 2921509Sigor@sysoev.ru 2931488St.nateldemoura@f5.com static nxt_int_t 2941488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) 2951488St.nateldemoura@f5.com { 2961488St.nateldemoura@f5.com nxt_runtime_stop_app_processes(task, task->thread->runtime); 2971488St.nateldemoura@f5.com 2981488St.nateldemoura@f5.com return NXT_OK; 2991488St.nateldemoura@f5.com } 3001488St.nateldemoura@f5.com 3011488St.nateldemoura@f5.com 3021488St.nateldemoura@f5.com static nxt_int_t 3031488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data) 30420Sigor@sysoev.ru { 305141Smax.romanov@nginx.com nxt_int_t ret; 306662Smax.romanov@nginx.com nxt_port_t *controller_port; 307141Smax.romanov@nginx.com nxt_router_t *router; 308141Smax.romanov@nginx.com nxt_runtime_t *rt; 309141Smax.romanov@nginx.com 310141Smax.romanov@nginx.com rt = task->thread->runtime; 31153Sigor@sysoev.ru 3121488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "router started"); 3131488St.nateldemoura@f5.com 314771Sigor@sysoev.ru #if (NXT_TLS) 315771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 316771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 317771Sigor@sysoev.ru return NXT_ERROR; 318771Sigor@sysoev.ru } 319771Sigor@sysoev.ru 320771Sigor@sysoev.ru ret = rt->tls->library_init(task); 321771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 322771Sigor@sysoev.ru return ret; 323771Sigor@sysoev.ru } 324771Sigor@sysoev.ru #endif 325771Sigor@sysoev.ru 3261459Smax.romanov@nginx.com ret = nxt_http_init(task); 32788Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 32888Smax.romanov@nginx.com return ret; 32988Smax.romanov@nginx.com } 33088Smax.romanov@nginx.com 33153Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 33253Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 33353Sigor@sysoev.ru return NXT_ERROR; 33453Sigor@sysoev.ru } 33553Sigor@sysoev.ru 33653Sigor@sysoev.ru nxt_queue_init(&router->engines); 33753Sigor@sysoev.ru nxt_queue_init(&router->sockets); 338133Sigor@sysoev.ru nxt_queue_init(&router->apps); 33953Sigor@sysoev.ru 340119Smax.romanov@nginx.com nxt_router = router; 341119Smax.romanov@nginx.com 342662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 343662Smax.romanov@nginx.com if (controller_port != NULL) { 344662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 345662Smax.romanov@nginx.com } 346662Smax.romanov@nginx.com 347115Sigor@sysoev.ru return NXT_OK; 348115Sigor@sysoev.ru } 349115Sigor@sysoev.ru 350115Sigor@sysoev.ru 351343Smax.romanov@nginx.com static void 352662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 353662Smax.romanov@nginx.com { 354662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 355662Smax.romanov@nginx.com -1, 0, 0, NULL); 356662Smax.romanov@nginx.com } 357662Smax.romanov@nginx.com 358662Smax.romanov@nginx.com 359662Smax.romanov@nginx.com static void 360507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 361507Smax.romanov@nginx.com void *data) 362167Smax.romanov@nginx.com { 363343Smax.romanov@nginx.com size_t size; 364343Smax.romanov@nginx.com uint32_t stream; 365430Sigor@sysoev.ru nxt_mp_t *mp; 366648Svbart@nginx.com nxt_int_t ret; 367343Smax.romanov@nginx.com nxt_app_t *app; 368343Smax.romanov@nginx.com nxt_buf_t *b; 369343Smax.romanov@nginx.com nxt_port_t *main_port; 370343Smax.romanov@nginx.com nxt_runtime_t *rt; 371343Smax.romanov@nginx.com 372343Smax.romanov@nginx.com app = data; 373167Smax.romanov@nginx.com 374167Smax.romanov@nginx.com rt = task->thread->runtime; 375240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 376167Smax.romanov@nginx.com 377507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 378343Smax.romanov@nginx.com 379343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 380343Smax.romanov@nginx.com 381343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 382343Smax.romanov@nginx.com 383343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 384343Smax.romanov@nginx.com goto failed; 385167Smax.romanov@nginx.com } 386167Smax.romanov@nginx.com 387343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 388343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 389343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 390343Smax.romanov@nginx.com 391753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 392753Smax.romanov@nginx.com 393343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 394343Smax.romanov@nginx.com nxt_router_app_port_ready, 395343Smax.romanov@nginx.com nxt_router_app_port_error, 396753Smax.romanov@nginx.com -1, app->joint); 397343Smax.romanov@nginx.com 398343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 399753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 400753Smax.romanov@nginx.com 401343Smax.romanov@nginx.com goto failed; 402343Smax.romanov@nginx.com } 403343Smax.romanov@nginx.com 4041488St.nateldemoura@f5.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS, 4051488St.nateldemoura@f5.com -1, stream, port->id, b); 406648Svbart@nginx.com 407648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 408648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 409753Smax.romanov@nginx.com 410753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 411753Smax.romanov@nginx.com 412648Svbart@nginx.com goto failed; 413648Svbart@nginx.com } 414343Smax.romanov@nginx.com 415753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 416753Smax.romanov@nginx.com 417343Smax.romanov@nginx.com return; 418343Smax.romanov@nginx.com 419343Smax.romanov@nginx.com failed: 420343Smax.romanov@nginx.com 421648Svbart@nginx.com if (b != NULL) { 422648Svbart@nginx.com mp = b->data; 423648Svbart@nginx.com nxt_mp_free(mp, b); 424648Svbart@nginx.com nxt_mp_release(mp); 425648Svbart@nginx.com } 426648Svbart@nginx.com 427343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 428343Smax.romanov@nginx.com 429507Smax.romanov@nginx.com app->pending_processes--; 430343Smax.romanov@nginx.com 431343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 432343Smax.romanov@nginx.com 433343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 434167Smax.romanov@nginx.com } 435167Smax.romanov@nginx.com 436167Smax.romanov@nginx.com 437753Smax.romanov@nginx.com static void 438753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 439753Smax.romanov@nginx.com { 440753Smax.romanov@nginx.com app_joint->use_count += i; 441753Smax.romanov@nginx.com 442753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 443753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 444753Smax.romanov@nginx.com 445753Smax.romanov@nginx.com nxt_free(app_joint); 446753Smax.romanov@nginx.com } 447753Smax.romanov@nginx.com } 448753Smax.romanov@nginx.com 449753Smax.romanov@nginx.com 450343Smax.romanov@nginx.com static nxt_int_t 451507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 452141Smax.romanov@nginx.com { 453343Smax.romanov@nginx.com nxt_int_t res; 454343Smax.romanov@nginx.com nxt_port_t *router_port; 455343Smax.romanov@nginx.com nxt_runtime_t *rt; 456343Smax.romanov@nginx.com 4571549Smax.romanov@nginx.com nxt_debug(task, "app '%V' start process", &app->name); 4581549Smax.romanov@nginx.com 459343Smax.romanov@nginx.com rt = task->thread->runtime; 460343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 461343Smax.romanov@nginx.com 462343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 463343Smax.romanov@nginx.com 464507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 465343Smax.romanov@nginx.com app); 466343Smax.romanov@nginx.com 467343Smax.romanov@nginx.com if (res == NXT_OK) { 468343Smax.romanov@nginx.com return res; 469318Smax.romanov@nginx.com } 470318Smax.romanov@nginx.com 471343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 472343Smax.romanov@nginx.com 473507Smax.romanov@nginx.com app->pending_processes--; 474343Smax.romanov@nginx.com 475343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 476343Smax.romanov@nginx.com 477343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 478343Smax.romanov@nginx.com 479343Smax.romanov@nginx.com return NXT_ERROR; 480318Smax.romanov@nginx.com } 481318Smax.romanov@nginx.com 482318Smax.romanov@nginx.com 483423Smax.romanov@nginx.com nxt_inline nxt_bool_t 4841555Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data) 485423Smax.romanov@nginx.com { 4861555Smax.romanov@nginx.com nxt_buf_t *b, *next; 4871555Smax.romanov@nginx.com nxt_bool_t cancelled; 4881555Smax.romanov@nginx.com nxt_msg_info_t *msg_info; 4891555Smax.romanov@nginx.com 4901555Smax.romanov@nginx.com msg_info = &req_rpc_data->msg_info; 491423Smax.romanov@nginx.com 492423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 493423Smax.romanov@nginx.com return 0; 494423Smax.romanov@nginx.com } 495423Smax.romanov@nginx.com 4961555Smax.romanov@nginx.com cancelled = nxt_app_queue_cancel(req_rpc_data->app->shared_port->queue, 4971555Smax.romanov@nginx.com msg_info->tracking_cookie, 4981555Smax.romanov@nginx.com req_rpc_data->stream); 499423Smax.romanov@nginx.com 500423Smax.romanov@nginx.com if (cancelled) { 5011555Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", 5021555Smax.romanov@nginx.com req_rpc_data->stream); 503423Smax.romanov@nginx.com } 504423Smax.romanov@nginx.com 505423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 506423Smax.romanov@nginx.com next = b->next; 5071269Sigor@sysoev.ru b->next = NULL; 508423Smax.romanov@nginx.com 509423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 510423Smax.romanov@nginx.com 511423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 512423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 513423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 514423Smax.romanov@nginx.com } 515423Smax.romanov@nginx.com } 516423Smax.romanov@nginx.com 517423Smax.romanov@nginx.com msg_info->buf = NULL; 518423Smax.romanov@nginx.com 519423Smax.romanov@nginx.com return cancelled; 520423Smax.romanov@nginx.com } 521423Smax.romanov@nginx.com 522423Smax.romanov@nginx.com 523425Smax.romanov@nginx.com nxt_inline nxt_bool_t 524425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 525425Smax.romanov@nginx.com { 526425Smax.romanov@nginx.com if (lnk->next != NULL) { 527425Smax.romanov@nginx.com nxt_queue_remove(lnk); 528425Smax.romanov@nginx.com 529425Smax.romanov@nginx.com lnk->next = NULL; 530425Smax.romanov@nginx.com 531425Smax.romanov@nginx.com return 1; 532425Smax.romanov@nginx.com } 533425Smax.romanov@nginx.com 534425Smax.romanov@nginx.com return 0; 535425Smax.romanov@nginx.com } 536425Smax.romanov@nginx.com 537425Smax.romanov@nginx.com 538343Smax.romanov@nginx.com nxt_inline void 5391123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task, 5401123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 541343Smax.romanov@nginx.com { 5421547Smax.romanov@nginx.com nxt_http_request_t *r; 5431547Smax.romanov@nginx.com 5441555Smax.romanov@nginx.com nxt_router_msg_cancel(task, req_rpc_data); 5451123Smax.romanov@nginx.com 5461123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 5471123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_rpc_data->app_port, 5481123Smax.romanov@nginx.com req_rpc_data->apr_action); 5491123Smax.romanov@nginx.com 5501123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 5511123Smax.romanov@nginx.com } 5521123Smax.romanov@nginx.com 5531123Smax.romanov@nginx.com if (req_rpc_data->app != NULL) { 5541123Smax.romanov@nginx.com nxt_router_app_use(task, req_rpc_data->app, -1); 5551123Smax.romanov@nginx.com 5561123Smax.romanov@nginx.com req_rpc_data->app = NULL; 5571123Smax.romanov@nginx.com } 5581123Smax.romanov@nginx.com 5591547Smax.romanov@nginx.com r = req_rpc_data->request; 5601547Smax.romanov@nginx.com 5611547Smax.romanov@nginx.com if (r != NULL) { 5621547Smax.romanov@nginx.com r->timer_data = NULL; 5631547Smax.romanov@nginx.com 5641547Smax.romanov@nginx.com nxt_router_http_request_release_post(task, r); 5651547Smax.romanov@nginx.com 5661547Smax.romanov@nginx.com r->req_rpc_data = NULL; 5671123Smax.romanov@nginx.com req_rpc_data->request = NULL; 568346Smax.romanov@nginx.com } 5691547Smax.romanov@nginx.com 5701547Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1) { 5711547Smax.romanov@nginx.com nxt_fd_close(req_rpc_data->msg_info.body_fd); 5721547Smax.romanov@nginx.com 5731547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 5741547Smax.romanov@nginx.com } 5751547Smax.romanov@nginx.com 5761547Smax.romanov@nginx.com if (req_rpc_data->rpc_cancel) { 5771547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 5781547Smax.romanov@nginx.com 5791547Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, 5801547Smax.romanov@nginx.com req_rpc_data->stream); 5811547Smax.romanov@nginx.com } 582343Smax.romanov@nginx.com } 583343Smax.romanov@nginx.com 584343Smax.romanov@nginx.com 5851552Smax.romanov@nginx.com static void 586141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 587141Smax.romanov@nginx.com { 5881555Smax.romanov@nginx.com nxt_int_t res; 5891547Smax.romanov@nginx.com nxt_app_t *app; 5901547Smax.romanov@nginx.com nxt_port_t *port, *main_app_port; 5911547Smax.romanov@nginx.com nxt_runtime_t *rt; 5921547Smax.romanov@nginx.com 593141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 594141Smax.romanov@nginx.com 5951547Smax.romanov@nginx.com port = msg->u.new_port; 5961547Smax.romanov@nginx.com 5971547Smax.romanov@nginx.com if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) { 598662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 599662Smax.romanov@nginx.com } 600662Smax.romanov@nginx.com 6011547Smax.romanov@nginx.com if (port == NULL || port->type != NXT_PROCESS_APP) { 6021547Smax.romanov@nginx.com 6031547Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 6041547Smax.romanov@nginx.com return; 6051547Smax.romanov@nginx.com } 6061547Smax.romanov@nginx.com 6071547Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 6081555Smax.romanov@nginx.com 6091555Smax.romanov@nginx.com } else { 610*1558Smax.romanov@nginx.com if (msg->fd[1] != -1) { 611*1558Smax.romanov@nginx.com res = nxt_router_port_queue_map(task, port, msg->fd[1]); 6121555Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 6131555Smax.romanov@nginx.com return; 6141555Smax.romanov@nginx.com } 6151555Smax.romanov@nginx.com 616*1558Smax.romanov@nginx.com nxt_fd_close(msg->fd[1]); 617*1558Smax.romanov@nginx.com msg->fd[1] = -1; 6181555Smax.romanov@nginx.com } 6191547Smax.romanov@nginx.com } 6201547Smax.romanov@nginx.com 6211547Smax.romanov@nginx.com if (msg->port_msg.stream != 0) { 6221547Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 623141Smax.romanov@nginx.com return; 624141Smax.romanov@nginx.com } 625141Smax.romanov@nginx.com 6261547Smax.romanov@nginx.com /* 6271547Smax.romanov@nginx.com * Port with "id == 0" is application 'main' port and it always 6281547Smax.romanov@nginx.com * should come with non-zero stream. 6291547Smax.romanov@nginx.com */ 6301547Smax.romanov@nginx.com nxt_assert(port->id != 0); 6311547Smax.romanov@nginx.com 6321547Smax.romanov@nginx.com /* Find 'main' app port and get app reference. */ 6331547Smax.romanov@nginx.com rt = task->thread->runtime; 6341547Smax.romanov@nginx.com 6351547Smax.romanov@nginx.com /* 6361547Smax.romanov@nginx.com * It is safe to access 'runtime->ports' hash because 'NEW_PORT' 6371547Smax.romanov@nginx.com * sent to main port (with id == 0) and processed in main thread. 6381547Smax.romanov@nginx.com */ 6391547Smax.romanov@nginx.com main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0); 6401547Smax.romanov@nginx.com nxt_assert(main_app_port != NULL); 6411547Smax.romanov@nginx.com 6421547Smax.romanov@nginx.com app = main_app_port->app; 6431547Smax.romanov@nginx.com nxt_assert(app != NULL); 6441547Smax.romanov@nginx.com 6451547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 6461547Smax.romanov@nginx.com 6471547Smax.romanov@nginx.com /* TODO here should be find-and-add code because there can be 6481547Smax.romanov@nginx.com port waiters in port_hash */ 6491547Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 6501547Smax.romanov@nginx.com app->port_hash_count++; 6511547Smax.romanov@nginx.com 6521547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 6531547Smax.romanov@nginx.com 6541547Smax.romanov@nginx.com port->app = app; 6551547Smax.romanov@nginx.com port->main_app_port = main_app_port; 656141Smax.romanov@nginx.com } 657141Smax.romanov@nginx.com 658141Smax.romanov@nginx.com 6591552Smax.romanov@nginx.com static void 660139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 661115Sigor@sysoev.ru { 6621526Smax.romanov@nginx.com void *p; 6631526Smax.romanov@nginx.com size_t size; 664198Sigor@sysoev.ru nxt_int_t ret; 665139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 666139Sigor@sysoev.ru 667139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 668139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 669139Sigor@sysoev.ru return; 67053Sigor@sysoev.ru } 67153Sigor@sysoev.ru 672*1558Smax.romanov@nginx.com if (nxt_slow_path(msg->fd[0] == -1)) { 6731526Smax.romanov@nginx.com nxt_alert(task, "conf_data_handler: invalid file shm fd"); 6741526Smax.romanov@nginx.com return; 6751526Smax.romanov@nginx.com } 6761526Smax.romanov@nginx.com 6771526Smax.romanov@nginx.com if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) { 6781526Smax.romanov@nginx.com nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)", 6791526Smax.romanov@nginx.com (int) nxt_buf_mem_used_size(&msg->buf->mem)); 6801526Smax.romanov@nginx.com 681*1558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 682*1558Smax.romanov@nginx.com msg->fd[0] = -1; 6831526Smax.romanov@nginx.com 6841526Smax.romanov@nginx.com return; 6851526Smax.romanov@nginx.com } 6861526Smax.romanov@nginx.com 6871526Smax.romanov@nginx.com nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t)); 6881526Smax.romanov@nginx.com 689*1558Smax.romanov@nginx.com p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0); 690*1558Smax.romanov@nginx.com 691*1558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 692*1558Smax.romanov@nginx.com msg->fd[0] = -1; 6931526Smax.romanov@nginx.com 6941526Smax.romanov@nginx.com if (nxt_slow_path(p == MAP_FAILED)) { 6951526Smax.romanov@nginx.com return; 6961526Smax.romanov@nginx.com } 6971526Smax.romanov@nginx.com 6981526Smax.romanov@nginx.com nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p); 699423Smax.romanov@nginx.com 700591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 701139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 702139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 703198Sigor@sysoev.ru msg->port_msg.pid, 704198Sigor@sysoev.ru msg->port_msg.reply_port); 705198Sigor@sysoev.ru 706779Smax.romanov@nginx.com if (nxt_slow_path(tmcf->port == NULL)) { 707779Smax.romanov@nginx.com nxt_alert(task, "reply port not found"); 708779Smax.romanov@nginx.com 7091526Smax.romanov@nginx.com goto fail; 710779Smax.romanov@nginx.com } 711779Smax.romanov@nginx.com 712779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 713779Smax.romanov@nginx.com 7141526Smax.romanov@nginx.com ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size)); 715198Sigor@sysoev.ru 716198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 717198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 718198Sigor@sysoev.ru 719198Sigor@sysoev.ru } else { 720198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 721139Sigor@sysoev.ru } 7221526Smax.romanov@nginx.com 7231526Smax.romanov@nginx.com fail: 7241526Smax.romanov@nginx.com 7251526Smax.romanov@nginx.com nxt_mem_munmap(p, size); 72653Sigor@sysoev.ru } 72753Sigor@sysoev.ru 72853Sigor@sysoev.ru 729347Smax.romanov@nginx.com static void 730507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 731507Smax.romanov@nginx.com void *data) 732347Smax.romanov@nginx.com { 733347Smax.romanov@nginx.com union { 734347Smax.romanov@nginx.com nxt_pid_t removed_pid; 735347Smax.romanov@nginx.com void *data; 736347Smax.romanov@nginx.com } u; 737347Smax.romanov@nginx.com 738347Smax.romanov@nginx.com u.data = data; 739347Smax.romanov@nginx.com 740347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 741347Smax.romanov@nginx.com } 742347Smax.romanov@nginx.com 743347Smax.romanov@nginx.com 7441552Smax.romanov@nginx.com static void 745192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 746192Smax.romanov@nginx.com { 747347Smax.romanov@nginx.com nxt_event_engine_t *engine; 748318Smax.romanov@nginx.com 749192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 750192Smax.romanov@nginx.com 751318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 752318Smax.romanov@nginx.com { 7531486Smax.romanov@nginx.com if (nxt_fast_path(engine->port != NULL)) { 7541486Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 7551486Smax.romanov@nginx.com msg->u.data); 7561486Smax.romanov@nginx.com } 757318Smax.romanov@nginx.com } 758318Smax.romanov@nginx.com nxt_queue_loop; 759318Smax.romanov@nginx.com 7601085Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 7611085Smax.romanov@nginx.com return; 7621085Smax.romanov@nginx.com } 7631085Smax.romanov@nginx.com 764192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 765192Smax.romanov@nginx.com 766192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 767192Smax.romanov@nginx.com } 768192Smax.romanov@nginx.com 769192Smax.romanov@nginx.com 77053Sigor@sysoev.ru static nxt_router_temp_conf_t * 771139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 77253Sigor@sysoev.ru { 77365Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 77453Sigor@sysoev.ru nxt_router_conf_t *rtcf; 77553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 77653Sigor@sysoev.ru 77765Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 77853Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 77953Sigor@sysoev.ru return NULL; 78053Sigor@sysoev.ru } 78153Sigor@sysoev.ru 78265Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 78353Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 78453Sigor@sysoev.ru goto fail; 78553Sigor@sysoev.ru } 78653Sigor@sysoev.ru 78753Sigor@sysoev.ru rtcf->mem_pool = mp; 78853Sigor@sysoev.ru 78965Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 79053Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 79153Sigor@sysoev.ru goto fail; 79253Sigor@sysoev.ru } 79353Sigor@sysoev.ru 79465Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 79553Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 79653Sigor@sysoev.ru goto temp_fail; 79753Sigor@sysoev.ru } 79853Sigor@sysoev.ru 79953Sigor@sysoev.ru tmcf->mem_pool = tmp; 800591Sigor@sysoev.ru tmcf->router_conf = rtcf; 801139Sigor@sysoev.ru tmcf->count = 1; 802139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 80353Sigor@sysoev.ru 80453Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 80553Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 80653Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 80753Sigor@sysoev.ru goto temp_fail; 80853Sigor@sysoev.ru } 80953Sigor@sysoev.ru 8101509Sigor@sysoev.ru nxt_queue_init(&creating_sockets); 8111509Sigor@sysoev.ru nxt_queue_init(&pending_sockets); 8121509Sigor@sysoev.ru nxt_queue_init(&updating_sockets); 8131509Sigor@sysoev.ru nxt_queue_init(&keeping_sockets); 8141509Sigor@sysoev.ru nxt_queue_init(&deleting_sockets); 815416Smax.romanov@nginx.com 816774Svbart@nginx.com #if (NXT_TLS) 817774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 818774Svbart@nginx.com #endif 819774Svbart@nginx.com 820133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 821133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 82253Sigor@sysoev.ru 82353Sigor@sysoev.ru return tmcf; 82453Sigor@sysoev.ru 82553Sigor@sysoev.ru temp_fail: 82653Sigor@sysoev.ru 82765Sigor@sysoev.ru nxt_mp_destroy(tmp); 82853Sigor@sysoev.ru 82953Sigor@sysoev.ru fail: 83053Sigor@sysoev.ru 83165Sigor@sysoev.ru nxt_mp_destroy(mp); 83253Sigor@sysoev.ru 83353Sigor@sysoev.ru return NULL; 83453Sigor@sysoev.ru } 83553Sigor@sysoev.ru 83653Sigor@sysoev.ru 837507Smax.romanov@nginx.com nxt_inline nxt_bool_t 838507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 839507Smax.romanov@nginx.com { 840507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 841507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 842507Smax.romanov@nginx.com } 843507Smax.romanov@nginx.com 844507Smax.romanov@nginx.com 845507Smax.romanov@nginx.com nxt_inline nxt_bool_t 846507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 847507Smax.romanov@nginx.com { 8481547Smax.romanov@nginx.com return (app->active_requests 8491547Smax.romanov@nginx.com > app->port_hash_count + app->pending_processes) 8501547Smax.romanov@nginx.com || (app->spare_processes 8511547Smax.romanov@nginx.com > app->idle_processes + app->pending_processes); 852507Smax.romanov@nginx.com } 853507Smax.romanov@nginx.com 854507Smax.romanov@nginx.com 855198Sigor@sysoev.ru static void 856198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 857139Sigor@sysoev.ru { 858139Sigor@sysoev.ru nxt_int_t ret; 859507Smax.romanov@nginx.com nxt_app_t *app; 860139Sigor@sysoev.ru nxt_router_t *router; 861139Sigor@sysoev.ru nxt_runtime_t *rt; 862198Sigor@sysoev.ru nxt_queue_link_t *qlk; 863198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 864630Svbart@nginx.com nxt_router_conf_t *rtcf; 865198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 866139Sigor@sysoev.ru const nxt_event_interface_t *interface; 867774Svbart@nginx.com #if (NXT_TLS) 868774Svbart@nginx.com nxt_router_tlssock_t *tls; 869774Svbart@nginx.com #endif 870139Sigor@sysoev.ru 871198Sigor@sysoev.ru tmcf = obj; 872198Sigor@sysoev.ru 8731509Sigor@sysoev.ru qlk = nxt_queue_first(&pending_sockets); 8741509Sigor@sysoev.ru 8751509Sigor@sysoev.ru if (qlk != nxt_queue_tail(&pending_sockets)) { 876198Sigor@sysoev.ru nxt_queue_remove(qlk); 8771509Sigor@sysoev.ru nxt_queue_insert_tail(&creating_sockets, qlk); 878198Sigor@sysoev.ru 879198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 880198Sigor@sysoev.ru 881198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 882198Sigor@sysoev.ru 883198Sigor@sysoev.ru return; 884139Sigor@sysoev.ru } 885139Sigor@sysoev.ru 886774Svbart@nginx.com #if (NXT_TLS) 887774Svbart@nginx.com qlk = nxt_queue_first(&tmcf->tls); 888774Svbart@nginx.com 889774Svbart@nginx.com if (qlk != nxt_queue_tail(&tmcf->tls)) { 890774Svbart@nginx.com nxt_queue_remove(qlk); 891774Svbart@nginx.com 892774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 893774Svbart@nginx.com 894774Svbart@nginx.com nxt_router_tls_rpc_create(task, tmcf, tls); 895774Svbart@nginx.com return; 896774Svbart@nginx.com } 897774Svbart@nginx.com #endif 898774Svbart@nginx.com 899507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 900507Smax.romanov@nginx.com 901507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 902507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 903507Smax.romanov@nginx.com return; 904507Smax.romanov@nginx.com } 905507Smax.romanov@nginx.com 906507Smax.romanov@nginx.com } nxt_queue_loop; 907507Smax.romanov@nginx.com 908630Svbart@nginx.com rtcf = tmcf->router_conf; 909630Svbart@nginx.com 910630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 911630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 912630Svbart@nginx.com return; 913630Svbart@nginx.com } 914630Svbart@nginx.com 915139Sigor@sysoev.ru rt = task->thread->runtime; 916139Sigor@sysoev.ru 917139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 918139Sigor@sysoev.ru 919630Svbart@nginx.com router = rtcf->router; 920198Sigor@sysoev.ru 921139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 922139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 923198Sigor@sysoev.ru goto fail; 924139Sigor@sysoev.ru } 925139Sigor@sysoev.ru 926139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 927139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 928198Sigor@sysoev.ru goto fail; 929139Sigor@sysoev.ru } 930139Sigor@sysoev.ru 931343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 932139Sigor@sysoev.ru 933315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 934139Sigor@sysoev.ru 9351509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &updating_sockets); 9361509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &creating_sockets); 937139Sigor@sysoev.ru 938630Svbart@nginx.com router->access_log = rtcf->access_log; 939630Svbart@nginx.com 940198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 941198Sigor@sysoev.ru 942198Sigor@sysoev.ru return; 943198Sigor@sysoev.ru 944198Sigor@sysoev.ru fail: 945198Sigor@sysoev.ru 946198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 947198Sigor@sysoev.ru 948198Sigor@sysoev.ru return; 949139Sigor@sysoev.ru } 950139Sigor@sysoev.ru 951139Sigor@sysoev.ru 952139Sigor@sysoev.ru static void 953139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 954139Sigor@sysoev.ru { 955153Sigor@sysoev.ru nxt_joint_job_t *job; 956153Sigor@sysoev.ru 957153Sigor@sysoev.ru job = obj; 958153Sigor@sysoev.ru 959198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 960139Sigor@sysoev.ru } 961139Sigor@sysoev.ru 962139Sigor@sysoev.ru 963139Sigor@sysoev.ru static void 964198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 965139Sigor@sysoev.ru { 9661542Smax.romanov@nginx.com uint32_t count; 9671542Smax.romanov@nginx.com nxt_router_conf_t *rtcf; 9681542Smax.romanov@nginx.com nxt_thread_spinlock_t *lock; 9691542Smax.romanov@nginx.com 9701542Smax.romanov@nginx.com nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count); 9711542Smax.romanov@nginx.com 9721542Smax.romanov@nginx.com if (--tmcf->count > 0) { 9731542Smax.romanov@nginx.com return; 9741542Smax.romanov@nginx.com } 9751542Smax.romanov@nginx.com 9761542Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 9771542Smax.romanov@nginx.com 9781542Smax.romanov@nginx.com rtcf = tmcf->router_conf; 9791542Smax.romanov@nginx.com 9801542Smax.romanov@nginx.com lock = &rtcf->router->lock; 9811542Smax.romanov@nginx.com 9821542Smax.romanov@nginx.com nxt_thread_spin_lock(lock); 9831542Smax.romanov@nginx.com 9841542Smax.romanov@nginx.com count = rtcf->count; 9851542Smax.romanov@nginx.com 9861542Smax.romanov@nginx.com nxt_thread_spin_unlock(lock); 9871542Smax.romanov@nginx.com 9881542Smax.romanov@nginx.com nxt_debug(task, "rtcf %p: %D", rtcf, count); 9891542Smax.romanov@nginx.com 9901542Smax.romanov@nginx.com if (count == 0) { 9911542Smax.romanov@nginx.com nxt_http_routes_cleanup(task, rtcf->routes); 9921542Smax.romanov@nginx.com 9931542Smax.romanov@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 9941542Smax.romanov@nginx.com 9951542Smax.romanov@nginx.com nxt_mp_destroy(rtcf->mem_pool); 9961542Smax.romanov@nginx.com } 9971542Smax.romanov@nginx.com 9981542Smax.romanov@nginx.com nxt_mp_destroy(tmcf->mem_pool); 999139Sigor@sysoev.ru } 1000139Sigor@sysoev.ru 1001139Sigor@sysoev.ru 1002139Sigor@sysoev.ru static void 1003139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1004139Sigor@sysoev.ru { 1005507Smax.romanov@nginx.com nxt_app_t *app; 1006568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1007148Sigor@sysoev.ru nxt_socket_t s; 1008149Sigor@sysoev.ru nxt_router_t *router; 1009148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1010148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1011630Svbart@nginx.com nxt_router_conf_t *rtcf; 1012148Sigor@sysoev.ru 1013564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1014198Sigor@sysoev.ru 10151509Sigor@sysoev.ru for (qlk = nxt_queue_first(&creating_sockets); 10161509Sigor@sysoev.ru qlk != nxt_queue_tail(&creating_sockets); 1017148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1018148Sigor@sysoev.ru { 1019148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1020359Sigor@sysoev.ru s = skcf->listen->socket; 1021148Sigor@sysoev.ru 1022148Sigor@sysoev.ru if (s != -1) { 1023148Sigor@sysoev.ru nxt_socket_close(task, s); 1024148Sigor@sysoev.ru } 1025148Sigor@sysoev.ru 1026359Sigor@sysoev.ru nxt_free(skcf->listen); 1027148Sigor@sysoev.ru } 1028148Sigor@sysoev.ru 1029568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 10301509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &updating_sockets); 10311509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &pending_sockets); 10321509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &creating_sockets); 1033568Smax.romanov@nginx.com 1034964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1035964Sigor@sysoev.ru 1036964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 1037964Sigor@sysoev.ru 1038568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1039568Smax.romanov@nginx.com 10401264Sigor@sysoev.ru if (skcf->action != NULL) { 10411264Sigor@sysoev.ru nxt_http_action_cleanup(task, skcf->action); 1042568Smax.romanov@nginx.com } 1043568Smax.romanov@nginx.com 1044568Smax.romanov@nginx.com } nxt_queue_loop; 1045568Smax.romanov@nginx.com 1046507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1047507Smax.romanov@nginx.com 1048753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1049507Smax.romanov@nginx.com 1050507Smax.romanov@nginx.com } nxt_queue_loop; 1051507Smax.romanov@nginx.com 1052630Svbart@nginx.com router = rtcf->router; 1053149Sigor@sysoev.ru 10541509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &keeping_sockets); 10551509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &deleting_sockets); 1056149Sigor@sysoev.ru 1057416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1058416Smax.romanov@nginx.com 1059148Sigor@sysoev.ru // TODO: new engines and threads 1060148Sigor@sysoev.ru 1061630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1062630Svbart@nginx.com 1063630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1064139Sigor@sysoev.ru 1065193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 10661509Sigor@sysoev.ru 10671509Sigor@sysoev.ru nxt_mp_destroy(tmcf->mem_pool); 1068139Sigor@sysoev.ru } 1069139Sigor@sysoev.ru 1070139Sigor@sysoev.ru 1071139Sigor@sysoev.ru static void 1072139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1073193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1074139Sigor@sysoev.ru { 1075193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1076779Smax.romanov@nginx.com 1077779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1078779Smax.romanov@nginx.com 1079779Smax.romanov@nginx.com tmcf->port = NULL; 1080139Sigor@sysoev.ru } 1081139Sigor@sysoev.ru 1082139Sigor@sysoev.ru 1083115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1084115Sigor@sysoev.ru { 1085133Sigor@sysoev.ru nxt_string("listeners_threads"), 1086115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1087115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1088115Sigor@sysoev.ru }, 1089115Sigor@sysoev.ru }; 1090115Sigor@sysoev.ru 1091115Sigor@sysoev.ru 1092133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1093115Sigor@sysoev.ru { 1094133Sigor@sysoev.ru nxt_string("type"), 1095115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1096133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1097115Sigor@sysoev.ru }, 1098115Sigor@sysoev.ru 1099115Sigor@sysoev.ru { 1100507Smax.romanov@nginx.com nxt_string("limits"), 1101507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1102507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1103133Sigor@sysoev.ru }, 1104318Smax.romanov@nginx.com 1105318Smax.romanov@nginx.com { 1106507Smax.romanov@nginx.com nxt_string("processes"), 1107507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1108507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1109507Smax.romanov@nginx.com }, 1110507Smax.romanov@nginx.com 1111507Smax.romanov@nginx.com { 1112507Smax.romanov@nginx.com nxt_string("processes"), 1113318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1114507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1115318Smax.romanov@nginx.com }, 11161473Svbart@nginx.com 11171473Svbart@nginx.com { 11181473Svbart@nginx.com nxt_string("targets"), 11191473Svbart@nginx.com NXT_CONF_MAP_PTR, 11201473Svbart@nginx.com offsetof(nxt_router_app_conf_t, targets_value), 11211473Svbart@nginx.com }, 1122318Smax.romanov@nginx.com }; 1123318Smax.romanov@nginx.com 1124318Smax.romanov@nginx.com 1125318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1126318Smax.romanov@nginx.com { 1127318Smax.romanov@nginx.com nxt_string("timeout"), 1128318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1129318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1130318Smax.romanov@nginx.com }, 1131318Smax.romanov@nginx.com 1132318Smax.romanov@nginx.com { 1133427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1134427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1135427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1136427Smax.romanov@nginx.com }, 1137427Smax.romanov@nginx.com 1138427Smax.romanov@nginx.com { 1139318Smax.romanov@nginx.com nxt_string("requests"), 1140318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1141318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1142318Smax.romanov@nginx.com }, 1143133Sigor@sysoev.ru }; 1144133Sigor@sysoev.ru 1145133Sigor@sysoev.ru 1146507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1147507Smax.romanov@nginx.com { 1148507Smax.romanov@nginx.com nxt_string("spare"), 1149507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1150507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1151507Smax.romanov@nginx.com }, 1152507Smax.romanov@nginx.com 1153507Smax.romanov@nginx.com { 1154507Smax.romanov@nginx.com nxt_string("max"), 1155507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1156507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1157507Smax.romanov@nginx.com }, 1158507Smax.romanov@nginx.com 1159507Smax.romanov@nginx.com { 1160507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1161507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1162507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1163507Smax.romanov@nginx.com }, 1164507Smax.romanov@nginx.com }; 1165507Smax.romanov@nginx.com 1166507Smax.romanov@nginx.com 1167133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1168133Sigor@sysoev.ru { 1169964Sigor@sysoev.ru nxt_string("pass"), 1170964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1171964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1172964Sigor@sysoev.ru }, 1173964Sigor@sysoev.ru 1174964Sigor@sysoev.ru { 1175133Sigor@sysoev.ru nxt_string("application"), 1176964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1177133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1178115Sigor@sysoev.ru }, 1179115Sigor@sysoev.ru }; 1180115Sigor@sysoev.ru 1181115Sigor@sysoev.ru 1182115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1183115Sigor@sysoev.ru { 1184115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1185115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1186115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1187115Sigor@sysoev.ru }, 1188115Sigor@sysoev.ru 1189115Sigor@sysoev.ru { 1190115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1191115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1192115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1193115Sigor@sysoev.ru }, 1194115Sigor@sysoev.ru 1195115Sigor@sysoev.ru { 1196206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1197206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1198206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1199206Smax.romanov@nginx.com }, 1200206Smax.romanov@nginx.com 1201206Smax.romanov@nginx.com { 1202206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1203206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1204206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1205206Smax.romanov@nginx.com }, 1206206Smax.romanov@nginx.com 1207206Smax.romanov@nginx.com { 1208206Smax.romanov@nginx.com nxt_string("max_body_size"), 1209206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1210206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1211206Smax.romanov@nginx.com }, 1212206Smax.romanov@nginx.com 1213206Smax.romanov@nginx.com { 1214431Sigor@sysoev.ru nxt_string("idle_timeout"), 1215431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1216431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1217431Sigor@sysoev.ru }, 1218431Sigor@sysoev.ru 1219431Sigor@sysoev.ru { 1220115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1221115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1222115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1223115Sigor@sysoev.ru }, 1224206Smax.romanov@nginx.com 1225206Smax.romanov@nginx.com { 1226206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1227206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1228206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1229206Smax.romanov@nginx.com }, 1230431Sigor@sysoev.ru 1231431Sigor@sysoev.ru { 1232431Sigor@sysoev.ru nxt_string("send_timeout"), 1233431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1234431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1235431Sigor@sysoev.ru }, 12361403Smax.romanov@nginx.com 12371403Smax.romanov@nginx.com { 12381403Smax.romanov@nginx.com nxt_string("body_temp_path"), 12391403Smax.romanov@nginx.com NXT_CONF_MAP_STR, 12401403Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_temp_path), 12411403Smax.romanov@nginx.com }, 1242115Sigor@sysoev.ru }; 1243115Sigor@sysoev.ru 1244115Sigor@sysoev.ru 12451131Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_websocket_conf[] = { 12461131Smax.romanov@nginx.com { 12471131Smax.romanov@nginx.com nxt_string("max_frame_size"), 12481131Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 12491131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, max_frame_size), 12501131Smax.romanov@nginx.com }, 12511131Smax.romanov@nginx.com 12521131Smax.romanov@nginx.com { 12531131Smax.romanov@nginx.com nxt_string("read_timeout"), 12541131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 12551131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, read_timeout), 12561131Smax.romanov@nginx.com }, 12571131Smax.romanov@nginx.com 12581131Smax.romanov@nginx.com { 12591131Smax.romanov@nginx.com nxt_string("keepalive_interval"), 12601131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 12611131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, keepalive_interval), 12621131Smax.romanov@nginx.com }, 12631131Smax.romanov@nginx.com 12641131Smax.romanov@nginx.com }; 12651131Smax.romanov@nginx.com 12661131Smax.romanov@nginx.com 126753Sigor@sysoev.ru static nxt_int_t 1268115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1269115Sigor@sysoev.ru u_char *start, u_char *end) 127053Sigor@sysoev.ru { 1271133Sigor@sysoev.ru u_char *p; 1272133Sigor@sysoev.ru size_t size; 12731473Svbart@nginx.com nxt_mp_t *mp, *app_mp; 12741473Svbart@nginx.com uint32_t next, next_target; 1275115Sigor@sysoev.ru nxt_int_t ret; 12761473Svbart@nginx.com nxt_str_t name, path, target; 1277133Sigor@sysoev.ru nxt_app_t *app, *prev; 12781473Svbart@nginx.com nxt_str_t *t, *s, *targets; 12791473Svbart@nginx.com nxt_uint_t n, i; 12801547Smax.romanov@nginx.com nxt_port_t *port; 1281359Sigor@sysoev.ru nxt_router_t *router; 1282753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 12831131Smax.romanov@nginx.com nxt_conf_value_t *conf, *http, *value, *websocket; 1284133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1285133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 12861183Svbart@nginx.com nxt_conf_value_t *routes_conf, *static_conf; 1287115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1288964Sigor@sysoev.ru nxt_http_routes_t *routes; 1289507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1290216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1291133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1292630Svbart@nginx.com nxt_router_access_log_t *access_log; 1293115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1294774Svbart@nginx.com #if (NXT_TLS) 1295774Svbart@nginx.com nxt_router_tlssock_t *tls; 1296774Svbart@nginx.com #endif 1297115Sigor@sysoev.ru 1298716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1299133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1300115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1301964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1302630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1303774Svbart@nginx.com #if (NXT_TLS) 1304774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1305774Svbart@nginx.com #endif 13061183Svbart@nginx.com static nxt_str_t static_path = nxt_string("/settings/http/static"); 13071131Smax.romanov@nginx.com static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); 1308115Sigor@sysoev.ru 1309208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1310115Sigor@sysoev.ru if (conf == NULL) { 1311564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1312115Sigor@sysoev.ru return NXT_ERROR; 1313115Sigor@sysoev.ru } 1314115Sigor@sysoev.ru 1315591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1316213Svbart@nginx.com 1317213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1318591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1319115Sigor@sysoev.ru if (ret != NXT_OK) { 1320564Svbart@nginx.com nxt_alert(task, "root map error"); 1321115Sigor@sysoev.ru return NXT_ERROR; 1322115Sigor@sysoev.ru } 1323115Sigor@sysoev.ru 1324591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1325591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1326117Sigor@sysoev.ru } 1327117Sigor@sysoev.ru 13281183Svbart@nginx.com static_conf = nxt_conf_get_path(conf, &static_path); 13291183Svbart@nginx.com 13301183Svbart@nginx.com ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf); 13311183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 13321183Svbart@nginx.com return NXT_ERROR; 13331183Svbart@nginx.com } 13341183Svbart@nginx.com 13351115Svbart@nginx.com router = tmcf->router_conf->router; 13361115Svbart@nginx.com 1337133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 13381115Svbart@nginx.com 13391115Svbart@nginx.com if (applications != NULL) { 13401115Svbart@nginx.com next = 0; 13411115Svbart@nginx.com 13421115Svbart@nginx.com for ( ;; ) { 13431235Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, 13441235Sigor@sysoev.ru &name, &next); 13451115Svbart@nginx.com if (application == NULL) { 13461115Svbart@nginx.com break; 13471115Svbart@nginx.com } 13481115Svbart@nginx.com 13491115Svbart@nginx.com nxt_debug(task, "application \"%V\"", &name); 13501115Svbart@nginx.com 13511115Svbart@nginx.com size = nxt_conf_json_length(application, NULL); 13521115Svbart@nginx.com 13531473Svbart@nginx.com app_mp = nxt_mp_create(4096, 128, 1024, 64); 13541473Svbart@nginx.com if (nxt_slow_path(app_mp == NULL)) { 13551473Svbart@nginx.com goto fail; 13561473Svbart@nginx.com } 13571473Svbart@nginx.com 13581473Svbart@nginx.com app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size); 13591115Svbart@nginx.com if (app == NULL) { 13601473Svbart@nginx.com goto app_fail; 13611115Svbart@nginx.com } 13621115Svbart@nginx.com 13631115Svbart@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 13641115Svbart@nginx.com 13651473Svbart@nginx.com app->mem_pool = app_mp; 13661473Svbart@nginx.com 13671115Svbart@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 13681115Svbart@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) 13691115Svbart@nginx.com + name.length); 13701115Svbart@nginx.com 13711115Svbart@nginx.com p = nxt_conf_json_print(app->conf.start, application, NULL); 13721115Svbart@nginx.com app->conf.length = p - app->conf.start; 13731115Svbart@nginx.com 13741115Svbart@nginx.com nxt_assert(app->conf.length <= size); 13751115Svbart@nginx.com 13761115Svbart@nginx.com nxt_debug(task, "application conf \"%V\"", &app->conf); 13771115Svbart@nginx.com 13781115Svbart@nginx.com prev = nxt_router_app_find(&router->apps, &name); 13791115Svbart@nginx.com 13801115Svbart@nginx.com if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 13811473Svbart@nginx.com nxt_mp_destroy(app_mp); 13821115Svbart@nginx.com 13831115Svbart@nginx.com nxt_queue_remove(&prev->link); 13841115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->previous, &prev->link); 13851115Svbart@nginx.com continue; 13861115Svbart@nginx.com } 13871115Svbart@nginx.com 13881115Svbart@nginx.com apcf.processes = 1; 13891115Svbart@nginx.com apcf.max_processes = 1; 13901115Svbart@nginx.com apcf.spare_processes = 0; 13911115Svbart@nginx.com apcf.timeout = 0; 13921115Svbart@nginx.com apcf.res_timeout = 1000; 13931115Svbart@nginx.com apcf.idle_timeout = 15000; 13941115Svbart@nginx.com apcf.requests = 0; 13951115Svbart@nginx.com apcf.limits_value = NULL; 13961115Svbart@nginx.com apcf.processes_value = NULL; 13971473Svbart@nginx.com apcf.targets_value = NULL; 13981115Svbart@nginx.com 13991115Svbart@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 14001115Svbart@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1401318Smax.romanov@nginx.com goto app_fail; 1402318Smax.romanov@nginx.com } 1403318Smax.romanov@nginx.com 14041115Svbart@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 14051115Svbart@nginx.com 14061115Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 14071115Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1408318Smax.romanov@nginx.com if (ret != NXT_OK) { 14091115Svbart@nginx.com nxt_alert(task, "application map error"); 1410318Smax.romanov@nginx.com goto app_fail; 1411318Smax.romanov@nginx.com } 14121115Svbart@nginx.com 14131115Svbart@nginx.com if (apcf.limits_value != NULL) { 14141115Svbart@nginx.com 14151115Svbart@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 14161115Svbart@nginx.com nxt_alert(task, "application limits is not object"); 14171115Svbart@nginx.com goto app_fail; 14181115Svbart@nginx.com } 14191115Svbart@nginx.com 14201115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 14211115Svbart@nginx.com nxt_router_app_limits_conf, 14221115Svbart@nginx.com nxt_nitems(nxt_router_app_limits_conf), 14231115Svbart@nginx.com &apcf); 14241115Svbart@nginx.com if (ret != NXT_OK) { 14251115Svbart@nginx.com nxt_alert(task, "application limits map error"); 14261115Svbart@nginx.com goto app_fail; 14271115Svbart@nginx.com } 14281115Svbart@nginx.com } 14291115Svbart@nginx.com 14301115Svbart@nginx.com if (apcf.processes_value != NULL 14311115Svbart@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 14321115Svbart@nginx.com { 14331115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 14341115Svbart@nginx.com nxt_router_app_processes_conf, 14351115Svbart@nginx.com nxt_nitems(nxt_router_app_processes_conf), 14361115Svbart@nginx.com &apcf); 14371115Svbart@nginx.com if (ret != NXT_OK) { 14381115Svbart@nginx.com nxt_alert(task, "application processes map error"); 14391115Svbart@nginx.com goto app_fail; 14401115Svbart@nginx.com } 14411115Svbart@nginx.com 14421115Svbart@nginx.com } else { 14431115Svbart@nginx.com apcf.max_processes = apcf.processes; 14441115Svbart@nginx.com apcf.spare_processes = apcf.processes; 14451115Svbart@nginx.com } 14461115Svbart@nginx.com 14471473Svbart@nginx.com if (apcf.targets_value != NULL) { 14481473Svbart@nginx.com n = nxt_conf_object_members_count(apcf.targets_value); 14491473Svbart@nginx.com 14501473Svbart@nginx.com targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n); 14511473Svbart@nginx.com if (nxt_slow_path(targets == NULL)) { 14521473Svbart@nginx.com goto app_fail; 14531473Svbart@nginx.com } 14541473Svbart@nginx.com 14551473Svbart@nginx.com next_target = 0; 14561473Svbart@nginx.com 14571473Svbart@nginx.com for (i = 0; i < n; i++) { 14581480Svbart@nginx.com (void) nxt_conf_next_object_member(apcf.targets_value, 14591480Svbart@nginx.com &target, &next_target); 14601473Svbart@nginx.com 14611473Svbart@nginx.com s = nxt_str_dup(app_mp, &targets[i], &target); 14621473Svbart@nginx.com if (nxt_slow_path(s == NULL)) { 14631473Svbart@nginx.com goto app_fail; 14641473Svbart@nginx.com } 14651473Svbart@nginx.com } 14661473Svbart@nginx.com 14671473Svbart@nginx.com } else { 14681473Svbart@nginx.com targets = NULL; 14691473Svbart@nginx.com } 14701473Svbart@nginx.com 14711115Svbart@nginx.com nxt_debug(task, "application type: %V", &apcf.type); 14721115Svbart@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 14731115Svbart@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 14741115Svbart@nginx.com nxt_debug(task, "application reschedule timeout: %M", 14751115Svbart@nginx.com apcf.res_timeout); 14761115Svbart@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 14771115Svbart@nginx.com 14781115Svbart@nginx.com lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 14791115Svbart@nginx.com 14801115Svbart@nginx.com if (lang == NULL) { 14811115Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1482507Smax.romanov@nginx.com goto app_fail; 1483507Smax.romanov@nginx.com } 1484507Smax.romanov@nginx.com 14851115Svbart@nginx.com nxt_debug(task, "application language module: \"%s\"", lang->file); 14861115Svbart@nginx.com 14871115Svbart@nginx.com ret = nxt_thread_mutex_create(&app->mutex); 14881115Svbart@nginx.com if (ret != NXT_OK) { 14891115Svbart@nginx.com goto app_fail; 14901115Svbart@nginx.com } 14911115Svbart@nginx.com 14921115Svbart@nginx.com nxt_queue_init(&app->ports); 14931115Svbart@nginx.com nxt_queue_init(&app->spare_ports); 14941115Svbart@nginx.com nxt_queue_init(&app->idle_ports); 14951115Svbart@nginx.com 14961115Svbart@nginx.com app->name.length = name.length; 14971115Svbart@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 14981115Svbart@nginx.com 14991115Svbart@nginx.com app->type = lang->type; 15001115Svbart@nginx.com app->max_processes = apcf.max_processes; 15011115Svbart@nginx.com app->spare_processes = apcf.spare_processes; 15021115Svbart@nginx.com app->max_pending_processes = apcf.spare_processes 15031115Svbart@nginx.com ? apcf.spare_processes : 1; 15041115Svbart@nginx.com app->timeout = apcf.timeout; 15051115Svbart@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 15061115Svbart@nginx.com app->idle_timeout = apcf.idle_timeout; 15071115Svbart@nginx.com app->max_requests = apcf.requests; 15081115Svbart@nginx.com 15091473Svbart@nginx.com app->targets = targets; 15101473Svbart@nginx.com 15111115Svbart@nginx.com engine = task->thread->engine; 15121115Svbart@nginx.com 15131115Svbart@nginx.com app->engine = engine; 15141115Svbart@nginx.com 15151115Svbart@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 15161115Svbart@nginx.com app->adjust_idle_work.task = &engine->task; 15171115Svbart@nginx.com app->adjust_idle_work.obj = app; 15181115Svbart@nginx.com 15191115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->apps, &app->link); 15201115Svbart@nginx.com 15211115Svbart@nginx.com nxt_router_app_use(task, app, 1); 15221115Svbart@nginx.com 15231115Svbart@nginx.com app->joint = app_joint; 15241115Svbart@nginx.com 15251115Svbart@nginx.com app_joint->use_count = 1; 15261115Svbart@nginx.com app_joint->app = app; 15271115Svbart@nginx.com 15281115Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 15291115Svbart@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 15301115Svbart@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 15311115Svbart@nginx.com app_joint->idle_timer.task = &engine->task; 15321115Svbart@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 15331115Svbart@nginx.com 15341115Svbart@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 15351115Svbart@nginx.com app_joint->free_app_work.task = &engine->task; 15361115Svbart@nginx.com app_joint->free_app_work.obj = app_joint; 15371547Smax.romanov@nginx.com 15381547Smax.romanov@nginx.com port = nxt_port_new(task, (nxt_port_id_t) -1, nxt_pid, 15391547Smax.romanov@nginx.com NXT_PROCESS_APP); 15401547Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 15411547Smax.romanov@nginx.com return NXT_ERROR; 15421547Smax.romanov@nginx.com } 15431547Smax.romanov@nginx.com 15441547Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 15451547Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 15461547Smax.romanov@nginx.com nxt_port_use(task, port, -1); 15471547Smax.romanov@nginx.com return NXT_ERROR; 15481547Smax.romanov@nginx.com } 15491547Smax.romanov@nginx.com 15501555Smax.romanov@nginx.com ret = nxt_router_app_queue_init(task, port); 15511555Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 15521555Smax.romanov@nginx.com nxt_port_use(task, port, -1); 15531555Smax.romanov@nginx.com return NXT_ERROR; 15541555Smax.romanov@nginx.com } 15551555Smax.romanov@nginx.com 15561547Smax.romanov@nginx.com nxt_port_write_enable(task, port); 15571547Smax.romanov@nginx.com port->app = app; 15581547Smax.romanov@nginx.com 15591547Smax.romanov@nginx.com app->shared_port = port; 15601547Smax.romanov@nginx.com 15611547Smax.romanov@nginx.com nxt_thread_mutex_create(&app->outgoing.mutex); 1562133Sigor@sysoev.ru } 1563133Sigor@sysoev.ru } 1564133Sigor@sysoev.ru 1565964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1566964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1567964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1568964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1569964Sigor@sysoev.ru return NXT_ERROR; 1570964Sigor@sysoev.ru } 1571964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1572964Sigor@sysoev.ru } 1573964Sigor@sysoev.ru 15741394Sigor@sysoev.ru ret = nxt_upstreams_create(task, tmcf, conf); 15751394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 15761394Sigor@sysoev.ru return ret; 15771394Sigor@sysoev.ru } 15781394Sigor@sysoev.ru 1579133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1580133Sigor@sysoev.ru #if 0 1581133Sigor@sysoev.ru if (http == NULL) { 1582564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1583133Sigor@sysoev.ru return NXT_ERROR; 1584133Sigor@sysoev.ru } 1585133Sigor@sysoev.ru #endif 1586133Sigor@sysoev.ru 15871131Smax.romanov@nginx.com websocket = nxt_conf_get_path(conf, &websocket_path); 15881131Smax.romanov@nginx.com 1589133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 15901115Svbart@nginx.com 15911115Svbart@nginx.com if (listeners != NULL) { 15921115Svbart@nginx.com next = 0; 15931115Svbart@nginx.com 15941115Svbart@nginx.com for ( ;; ) { 15951115Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &name, &next); 15961115Svbart@nginx.com if (listener == NULL) { 15971115Svbart@nginx.com break; 15981115Svbart@nginx.com } 15991115Svbart@nginx.com 16001115Svbart@nginx.com skcf = nxt_router_socket_conf(task, tmcf, &name); 16011115Svbart@nginx.com if (skcf == NULL) { 16021115Svbart@nginx.com goto fail; 16031115Svbart@nginx.com } 16041115Svbart@nginx.com 16051115Svbart@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 16061115Svbart@nginx.com 16071115Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 16081115Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), 16091115Svbart@nginx.com &lscf); 1610133Sigor@sysoev.ru if (ret != NXT_OK) { 16111115Svbart@nginx.com nxt_alert(task, "listener map error"); 1612133Sigor@sysoev.ru goto fail; 1613133Sigor@sysoev.ru } 16141115Svbart@nginx.com 16151115Svbart@nginx.com nxt_debug(task, "application: %V", &lscf.application); 16161115Svbart@nginx.com 16171115Svbart@nginx.com // STUB, default values if http block is not defined. 16181115Svbart@nginx.com skcf->header_buffer_size = 2048; 16191115Svbart@nginx.com skcf->large_header_buffer_size = 8192; 16201115Svbart@nginx.com skcf->large_header_buffers = 4; 16211115Svbart@nginx.com skcf->body_buffer_size = 16 * 1024; 16221115Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 16231270Sigor@sysoev.ru skcf->proxy_header_buffer_size = 64 * 1024; 16241270Sigor@sysoev.ru skcf->proxy_buffer_size = 4096; 16251270Sigor@sysoev.ru skcf->proxy_buffers = 256; 16261115Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 16271115Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 16281115Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 16291115Svbart@nginx.com skcf->send_timeout = 30 * 1000; 16301270Sigor@sysoev.ru skcf->proxy_timeout = 60 * 1000; 16311270Sigor@sysoev.ru skcf->proxy_send_timeout = 30 * 1000; 16321270Sigor@sysoev.ru skcf->proxy_read_timeout = 30 * 1000; 16331115Svbart@nginx.com 16341131Smax.romanov@nginx.com skcf->websocket_conf.max_frame_size = 1024 * 1024; 16351131Smax.romanov@nginx.com skcf->websocket_conf.read_timeout = 60 * 1000; 16361131Smax.romanov@nginx.com skcf->websocket_conf.keepalive_interval = 30 * 1000; 16371131Smax.romanov@nginx.com 16381403Smax.romanov@nginx.com nxt_str_null(&skcf->body_temp_path); 16391403Smax.romanov@nginx.com 16401115Svbart@nginx.com if (http != NULL) { 16411115Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 16421115Svbart@nginx.com nxt_nitems(nxt_router_http_conf), 16431115Svbart@nginx.com skcf); 16441115Svbart@nginx.com if (ret != NXT_OK) { 16451115Svbart@nginx.com nxt_alert(task, "http map error"); 16461115Svbart@nginx.com goto fail; 16471115Svbart@nginx.com } 16481115Svbart@nginx.com } 1649115Sigor@sysoev.ru 16501131Smax.romanov@nginx.com if (websocket != NULL) { 16511131Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, websocket, 16521131Smax.romanov@nginx.com nxt_router_websocket_conf, 16531131Smax.romanov@nginx.com nxt_nitems(nxt_router_websocket_conf), 16541131Smax.romanov@nginx.com &skcf->websocket_conf); 16551131Smax.romanov@nginx.com if (ret != NXT_OK) { 16561131Smax.romanov@nginx.com nxt_alert(task, "websocket map error"); 16571131Smax.romanov@nginx.com goto fail; 16581131Smax.romanov@nginx.com } 16591131Smax.romanov@nginx.com } 16601131Smax.romanov@nginx.com 16611403Smax.romanov@nginx.com t = &skcf->body_temp_path; 16621403Smax.romanov@nginx.com 16631403Smax.romanov@nginx.com if (t->length == 0) { 16641403Smax.romanov@nginx.com t->start = (u_char *) task->thread->runtime->tmp; 16651403Smax.romanov@nginx.com t->length = nxt_strlen(t->start); 16661403Smax.romanov@nginx.com } 16671403Smax.romanov@nginx.com 1668774Svbart@nginx.com #if (NXT_TLS) 16691115Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 16701115Svbart@nginx.com 16711115Svbart@nginx.com if (value != NULL) { 16721115Svbart@nginx.com nxt_conf_get_string(value, &name); 16731115Svbart@nginx.com 16741115Svbart@nginx.com tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); 16751115Svbart@nginx.com if (nxt_slow_path(tls == NULL)) { 16761115Svbart@nginx.com goto fail; 16771115Svbart@nginx.com } 16781115Svbart@nginx.com 16791115Svbart@nginx.com tls->name = name; 16801115Svbart@nginx.com tls->conf = skcf; 16811115Svbart@nginx.com 16821115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 1683774Svbart@nginx.com } 1684774Svbart@nginx.com #endif 1685774Svbart@nginx.com 16861115Svbart@nginx.com skcf->listen->handler = nxt_http_conn_init; 16871115Svbart@nginx.com skcf->router_conf = tmcf->router_conf; 16881115Svbart@nginx.com skcf->router_conf->count++; 16891115Svbart@nginx.com 16901115Svbart@nginx.com if (lscf.pass.length != 0) { 16911264Sigor@sysoev.ru skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass); 16921115Svbart@nginx.com 16931115Svbart@nginx.com /* COMPATIBILITY: listener application. */ 16941115Svbart@nginx.com } else if (lscf.application.length > 0) { 16951264Sigor@sysoev.ru skcf->action = nxt_http_pass_application(task, tmcf, 16961264Sigor@sysoev.ru &lscf.application); 16971115Svbart@nginx.com } 1698770Smax.romanov@nginx.com } 1699115Sigor@sysoev.ru } 170053Sigor@sysoev.ru 17011472Svbart@nginx.com ret = nxt_http_routes_resolve(task, tmcf); 17021472Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 17031472Svbart@nginx.com goto fail; 17041472Svbart@nginx.com } 17051472Svbart@nginx.com 1706630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1707630Svbart@nginx.com 1708630Svbart@nginx.com if (value != NULL) { 1709630Svbart@nginx.com nxt_conf_get_string(value, &path); 1710630Svbart@nginx.com 1711630Svbart@nginx.com access_log = router->access_log; 1712630Svbart@nginx.com 1713630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1714630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1715630Svbart@nginx.com access_log->count++; 1716630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1717630Svbart@nginx.com 1718630Svbart@nginx.com } else { 1719630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1720630Svbart@nginx.com + path.length); 1721630Svbart@nginx.com if (access_log == NULL) { 1722630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1723630Svbart@nginx.com goto fail; 1724630Svbart@nginx.com } 1725630Svbart@nginx.com 1726630Svbart@nginx.com access_log->fd = -1; 1727630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1728630Svbart@nginx.com access_log->count = 1; 1729630Svbart@nginx.com 1730630Svbart@nginx.com access_log->path.length = path.length; 1731630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1732630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1733630Svbart@nginx.com 1734630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1735630Svbart@nginx.com } 1736630Svbart@nginx.com 1737630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1738630Svbart@nginx.com } 1739630Svbart@nginx.com 17401509Sigor@sysoev.ru nxt_queue_add(&deleting_sockets, &router->sockets); 1741359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1742198Sigor@sysoev.ru 174353Sigor@sysoev.ru return NXT_OK; 1744133Sigor@sysoev.ru 1745133Sigor@sysoev.ru app_fail: 1746133Sigor@sysoev.ru 17471473Svbart@nginx.com nxt_mp_destroy(app_mp); 1748133Sigor@sysoev.ru 1749133Sigor@sysoev.ru fail: 1750133Sigor@sysoev.ru 1751141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1752141Smax.romanov@nginx.com 1753141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1754133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 17551473Svbart@nginx.com nxt_mp_destroy(app->mem_pool); 1756141Smax.romanov@nginx.com 1757141Smax.romanov@nginx.com } nxt_queue_loop; 1758133Sigor@sysoev.ru 1759133Sigor@sysoev.ru return NXT_ERROR; 1760133Sigor@sysoev.ru } 1761133Sigor@sysoev.ru 1762133Sigor@sysoev.ru 17631183Svbart@nginx.com static nxt_int_t 17641183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, 17651183Svbart@nginx.com nxt_conf_value_t *conf) 17661183Svbart@nginx.com { 17671183Svbart@nginx.com uint32_t next, i; 17681183Svbart@nginx.com nxt_mp_t *mp; 17691183Svbart@nginx.com nxt_str_t *type, extension, str; 17701183Svbart@nginx.com nxt_int_t ret; 17711183Svbart@nginx.com nxt_uint_t exts; 17721183Svbart@nginx.com nxt_conf_value_t *mtypes_conf, *ext_conf, *value; 17731183Svbart@nginx.com 17741183Svbart@nginx.com static nxt_str_t mtypes_path = nxt_string("/mime_types"); 17751183Svbart@nginx.com 17761183Svbart@nginx.com mp = rtcf->mem_pool; 17771183Svbart@nginx.com 17781183Svbart@nginx.com ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash); 17791183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 17801183Svbart@nginx.com return NXT_ERROR; 17811183Svbart@nginx.com } 17821183Svbart@nginx.com 17831183Svbart@nginx.com if (conf == NULL) { 17841183Svbart@nginx.com return NXT_OK; 17851183Svbart@nginx.com } 17861183Svbart@nginx.com 17871183Svbart@nginx.com mtypes_conf = nxt_conf_get_path(conf, &mtypes_path); 17881183Svbart@nginx.com 17891183Svbart@nginx.com if (mtypes_conf != NULL) { 17901183Svbart@nginx.com next = 0; 17911183Svbart@nginx.com 17921183Svbart@nginx.com for ( ;; ) { 17931183Svbart@nginx.com ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next); 17941183Svbart@nginx.com 17951183Svbart@nginx.com if (ext_conf == NULL) { 17961183Svbart@nginx.com break; 17971183Svbart@nginx.com } 17981183Svbart@nginx.com 17991183Svbart@nginx.com type = nxt_str_dup(mp, NULL, &str); 18001183Svbart@nginx.com if (nxt_slow_path(type == NULL)) { 18011183Svbart@nginx.com return NXT_ERROR; 18021183Svbart@nginx.com } 18031183Svbart@nginx.com 18041183Svbart@nginx.com if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) { 18051183Svbart@nginx.com nxt_conf_get_string(ext_conf, &str); 18061183Svbart@nginx.com 18071183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 18081183Svbart@nginx.com return NXT_ERROR; 18091183Svbart@nginx.com } 18101183Svbart@nginx.com 18111183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 18121183Svbart@nginx.com &extension, type); 18131183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 18141183Svbart@nginx.com return NXT_ERROR; 18151183Svbart@nginx.com } 18161183Svbart@nginx.com 18171183Svbart@nginx.com continue; 18181183Svbart@nginx.com } 18191183Svbart@nginx.com 18201183Svbart@nginx.com exts = nxt_conf_array_elements_count(ext_conf); 18211183Svbart@nginx.com 18221183Svbart@nginx.com for (i = 0; i < exts; i++) { 18231183Svbart@nginx.com value = nxt_conf_get_array_element(ext_conf, i); 18241183Svbart@nginx.com 18251183Svbart@nginx.com nxt_conf_get_string(value, &str); 18261183Svbart@nginx.com 18271183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 18281183Svbart@nginx.com return NXT_ERROR; 18291183Svbart@nginx.com } 18301183Svbart@nginx.com 18311183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 18321183Svbart@nginx.com &extension, type); 18331183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 18341183Svbart@nginx.com return NXT_ERROR; 18351183Svbart@nginx.com } 18361183Svbart@nginx.com } 18371183Svbart@nginx.com } 18381183Svbart@nginx.com } 18391183Svbart@nginx.com 18401183Svbart@nginx.com return NXT_OK; 18411183Svbart@nginx.com } 18421183Svbart@nginx.com 18431183Svbart@nginx.com 1844133Sigor@sysoev.ru static nxt_app_t * 1845133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1846133Sigor@sysoev.ru { 1847141Smax.romanov@nginx.com nxt_app_t *app; 1848141Smax.romanov@nginx.com 1849141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1850133Sigor@sysoev.ru 1851133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1852133Sigor@sysoev.ru return app; 1853133Sigor@sysoev.ru } 1854141Smax.romanov@nginx.com 1855141Smax.romanov@nginx.com } nxt_queue_loop; 1856133Sigor@sysoev.ru 1857133Sigor@sysoev.ru return NULL; 1858133Sigor@sysoev.ru } 1859133Sigor@sysoev.ru 1860133Sigor@sysoev.ru 18611555Smax.romanov@nginx.com static nxt_int_t 18621555Smax.romanov@nginx.com nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port) 18631555Smax.romanov@nginx.com { 18641555Smax.romanov@nginx.com void *mem; 18651555Smax.romanov@nginx.com nxt_int_t fd; 18661555Smax.romanov@nginx.com 18671555Smax.romanov@nginx.com fd = nxt_shm_open(task, sizeof(nxt_app_queue_t)); 18681555Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 18691555Smax.romanov@nginx.com return NXT_ERROR; 18701555Smax.romanov@nginx.com } 18711555Smax.romanov@nginx.com 18721555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t), 18731555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 18741555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 18751555Smax.romanov@nginx.com nxt_fd_close(fd); 18761555Smax.romanov@nginx.com 18771555Smax.romanov@nginx.com return NXT_ERROR; 18781555Smax.romanov@nginx.com } 18791555Smax.romanov@nginx.com 18801555Smax.romanov@nginx.com nxt_app_queue_init(mem); 18811555Smax.romanov@nginx.com 18821555Smax.romanov@nginx.com port->queue_fd = fd; 18831555Smax.romanov@nginx.com port->queue = mem; 18841555Smax.romanov@nginx.com 18851555Smax.romanov@nginx.com return NXT_OK; 18861555Smax.romanov@nginx.com } 18871555Smax.romanov@nginx.com 18881555Smax.romanov@nginx.com 18891555Smax.romanov@nginx.com static nxt_int_t 18901555Smax.romanov@nginx.com nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port) 18911555Smax.romanov@nginx.com { 18921555Smax.romanov@nginx.com void *mem; 18931555Smax.romanov@nginx.com nxt_int_t fd; 18941555Smax.romanov@nginx.com 18951555Smax.romanov@nginx.com fd = nxt_shm_open(task, sizeof(nxt_port_queue_t)); 18961555Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 18971555Smax.romanov@nginx.com return NXT_ERROR; 18981555Smax.romanov@nginx.com } 18991555Smax.romanov@nginx.com 19001555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), 19011555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 19021555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 19031555Smax.romanov@nginx.com nxt_fd_close(fd); 19041555Smax.romanov@nginx.com 19051555Smax.romanov@nginx.com return NXT_ERROR; 19061555Smax.romanov@nginx.com } 19071555Smax.romanov@nginx.com 19081555Smax.romanov@nginx.com nxt_port_queue_init(mem); 19091555Smax.romanov@nginx.com 19101555Smax.romanov@nginx.com port->queue_fd = fd; 19111555Smax.romanov@nginx.com port->queue = mem; 19121555Smax.romanov@nginx.com 19131555Smax.romanov@nginx.com return NXT_OK; 19141555Smax.romanov@nginx.com } 19151555Smax.romanov@nginx.com 19161555Smax.romanov@nginx.com 19171555Smax.romanov@nginx.com static nxt_int_t 19181555Smax.romanov@nginx.com nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd) 19191555Smax.romanov@nginx.com { 19201555Smax.romanov@nginx.com void *mem; 19211555Smax.romanov@nginx.com 19221555Smax.romanov@nginx.com nxt_assert(fd != -1); 19231555Smax.romanov@nginx.com 19241555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), 19251555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 19261555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 19271555Smax.romanov@nginx.com 19281555Smax.romanov@nginx.com return NXT_ERROR; 19291555Smax.romanov@nginx.com } 19301555Smax.romanov@nginx.com 19311555Smax.romanov@nginx.com port->queue = mem; 19321555Smax.romanov@nginx.com 19331555Smax.romanov@nginx.com return NXT_OK; 19341555Smax.romanov@nginx.com } 19351555Smax.romanov@nginx.com 19361555Smax.romanov@nginx.com 19371392Sigor@sysoev.ru void 19381392Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name, 19391392Sigor@sysoev.ru nxt_http_action_t *action) 1940133Sigor@sysoev.ru { 1941133Sigor@sysoev.ru nxt_app_t *app; 1942133Sigor@sysoev.ru 1943133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1944133Sigor@sysoev.ru 1945133Sigor@sysoev.ru if (app == NULL) { 1946134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1947133Sigor@sysoev.ru } 1948133Sigor@sysoev.ru 19491392Sigor@sysoev.ru action->u.application = app; 19501392Sigor@sysoev.ru action->handler = nxt_http_application_handler; 195153Sigor@sysoev.ru } 195253Sigor@sysoev.ru 195353Sigor@sysoev.ru 195453Sigor@sysoev.ru static nxt_socket_conf_t * 1955359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1956359Sigor@sysoev.ru nxt_str_t *name) 195753Sigor@sysoev.ru { 1958359Sigor@sysoev.ru size_t size; 1959359Sigor@sysoev.ru nxt_int_t ret; 1960359Sigor@sysoev.ru nxt_bool_t wildcard; 1961359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1962359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1963359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1964359Sigor@sysoev.ru 1965359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1966359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1967564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1968359Sigor@sysoev.ru return NULL; 1969359Sigor@sysoev.ru } 1970359Sigor@sysoev.ru 1971359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1972359Sigor@sysoev.ru 1973359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1974493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1975359Sigor@sysoev.ru 1976591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1977163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 197853Sigor@sysoev.ru return NULL; 197953Sigor@sysoev.ru } 198053Sigor@sysoev.ru 1981359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1982359Sigor@sysoev.ru 1983359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1984359Sigor@sysoev.ru 1985359Sigor@sysoev.ru if (ret != NXT_OK) { 1986359Sigor@sysoev.ru 1987359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1988359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1989359Sigor@sysoev.ru return NULL; 1990359Sigor@sysoev.ru } 1991359Sigor@sysoev.ru 1992359Sigor@sysoev.ru skcf->listen = ls; 1993359Sigor@sysoev.ru 1994359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1995359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1996359Sigor@sysoev.ru 1997359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1998359Sigor@sysoev.ru 1999359Sigor@sysoev.ru ls->socket = -1; 2000359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 2001359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 2002359Sigor@sysoev.ru ls->read_after_accept = 1; 2003359Sigor@sysoev.ru } 2004359Sigor@sysoev.ru 2005359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 2006359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 2007359Sigor@sysoev.ru case AF_UNIX: 2008359Sigor@sysoev.ru wildcard = 0; 2009359Sigor@sysoev.ru break; 2010359Sigor@sysoev.ru #endif 2011359Sigor@sysoev.ru #if (NXT_INET6) 2012359Sigor@sysoev.ru case AF_INET6: 2013359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 2014359Sigor@sysoev.ru break; 2015359Sigor@sysoev.ru #endif 2016359Sigor@sysoev.ru case AF_INET: 2017359Sigor@sysoev.ru default: 2018359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 2019359Sigor@sysoev.ru break; 2020359Sigor@sysoev.ru } 2021359Sigor@sysoev.ru 2022359Sigor@sysoev.ru if (!wildcard) { 2023591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 2024359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 2025359Sigor@sysoev.ru return NULL; 2026359Sigor@sysoev.ru } 2027359Sigor@sysoev.ru 2028359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 2029359Sigor@sysoev.ru } 2030163Smax.romanov@nginx.com 2031163Smax.romanov@nginx.com return skcf; 203253Sigor@sysoev.ru } 203353Sigor@sysoev.ru 203453Sigor@sysoev.ru 2035359Sigor@sysoev.ru static nxt_int_t 2036359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 2037359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 203853Sigor@sysoev.ru { 2039359Sigor@sysoev.ru nxt_router_t *router; 2040359Sigor@sysoev.ru nxt_queue_link_t *qlk; 2041359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2042359Sigor@sysoev.ru 2043591Sigor@sysoev.ru router = tmcf->router_conf->router; 2044359Sigor@sysoev.ru 2045359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 2046359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 2047359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 204853Sigor@sysoev.ru { 2049359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2050359Sigor@sysoev.ru 2051359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 2052359Sigor@sysoev.ru nskcf->listen = skcf->listen; 2053359Sigor@sysoev.ru 2054359Sigor@sysoev.ru nxt_queue_remove(qlk); 20551509Sigor@sysoev.ru nxt_queue_insert_tail(&keeping_sockets, qlk); 20561509Sigor@sysoev.ru 20571509Sigor@sysoev.ru nxt_queue_insert_tail(&updating_sockets, &nskcf->link); 2058359Sigor@sysoev.ru 2059359Sigor@sysoev.ru return NXT_OK; 206053Sigor@sysoev.ru } 206153Sigor@sysoev.ru } 206253Sigor@sysoev.ru 20631509Sigor@sysoev.ru nxt_queue_insert_tail(&pending_sockets, &nskcf->link); 2064359Sigor@sysoev.ru 2065359Sigor@sysoev.ru return NXT_DECLINED; 206653Sigor@sysoev.ru } 206753Sigor@sysoev.ru 206853Sigor@sysoev.ru 2069198Sigor@sysoev.ru static void 2070198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 2071198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 2072198Sigor@sysoev.ru { 2073358Sigor@sysoev.ru size_t size; 2074198Sigor@sysoev.ru uint32_t stream; 2075648Svbart@nginx.com nxt_int_t ret; 2076198Sigor@sysoev.ru nxt_buf_t *b; 2077198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 2078198Sigor@sysoev.ru nxt_runtime_t *rt; 2079198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 2080198Sigor@sysoev.ru 2081198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2082198Sigor@sysoev.ru if (rpc == NULL) { 2083198Sigor@sysoev.ru goto fail; 2084198Sigor@sysoev.ru } 2085198Sigor@sysoev.ru 2086198Sigor@sysoev.ru rpc->socket_conf = skcf; 2087198Sigor@sysoev.ru rpc->temp_conf = tmcf; 2088198Sigor@sysoev.ru 2089359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 2090358Sigor@sysoev.ru 2091358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2092198Sigor@sysoev.ru if (b == NULL) { 2093198Sigor@sysoev.ru goto fail; 2094198Sigor@sysoev.ru } 2095198Sigor@sysoev.ru 2096359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 2097198Sigor@sysoev.ru 2098198Sigor@sysoev.ru rt = task->thread->runtime; 2099240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2100198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2101198Sigor@sysoev.ru 2102198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 2103198Sigor@sysoev.ru nxt_router_listen_socket_ready, 2104198Sigor@sysoev.ru nxt_router_listen_socket_error, 2105198Sigor@sysoev.ru main_port->pid, rpc); 2106645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 2107198Sigor@sysoev.ru goto fail; 2108198Sigor@sysoev.ru } 2109198Sigor@sysoev.ru 2110648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 2111648Svbart@nginx.com stream, router_port->id, b); 2112648Svbart@nginx.com 2113648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2114648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2115648Svbart@nginx.com goto fail; 2116648Svbart@nginx.com } 2117198Sigor@sysoev.ru 2118198Sigor@sysoev.ru return; 2119198Sigor@sysoev.ru 2120198Sigor@sysoev.ru fail: 2121198Sigor@sysoev.ru 2122198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 2123198Sigor@sysoev.ru } 2124198Sigor@sysoev.ru 2125198Sigor@sysoev.ru 2126198Sigor@sysoev.ru static void 2127198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2128198Sigor@sysoev.ru void *data) 212953Sigor@sysoev.ru { 2130359Sigor@sysoev.ru nxt_int_t ret; 2131359Sigor@sysoev.ru nxt_socket_t s; 2132359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 213353Sigor@sysoev.ru 2134198Sigor@sysoev.ru rpc = data; 2135198Sigor@sysoev.ru 2136*1558Smax.romanov@nginx.com s = msg->fd[0]; 2137198Sigor@sysoev.ru 2138198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 2139198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2140198Sigor@sysoev.ru goto fail; 214153Sigor@sysoev.ru } 214253Sigor@sysoev.ru 2143359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 2144198Sigor@sysoev.ru 2145198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 2146198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2147198Sigor@sysoev.ru goto fail; 2148198Sigor@sysoev.ru } 2149198Sigor@sysoev.ru 2150359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 2151198Sigor@sysoev.ru 2152198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2153198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2154198Sigor@sysoev.ru 2155198Sigor@sysoev.ru return; 2156148Sigor@sysoev.ru 2157148Sigor@sysoev.ru fail: 2158148Sigor@sysoev.ru 2159148Sigor@sysoev.ru nxt_socket_close(task, s); 2160148Sigor@sysoev.ru 2161198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2162198Sigor@sysoev.ru } 2163198Sigor@sysoev.ru 2164198Sigor@sysoev.ru 2165198Sigor@sysoev.ru static void 2166198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2167198Sigor@sysoev.ru void *data) 2168198Sigor@sysoev.ru { 2169955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2170955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2171955Svbart@nginx.com 2172955Svbart@nginx.com rpc = data; 2173955Svbart@nginx.com tmcf = rpc->temp_conf; 2174955Svbart@nginx.com 2175955Svbart@nginx.com #if 0 2176198Sigor@sysoev.ru u_char *p; 2177198Sigor@sysoev.ru size_t size; 2178198Sigor@sysoev.ru uint8_t error; 2179198Sigor@sysoev.ru nxt_buf_t *in, *out; 2180198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2181198Sigor@sysoev.ru 2182198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2183198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2184198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2185198Sigor@sysoev.ru nxt_string("ListenerPort"), 2186198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2187198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2188198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2189198Sigor@sysoev.ru nxt_string("ListenerPath"), 2190198Sigor@sysoev.ru }; 2191198Sigor@sysoev.ru 2192359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2193352Smax.romanov@nginx.com 2194352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2195352Smax.romanov@nginx.com 2196551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2197551Smax.romanov@nginx.com return; 2198551Smax.romanov@nginx.com } 2199352Smax.romanov@nginx.com 2200198Sigor@sysoev.ru p = in->mem.pos; 2201198Sigor@sysoev.ru 2202198Sigor@sysoev.ru error = *p++; 2203198Sigor@sysoev.ru 2204703Svbart@nginx.com size = nxt_length("listen socket error: ") 2205703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2206198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2207198Sigor@sysoev.ru 2208198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2209198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2210198Sigor@sysoev.ru return; 2211198Sigor@sysoev.ru } 2212198Sigor@sysoev.ru 2213198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2214198Sigor@sysoev.ru "listen socket error: " 2215198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2216493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2217198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2218198Sigor@sysoev.ru 2219198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2220955Svbart@nginx.com #endif 2221198Sigor@sysoev.ru 2222198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 222353Sigor@sysoev.ru } 222453Sigor@sysoev.ru 222553Sigor@sysoev.ru 2226774Svbart@nginx.com #if (NXT_TLS) 2227774Svbart@nginx.com 2228774Svbart@nginx.com static void 2229774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2230774Svbart@nginx.com nxt_router_tlssock_t *tls) 2231774Svbart@nginx.com { 2232774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2233774Svbart@nginx.com 2234774Svbart@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2235774Svbart@nginx.com if (rpc == NULL) { 2236774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2237774Svbart@nginx.com return; 2238774Svbart@nginx.com } 2239774Svbart@nginx.com 2240774Svbart@nginx.com rpc->socket_conf = tls->conf; 2241774Svbart@nginx.com rpc->temp_conf = tmcf; 2242774Svbart@nginx.com 2243774Svbart@nginx.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 2244774Svbart@nginx.com nxt_router_tls_rpc_handler, rpc); 2245774Svbart@nginx.com } 2246774Svbart@nginx.com 2247774Svbart@nginx.com 2248774Svbart@nginx.com static void 2249774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2250774Svbart@nginx.com void *data) 2251774Svbart@nginx.com { 2252774Svbart@nginx.com nxt_mp_t *mp; 2253774Svbart@nginx.com nxt_int_t ret; 2254774Svbart@nginx.com nxt_tls_conf_t *tlscf; 2255774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2256774Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2257774Svbart@nginx.com 2258774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2259774Svbart@nginx.com 2260774Svbart@nginx.com rpc = data; 2261774Svbart@nginx.com tmcf = rpc->temp_conf; 2262774Svbart@nginx.com 2263774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2264774Svbart@nginx.com goto fail; 2265774Svbart@nginx.com } 2266774Svbart@nginx.com 2267774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2268774Svbart@nginx.com 2269774Svbart@nginx.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 2270774Svbart@nginx.com if (nxt_slow_path(tlscf == NULL)) { 2271774Svbart@nginx.com goto fail; 2272774Svbart@nginx.com } 2273774Svbart@nginx.com 2274*1558Smax.romanov@nginx.com tlscf->chain_file = msg->fd[0]; 2275774Svbart@nginx.com 2276774Svbart@nginx.com ret = task->thread->runtime->tls->server_init(task, tlscf); 2277774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2278774Svbart@nginx.com goto fail; 2279774Svbart@nginx.com } 2280774Svbart@nginx.com 2281774Svbart@nginx.com rpc->socket_conf->tls = tlscf; 2282774Svbart@nginx.com 2283774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2284774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2285774Svbart@nginx.com return; 2286774Svbart@nginx.com 2287774Svbart@nginx.com fail: 2288774Svbart@nginx.com 2289774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2290774Svbart@nginx.com } 2291774Svbart@nginx.com 2292774Svbart@nginx.com #endif 2293774Svbart@nginx.com 2294774Svbart@nginx.com 2295507Smax.romanov@nginx.com static void 2296507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2297507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2298507Smax.romanov@nginx.com { 2299507Smax.romanov@nginx.com size_t size; 2300507Smax.romanov@nginx.com uint32_t stream; 2301648Svbart@nginx.com nxt_int_t ret; 2302507Smax.romanov@nginx.com nxt_buf_t *b; 2303507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 2304507Smax.romanov@nginx.com nxt_runtime_t *rt; 2305507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2306507Smax.romanov@nginx.com 2307507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 2308507Smax.romanov@nginx.com if (rpc == NULL) { 2309507Smax.romanov@nginx.com goto fail; 2310507Smax.romanov@nginx.com } 2311507Smax.romanov@nginx.com 2312507Smax.romanov@nginx.com rpc->app = app; 2313507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2314507Smax.romanov@nginx.com 2315507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 2316507Smax.romanov@nginx.com 2317507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 2318507Smax.romanov@nginx.com 2319507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2320507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2321507Smax.romanov@nginx.com goto fail; 2322507Smax.romanov@nginx.com } 2323507Smax.romanov@nginx.com 2324507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 2325507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 2326507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2327507Smax.romanov@nginx.com 2328507Smax.romanov@nginx.com rt = task->thread->runtime; 2329507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2330507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2331507Smax.romanov@nginx.com 2332507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2333507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 2334507Smax.romanov@nginx.com nxt_router_app_prefork_error, 2335507Smax.romanov@nginx.com -1, rpc); 2336507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2337507Smax.romanov@nginx.com goto fail; 2338507Smax.romanov@nginx.com } 2339507Smax.romanov@nginx.com 23401488St.nateldemoura@f5.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS, 23411488St.nateldemoura@f5.com -1, stream, router_port->id, b); 2342648Svbart@nginx.com 2343648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2344648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2345648Svbart@nginx.com goto fail; 2346648Svbart@nginx.com } 2347648Svbart@nginx.com 2348507Smax.romanov@nginx.com app->pending_processes++; 2349507Smax.romanov@nginx.com 2350507Smax.romanov@nginx.com return; 2351507Smax.romanov@nginx.com 2352507Smax.romanov@nginx.com fail: 2353507Smax.romanov@nginx.com 2354507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2355507Smax.romanov@nginx.com } 2356507Smax.romanov@nginx.com 2357507Smax.romanov@nginx.com 2358507Smax.romanov@nginx.com static void 2359507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2360507Smax.romanov@nginx.com void *data) 2361507Smax.romanov@nginx.com { 2362507Smax.romanov@nginx.com nxt_app_t *app; 2363507Smax.romanov@nginx.com nxt_port_t *port; 2364507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2365507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2366507Smax.romanov@nginx.com 2367507Smax.romanov@nginx.com rpc = data; 2368507Smax.romanov@nginx.com app = rpc->app; 2369507Smax.romanov@nginx.com 2370507Smax.romanov@nginx.com port = msg->u.new_port; 23711547Smax.romanov@nginx.com 23721547Smax.romanov@nginx.com nxt_assert(port != NULL); 23731547Smax.romanov@nginx.com nxt_assert(port->type == NXT_PROCESS_APP); 23741547Smax.romanov@nginx.com nxt_assert(port->id == 0); 23751547Smax.romanov@nginx.com 2376507Smax.romanov@nginx.com port->app = app; 23771547Smax.romanov@nginx.com port->main_app_port = port; 2378507Smax.romanov@nginx.com 2379507Smax.romanov@nginx.com app->pending_processes--; 2380507Smax.romanov@nginx.com app->processes++; 2381507Smax.romanov@nginx.com app->idle_processes++; 2382507Smax.romanov@nginx.com 2383507Smax.romanov@nginx.com engine = task->thread->engine; 2384507Smax.romanov@nginx.com 2385507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2386507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 23871549Smax.romanov@nginx.com 23881549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports", 23891549Smax.romanov@nginx.com &app->name, port->pid, port->id); 23901549Smax.romanov@nginx.com 23911547Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 23921547Smax.romanov@nginx.com app->port_hash_count++; 2393507Smax.romanov@nginx.com 2394507Smax.romanov@nginx.com port->idle_start = 0; 2395507Smax.romanov@nginx.com 2396507Smax.romanov@nginx.com nxt_port_inc_use(port); 2397507Smax.romanov@nginx.com 23981547Smax.romanov@nginx.com nxt_router_app_shared_port_send(task, port); 23991547Smax.romanov@nginx.com 2400507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2401507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2402507Smax.romanov@nginx.com } 2403507Smax.romanov@nginx.com 2404507Smax.romanov@nginx.com 2405507Smax.romanov@nginx.com static void 2406507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2407507Smax.romanov@nginx.com void *data) 2408507Smax.romanov@nginx.com { 2409507Smax.romanov@nginx.com nxt_app_t *app; 2410507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2411507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2412507Smax.romanov@nginx.com 2413507Smax.romanov@nginx.com rpc = data; 2414507Smax.romanov@nginx.com app = rpc->app; 2415507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2416507Smax.romanov@nginx.com 2417507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2418507Smax.romanov@nginx.com &app->name); 2419507Smax.romanov@nginx.com 2420507Smax.romanov@nginx.com app->pending_processes--; 2421507Smax.romanov@nginx.com 2422507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2423507Smax.romanov@nginx.com } 2424507Smax.romanov@nginx.com 2425507Smax.romanov@nginx.com 242653Sigor@sysoev.ru static nxt_int_t 242753Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 242853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 242953Sigor@sysoev.ru { 243053Sigor@sysoev.ru nxt_int_t ret; 243153Sigor@sysoev.ru nxt_uint_t n, threads; 243253Sigor@sysoev.ru nxt_queue_link_t *qlk; 243353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 243453Sigor@sysoev.ru 2435591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 243653Sigor@sysoev.ru 243753Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 243853Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 243953Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 244053Sigor@sysoev.ru return NXT_ERROR; 244153Sigor@sysoev.ru } 244253Sigor@sysoev.ru 244353Sigor@sysoev.ru n = 0; 244453Sigor@sysoev.ru 244553Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 244653Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 244753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 244853Sigor@sysoev.ru { 244953Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 245053Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 245153Sigor@sysoev.ru return NXT_ERROR; 245253Sigor@sysoev.ru } 245353Sigor@sysoev.ru 2454115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 245553Sigor@sysoev.ru 245653Sigor@sysoev.ru if (n < threads) { 2457315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2458115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 245953Sigor@sysoev.ru 246053Sigor@sysoev.ru } else { 2461315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2462115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 246353Sigor@sysoev.ru } 246453Sigor@sysoev.ru 246553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 246653Sigor@sysoev.ru return ret; 246753Sigor@sysoev.ru } 246853Sigor@sysoev.ru 246953Sigor@sysoev.ru n++; 247053Sigor@sysoev.ru } 247153Sigor@sysoev.ru 247253Sigor@sysoev.ru tmcf->new_threads = n; 247353Sigor@sysoev.ru 247453Sigor@sysoev.ru while (n < threads) { 247553Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 247653Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 247753Sigor@sysoev.ru return NXT_ERROR; 247853Sigor@sysoev.ru } 247953Sigor@sysoev.ru 2480315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2481315Sigor@sysoev.ru 248253Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 248353Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 248453Sigor@sysoev.ru return NXT_ERROR; 248553Sigor@sysoev.ru } 248653Sigor@sysoev.ru 2487115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 248853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 248953Sigor@sysoev.ru return ret; 249053Sigor@sysoev.ru } 249153Sigor@sysoev.ru 249253Sigor@sysoev.ru n++; 249353Sigor@sysoev.ru } 249453Sigor@sysoev.ru 249553Sigor@sysoev.ru return NXT_OK; 249653Sigor@sysoev.ru } 249753Sigor@sysoev.ru 249853Sigor@sysoev.ru 249953Sigor@sysoev.ru static nxt_int_t 2500115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2501115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 250253Sigor@sysoev.ru { 2503359Sigor@sysoev.ru nxt_int_t ret; 250453Sigor@sysoev.ru 25051509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, 2506154Sigor@sysoev.ru nxt_router_listen_socket_create); 2507115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2508115Sigor@sysoev.ru return ret; 2509115Sigor@sysoev.ru } 2510115Sigor@sysoev.ru 25111509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, 2512154Sigor@sysoev.ru nxt_router_listen_socket_create); 251353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 251453Sigor@sysoev.ru return ret; 251553Sigor@sysoev.ru } 251653Sigor@sysoev.ru 2517115Sigor@sysoev.ru return ret; 251853Sigor@sysoev.ru } 251953Sigor@sysoev.ru 252053Sigor@sysoev.ru 252153Sigor@sysoev.ru static nxt_int_t 2522115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2523115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 252453Sigor@sysoev.ru { 2525359Sigor@sysoev.ru nxt_int_t ret; 252653Sigor@sysoev.ru 25271509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, 2528154Sigor@sysoev.ru nxt_router_listen_socket_create); 252953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 253053Sigor@sysoev.ru return ret; 253153Sigor@sysoev.ru } 253253Sigor@sysoev.ru 25331509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, 2534154Sigor@sysoev.ru nxt_router_listen_socket_update); 253553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 253653Sigor@sysoev.ru return ret; 253753Sigor@sysoev.ru } 253853Sigor@sysoev.ru 25391509Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); 2540115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2541115Sigor@sysoev.ru return ret; 2542115Sigor@sysoev.ru } 2543115Sigor@sysoev.ru 2544115Sigor@sysoev.ru return ret; 254553Sigor@sysoev.ru } 254653Sigor@sysoev.ru 254753Sigor@sysoev.ru 254853Sigor@sysoev.ru static nxt_int_t 2549115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2550115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 255153Sigor@sysoev.ru { 255253Sigor@sysoev.ru nxt_int_t ret; 255353Sigor@sysoev.ru 2554313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2555313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2556313Sigor@sysoev.ru return ret; 2557313Sigor@sysoev.ru } 2558313Sigor@sysoev.ru 25591509Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets); 256053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 256153Sigor@sysoev.ru return ret; 256253Sigor@sysoev.ru } 256353Sigor@sysoev.ru 25641509Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); 256553Sigor@sysoev.ru } 256653Sigor@sysoev.ru 256753Sigor@sysoev.ru 256853Sigor@sysoev.ru static nxt_int_t 2569154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2570154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 257153Sigor@sysoev.ru nxt_work_handler_t handler) 257253Sigor@sysoev.ru { 25731394Sigor@sysoev.ru nxt_int_t ret; 2574153Sigor@sysoev.ru nxt_joint_job_t *job; 257553Sigor@sysoev.ru nxt_queue_link_t *qlk; 2576155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 257753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 257853Sigor@sysoev.ru 257953Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 258053Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 258153Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 258253Sigor@sysoev.ru { 2583154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2584153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2585139Sigor@sysoev.ru return NXT_ERROR; 2586139Sigor@sysoev.ru } 2587139Sigor@sysoev.ru 2588154Sigor@sysoev.ru job->work.next = recf->jobs; 2589154Sigor@sysoev.ru recf->jobs = &job->work; 2590154Sigor@sysoev.ru 2591153Sigor@sysoev.ru job->task = tmcf->engine->task; 2592153Sigor@sysoev.ru job->work.handler = handler; 2593153Sigor@sysoev.ru job->work.task = &job->task; 2594153Sigor@sysoev.ru job->work.obj = job; 2595153Sigor@sysoev.ru job->tmcf = tmcf; 259653Sigor@sysoev.ru 2597154Sigor@sysoev.ru tmcf->count++; 2598154Sigor@sysoev.ru 2599591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2600154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 260153Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 260253Sigor@sysoev.ru return NXT_ERROR; 260353Sigor@sysoev.ru } 260453Sigor@sysoev.ru 2605153Sigor@sysoev.ru job->work.data = joint; 260653Sigor@sysoev.ru 26071394Sigor@sysoev.ru ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams); 26081394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 26091394Sigor@sysoev.ru return ret; 26101394Sigor@sysoev.ru } 26111394Sigor@sysoev.ru 261253Sigor@sysoev.ru joint->count = 1; 2613155Sigor@sysoev.ru 2614155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2615155Sigor@sysoev.ru skcf->count++; 2616155Sigor@sysoev.ru joint->socket_conf = skcf; 2617155Sigor@sysoev.ru 261888Smax.romanov@nginx.com joint->engine = recf->engine; 261953Sigor@sysoev.ru } 262053Sigor@sysoev.ru 262120Sigor@sysoev.ru return NXT_OK; 262220Sigor@sysoev.ru } 262320Sigor@sysoev.ru 262420Sigor@sysoev.ru 262520Sigor@sysoev.ru static nxt_int_t 2626313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2627313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2628313Sigor@sysoev.ru { 2629313Sigor@sysoev.ru nxt_joint_job_t *job; 2630313Sigor@sysoev.ru 2631313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2632313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2633313Sigor@sysoev.ru return NXT_ERROR; 2634313Sigor@sysoev.ru } 2635313Sigor@sysoev.ru 2636313Sigor@sysoev.ru job->work.next = recf->jobs; 2637313Sigor@sysoev.ru recf->jobs = &job->work; 2638313Sigor@sysoev.ru 2639313Sigor@sysoev.ru job->task = tmcf->engine->task; 2640313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2641313Sigor@sysoev.ru job->work.task = &job->task; 2642313Sigor@sysoev.ru job->work.obj = NULL; 2643313Sigor@sysoev.ru job->work.data = NULL; 2644313Sigor@sysoev.ru job->tmcf = NULL; 2645313Sigor@sysoev.ru 2646313Sigor@sysoev.ru return NXT_OK; 2647313Sigor@sysoev.ru } 2648313Sigor@sysoev.ru 2649313Sigor@sysoev.ru 2650313Sigor@sysoev.ru static nxt_int_t 2651139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2652139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 265320Sigor@sysoev.ru { 2654153Sigor@sysoev.ru nxt_joint_job_t *job; 265553Sigor@sysoev.ru nxt_queue_link_t *qlk; 265620Sigor@sysoev.ru 265753Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 265853Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 265953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 266053Sigor@sysoev.ru { 2661154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2662153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2663139Sigor@sysoev.ru return NXT_ERROR; 2664139Sigor@sysoev.ru } 2665139Sigor@sysoev.ru 2666154Sigor@sysoev.ru job->work.next = recf->jobs; 2667154Sigor@sysoev.ru recf->jobs = &job->work; 2668154Sigor@sysoev.ru 2669153Sigor@sysoev.ru job->task = tmcf->engine->task; 2670153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2671153Sigor@sysoev.ru job->work.task = &job->task; 2672153Sigor@sysoev.ru job->work.obj = job; 2673153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2674153Sigor@sysoev.ru job->tmcf = tmcf; 2675154Sigor@sysoev.ru 2676154Sigor@sysoev.ru tmcf->count++; 267720Sigor@sysoev.ru } 267820Sigor@sysoev.ru 267953Sigor@sysoev.ru return NXT_OK; 268053Sigor@sysoev.ru } 268120Sigor@sysoev.ru 268220Sigor@sysoev.ru 268353Sigor@sysoev.ru static nxt_int_t 268453Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 268553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 268653Sigor@sysoev.ru { 268753Sigor@sysoev.ru nxt_int_t ret; 268853Sigor@sysoev.ru nxt_uint_t i, threads; 268953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 269020Sigor@sysoev.ru 269153Sigor@sysoev.ru recf = tmcf->engines->elts; 2692591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 269320Sigor@sysoev.ru 269453Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 269553Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 269653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 269753Sigor@sysoev.ru return ret; 269853Sigor@sysoev.ru } 269920Sigor@sysoev.ru } 270020Sigor@sysoev.ru 270120Sigor@sysoev.ru return NXT_OK; 270220Sigor@sysoev.ru } 270353Sigor@sysoev.ru 270453Sigor@sysoev.ru 270553Sigor@sysoev.ru static nxt_int_t 270653Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 270753Sigor@sysoev.ru nxt_event_engine_t *engine) 270853Sigor@sysoev.ru { 270953Sigor@sysoev.ru nxt_int_t ret; 271053Sigor@sysoev.ru nxt_thread_link_t *link; 271153Sigor@sysoev.ru nxt_thread_handle_t handle; 271253Sigor@sysoev.ru 271353Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 271453Sigor@sysoev.ru 271553Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 271653Sigor@sysoev.ru return NXT_ERROR; 271753Sigor@sysoev.ru } 271853Sigor@sysoev.ru 271953Sigor@sysoev.ru link->start = nxt_router_thread_start; 272053Sigor@sysoev.ru link->engine = engine; 272153Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 272253Sigor@sysoev.ru link->work.task = task; 272353Sigor@sysoev.ru link->work.data = link; 272453Sigor@sysoev.ru 272553Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 272653Sigor@sysoev.ru 272753Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 272853Sigor@sysoev.ru 272953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 273053Sigor@sysoev.ru nxt_queue_remove(&engine->link); 273153Sigor@sysoev.ru } 273253Sigor@sysoev.ru 273353Sigor@sysoev.ru return ret; 273453Sigor@sysoev.ru } 273553Sigor@sysoev.ru 273653Sigor@sysoev.ru 273753Sigor@sysoev.ru static void 2738343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2739343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2740133Sigor@sysoev.ru { 2741507Smax.romanov@nginx.com nxt_app_t *app; 2742141Smax.romanov@nginx.com 2743141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2744133Sigor@sysoev.ru 2745753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2746343Smax.romanov@nginx.com 2747141Smax.romanov@nginx.com } nxt_queue_loop; 2748133Sigor@sysoev.ru 2749133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2750133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2751133Sigor@sysoev.ru } 2752133Sigor@sysoev.ru 2753133Sigor@sysoev.ru 2754133Sigor@sysoev.ru static void 2755315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 275653Sigor@sysoev.ru { 275753Sigor@sysoev.ru nxt_uint_t n; 2758315Sigor@sysoev.ru nxt_event_engine_t *engine; 275953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 276053Sigor@sysoev.ru 276153Sigor@sysoev.ru recf = tmcf->engines->elts; 276253Sigor@sysoev.ru 276353Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2764315Sigor@sysoev.ru engine = recf->engine; 2765315Sigor@sysoev.ru 2766315Sigor@sysoev.ru switch (recf->action) { 2767315Sigor@sysoev.ru 2768315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2769315Sigor@sysoev.ru break; 2770315Sigor@sysoev.ru 2771315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2772315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2773315Sigor@sysoev.ru break; 2774315Sigor@sysoev.ru 2775315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2776315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2777315Sigor@sysoev.ru break; 2778315Sigor@sysoev.ru } 2779315Sigor@sysoev.ru 2780316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2781316Sigor@sysoev.ru 278253Sigor@sysoev.ru recf++; 278353Sigor@sysoev.ru } 278453Sigor@sysoev.ru } 278553Sigor@sysoev.ru 278653Sigor@sysoev.ru 278753Sigor@sysoev.ru static void 2788315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 278953Sigor@sysoev.ru { 2790154Sigor@sysoev.ru nxt_work_t *work, *next; 2791154Sigor@sysoev.ru 2792315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2793154Sigor@sysoev.ru next = work->next; 2794154Sigor@sysoev.ru work->next = NULL; 2795154Sigor@sysoev.ru 2796315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 279753Sigor@sysoev.ru } 279853Sigor@sysoev.ru } 279953Sigor@sysoev.ru 280053Sigor@sysoev.ru 2801320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 28021547Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 28031547Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 28041547Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 28051547Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 28061547Smax.romanov@nginx.com .req_headers_ack = nxt_port_rpc_handler, 280788Smax.romanov@nginx.com }; 280888Smax.romanov@nginx.com 280988Smax.romanov@nginx.com 281088Smax.romanov@nginx.com static void 281153Sigor@sysoev.ru nxt_router_thread_start(void *data) 281253Sigor@sysoev.ru { 2813141Smax.romanov@nginx.com nxt_int_t ret; 2814141Smax.romanov@nginx.com nxt_port_t *port; 281588Smax.romanov@nginx.com nxt_task_t *task; 28161545Smax.romanov@nginx.com nxt_work_t *work; 281753Sigor@sysoev.ru nxt_thread_t *thread; 281853Sigor@sysoev.ru nxt_thread_link_t *link; 281953Sigor@sysoev.ru nxt_event_engine_t *engine; 282053Sigor@sysoev.ru 282153Sigor@sysoev.ru link = data; 282253Sigor@sysoev.ru engine = link->engine; 282388Smax.romanov@nginx.com task = &engine->task; 282453Sigor@sysoev.ru 282553Sigor@sysoev.ru thread = nxt_thread(); 282653Sigor@sysoev.ru 2827165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2828165Smax.romanov@nginx.com 282953Sigor@sysoev.ru /* STUB */ 283053Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 283153Sigor@sysoev.ru 283253Sigor@sysoev.ru engine->task.thread = thread; 283353Sigor@sysoev.ru engine->task.log = thread->log; 283453Sigor@sysoev.ru thread->engine = engine; 283563Sigor@sysoev.ru thread->task = &engine->task; 2836326Svbart@nginx.com #if 0 283753Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2838326Svbart@nginx.com #endif 283953Sigor@sysoev.ru 284063Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2841337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2842337Sigor@sysoev.ru return; 2843337Sigor@sysoev.ru } 284453Sigor@sysoev.ru 2845197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2846197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2847141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2848141Smax.romanov@nginx.com return; 2849141Smax.romanov@nginx.com } 2850141Smax.romanov@nginx.com 2851141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2852141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2853343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2854141Smax.romanov@nginx.com return; 2855141Smax.romanov@nginx.com } 2856141Smax.romanov@nginx.com 28571555Smax.romanov@nginx.com ret = nxt_router_port_queue_init(task, port); 28581555Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 28591555Smax.romanov@nginx.com nxt_port_use(task, port, -1); 28601555Smax.romanov@nginx.com return; 28611555Smax.romanov@nginx.com } 28621555Smax.romanov@nginx.com 2863141Smax.romanov@nginx.com engine->port = port; 2864141Smax.romanov@nginx.com 2865320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2866141Smax.romanov@nginx.com 28671545Smax.romanov@nginx.com work = nxt_zalloc(sizeof(nxt_work_t)); 28681545Smax.romanov@nginx.com if (nxt_slow_path(work == NULL)) { 28691545Smax.romanov@nginx.com return; 28701545Smax.romanov@nginx.com } 28711545Smax.romanov@nginx.com 28721545Smax.romanov@nginx.com work->handler = nxt_router_rt_add_port; 28731545Smax.romanov@nginx.com work->task = link->work.task; 28741545Smax.romanov@nginx.com work->obj = work; 28751545Smax.romanov@nginx.com work->data = port; 28761545Smax.romanov@nginx.com 28771545Smax.romanov@nginx.com nxt_event_engine_post(link->work.task->thread->engine, work); 28781545Smax.romanov@nginx.com 287953Sigor@sysoev.ru nxt_event_engine_start(engine); 288053Sigor@sysoev.ru } 288153Sigor@sysoev.ru 288253Sigor@sysoev.ru 288353Sigor@sysoev.ru static void 28841545Smax.romanov@nginx.com nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data) 28851545Smax.romanov@nginx.com { 28861545Smax.romanov@nginx.com nxt_int_t res; 28871545Smax.romanov@nginx.com nxt_port_t *port; 28881545Smax.romanov@nginx.com nxt_runtime_t *rt; 28891545Smax.romanov@nginx.com 28901545Smax.romanov@nginx.com rt = task->thread->runtime; 28911545Smax.romanov@nginx.com port = data; 28921545Smax.romanov@nginx.com 28931545Smax.romanov@nginx.com nxt_free(obj); 28941545Smax.romanov@nginx.com 28951545Smax.romanov@nginx.com res = nxt_port_hash_add(&rt->ports, port); 28961545Smax.romanov@nginx.com 28971545Smax.romanov@nginx.com if (nxt_fast_path(res == NXT_OK)) { 28981545Smax.romanov@nginx.com nxt_port_use(task, port, 1); 28991545Smax.romanov@nginx.com } 29001545Smax.romanov@nginx.com } 29011545Smax.romanov@nginx.com 29021545Smax.romanov@nginx.com 29031545Smax.romanov@nginx.com static void 290453Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 290553Sigor@sysoev.ru { 2906153Sigor@sysoev.ru nxt_joint_job_t *job; 2907359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2908359Sigor@sysoev.ru nxt_listen_event_t *lev; 290953Sigor@sysoev.ru nxt_listen_socket_t *ls; 2910359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 291153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 291253Sigor@sysoev.ru 2913153Sigor@sysoev.ru job = obj; 291453Sigor@sysoev.ru joint = data; 291553Sigor@sysoev.ru 2916159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2917159Sigor@sysoev.ru 2918359Sigor@sysoev.ru skcf = joint->socket_conf; 2919359Sigor@sysoev.ru ls = skcf->listen; 2920359Sigor@sysoev.ru 2921359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2922359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2923359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 292453Sigor@sysoev.ru return; 292553Sigor@sysoev.ru } 292653Sigor@sysoev.ru 2927359Sigor@sysoev.ru lev->socket.data = joint; 2928359Sigor@sysoev.ru 2929359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2930359Sigor@sysoev.ru 2931359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2932359Sigor@sysoev.ru ls->count++; 2933359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2934139Sigor@sysoev.ru 2935153Sigor@sysoev.ru job->work.next = NULL; 2936153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2937153Sigor@sysoev.ru 2938153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 293953Sigor@sysoev.ru } 294053Sigor@sysoev.ru 294153Sigor@sysoev.ru 294253Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 294353Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 294453Sigor@sysoev.ru nxt_socket_conf_t *skcf) 294553Sigor@sysoev.ru { 2946115Sigor@sysoev.ru nxt_socket_t fd; 2947115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2948359Sigor@sysoev.ru nxt_listen_event_t *lev; 2949359Sigor@sysoev.ru 2950359Sigor@sysoev.ru fd = skcf->listen->socket; 295153Sigor@sysoev.ru 2952115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2953115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2954115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 295553Sigor@sysoev.ru { 2956359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2957359Sigor@sysoev.ru 2958359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2959359Sigor@sysoev.ru return lev; 296053Sigor@sysoev.ru } 296153Sigor@sysoev.ru } 296253Sigor@sysoev.ru 296353Sigor@sysoev.ru return NULL; 296453Sigor@sysoev.ru } 296553Sigor@sysoev.ru 296653Sigor@sysoev.ru 296753Sigor@sysoev.ru static void 296853Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 296953Sigor@sysoev.ru { 2970153Sigor@sysoev.ru nxt_joint_job_t *job; 297153Sigor@sysoev.ru nxt_event_engine_t *engine; 2972359Sigor@sysoev.ru nxt_listen_event_t *lev; 297353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 297453Sigor@sysoev.ru 2975153Sigor@sysoev.ru job = obj; 297653Sigor@sysoev.ru joint = data; 297753Sigor@sysoev.ru 2978139Sigor@sysoev.ru engine = task->thread->engine; 2979139Sigor@sysoev.ru 2980159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2981159Sigor@sysoev.ru 2982359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2983359Sigor@sysoev.ru joint->socket_conf); 2984359Sigor@sysoev.ru 2985359Sigor@sysoev.ru old = lev->socket.data; 2986359Sigor@sysoev.ru lev->socket.data = joint; 2987359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 298853Sigor@sysoev.ru 2989153Sigor@sysoev.ru job->work.next = NULL; 2990153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2991153Sigor@sysoev.ru 2992153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2993139Sigor@sysoev.ru 2994181Smax.romanov@nginx.com /* 2995181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2996181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2997181Smax.romanov@nginx.com */ 2998181Smax.romanov@nginx.com 2999181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 300053Sigor@sysoev.ru } 300153Sigor@sysoev.ru 300253Sigor@sysoev.ru 300353Sigor@sysoev.ru static void 300453Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 300553Sigor@sysoev.ru { 3006153Sigor@sysoev.ru nxt_joint_job_t *job; 3007153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 3008359Sigor@sysoev.ru nxt_listen_event_t *lev; 3009153Sigor@sysoev.ru nxt_event_engine_t *engine; 3010153Sigor@sysoev.ru 3011153Sigor@sysoev.ru job = obj; 301253Sigor@sysoev.ru skcf = data; 301353Sigor@sysoev.ru 3014139Sigor@sysoev.ru engine = task->thread->engine; 3015139Sigor@sysoev.ru 3016359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 3017359Sigor@sysoev.ru 3018359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 301953Sigor@sysoev.ru 3020163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 3021359Sigor@sysoev.ru lev->socket.fd); 3022359Sigor@sysoev.ru 3023359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 3024359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 3025359Sigor@sysoev.ru 3026359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 3027139Sigor@sysoev.ru 3028153Sigor@sysoev.ru job->work.next = NULL; 3029153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 3030153Sigor@sysoev.ru 3031153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 303253Sigor@sysoev.ru } 303353Sigor@sysoev.ru 303453Sigor@sysoev.ru 303553Sigor@sysoev.ru static void 3036313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 3037313Sigor@sysoev.ru { 3038313Sigor@sysoev.ru nxt_event_engine_t *engine; 3039313Sigor@sysoev.ru 3040313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 3041313Sigor@sysoev.ru 3042313Sigor@sysoev.ru engine = task->thread->engine; 3043313Sigor@sysoev.ru 3044313Sigor@sysoev.ru engine->shutdown = 1; 3045313Sigor@sysoev.ru 3046313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 3047313Sigor@sysoev.ru nxt_thread_exit(task->thread); 3048313Sigor@sysoev.ru } 3049313Sigor@sysoev.ru } 3050313Sigor@sysoev.ru 3051313Sigor@sysoev.ru 3052313Sigor@sysoev.ru static void 305353Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 305453Sigor@sysoev.ru { 305553Sigor@sysoev.ru nxt_timer_t *timer; 3056359Sigor@sysoev.ru nxt_listen_event_t *lev; 305753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 305853Sigor@sysoev.ru 305953Sigor@sysoev.ru timer = obj; 3060359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 306153Sigor@sysoev.ru 3062163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 3063359Sigor@sysoev.ru lev->socket.fd); 3064359Sigor@sysoev.ru 3065359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 3066359Sigor@sysoev.ru 3067683Sigor@sysoev.ru joint = lev->socket.data; 3068683Sigor@sysoev.ru lev->socket.data = NULL; 3069683Sigor@sysoev.ru 3070359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 3071123Smax.romanov@nginx.com task = &task->thread->engine->task; 3072123Smax.romanov@nginx.com 3073359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 3074359Sigor@sysoev.ru 3075683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 307653Sigor@sysoev.ru } 307753Sigor@sysoev.ru 307853Sigor@sysoev.ru 307953Sigor@sysoev.ru static void 3080359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 308153Sigor@sysoev.ru { 3082359Sigor@sysoev.ru nxt_listen_socket_t *ls; 308353Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 308453Sigor@sysoev.ru 3085359Sigor@sysoev.ru ls = skcf->listen; 3086118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 308753Sigor@sysoev.ru 308853Sigor@sysoev.ru nxt_thread_spin_lock(lock); 308953Sigor@sysoev.ru 3090359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 3091359Sigor@sysoev.ru task->thread->engine, ls->count); 3092359Sigor@sysoev.ru 3093359Sigor@sysoev.ru if (--ls->count != 0) { 3094359Sigor@sysoev.ru ls = NULL; 309553Sigor@sysoev.ru } 309653Sigor@sysoev.ru 309753Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 309853Sigor@sysoev.ru 3099359Sigor@sysoev.ru if (ls != NULL) { 3100359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 3101359Sigor@sysoev.ru nxt_free(ls); 310253Sigor@sysoev.ru } 310353Sigor@sysoev.ru } 310453Sigor@sysoev.ru 310553Sigor@sysoev.ru 3106683Sigor@sysoev.ru void 3107683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 3108683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 3109683Sigor@sysoev.ru { 3110683Sigor@sysoev.ru nxt_event_engine_t *engine; 3111683Sigor@sysoev.ru 3112683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 3113683Sigor@sysoev.ru 31141541Smax.romanov@nginx.com engine = task->thread->engine; 31151541Smax.romanov@nginx.com 3116683Sigor@sysoev.ru if (--lev->count == 0) { 31171535Smax.romanov@nginx.com if (lev->next != NULL) { 31181541Smax.romanov@nginx.com nxt_sockaddr_cache_free(engine, lev->next); 31191541Smax.romanov@nginx.com 31201535Smax.romanov@nginx.com nxt_conn_free(task, lev->next); 31211535Smax.romanov@nginx.com } 31221535Smax.romanov@nginx.com 3123683Sigor@sysoev.ru nxt_free(lev); 3124683Sigor@sysoev.ru } 3125683Sigor@sysoev.ru 3126683Sigor@sysoev.ru if (joint != NULL) { 3127683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 3128683Sigor@sysoev.ru } 3129683Sigor@sysoev.ru 3130683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 3131683Sigor@sysoev.ru nxt_thread_exit(task->thread); 3132683Sigor@sysoev.ru } 3133683Sigor@sysoev.ru } 3134683Sigor@sysoev.ru 3135683Sigor@sysoev.ru 3136683Sigor@sysoev.ru void 313753Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 313853Sigor@sysoev.ru { 313953Sigor@sysoev.ru nxt_socket_conf_t *skcf; 314053Sigor@sysoev.ru nxt_router_conf_t *rtcf; 314153Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 314253Sigor@sysoev.ru 3143163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 314453Sigor@sysoev.ru 314553Sigor@sysoev.ru if (--joint->count != 0) { 314653Sigor@sysoev.ru return; 314753Sigor@sysoev.ru } 314853Sigor@sysoev.ru 314953Sigor@sysoev.ru nxt_queue_remove(&joint->link); 315053Sigor@sysoev.ru 3151530Sigor@sysoev.ru /* 3152530Sigor@sysoev.ru * The joint content can not be safely used after the critical 3153530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 3154530Sigor@sysoev.ru * be already destroyed by another thread. 3155530Sigor@sysoev.ru */ 315653Sigor@sysoev.ru skcf = joint->socket_conf; 315753Sigor@sysoev.ru rtcf = skcf->router_conf; 315853Sigor@sysoev.ru lock = &rtcf->router->lock; 315953Sigor@sysoev.ru 316053Sigor@sysoev.ru nxt_thread_spin_lock(lock); 316153Sigor@sysoev.ru 3162163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 3163163Smax.romanov@nginx.com rtcf, rtcf->count); 3164163Smax.romanov@nginx.com 316553Sigor@sysoev.ru if (--skcf->count != 0) { 3166952Sigor@sysoev.ru skcf = NULL; 316753Sigor@sysoev.ru rtcf = NULL; 316853Sigor@sysoev.ru 316953Sigor@sysoev.ru } else { 317053Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 317153Sigor@sysoev.ru 317253Sigor@sysoev.ru if (--rtcf->count != 0) { 317353Sigor@sysoev.ru rtcf = NULL; 317453Sigor@sysoev.ru } 317553Sigor@sysoev.ru } 317653Sigor@sysoev.ru 317753Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 317853Sigor@sysoev.ru 3179952Sigor@sysoev.ru if (skcf != NULL) { 31801264Sigor@sysoev.ru if (skcf->action != NULL) { 31811264Sigor@sysoev.ru nxt_http_action_cleanup(task, skcf->action); 3182964Sigor@sysoev.ru } 3183964Sigor@sysoev.ru 3184952Sigor@sysoev.ru #if (NXT_TLS) 3185952Sigor@sysoev.ru if (skcf->tls != NULL) { 3186952Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 3187952Sigor@sysoev.ru } 3188952Sigor@sysoev.ru #endif 3189952Sigor@sysoev.ru } 3190952Sigor@sysoev.ru 3191141Smax.romanov@nginx.com /* TODO remove engine->port */ 3192141Smax.romanov@nginx.com 319353Sigor@sysoev.ru if (rtcf != NULL) { 3194115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 3195131Smax.romanov@nginx.com 3196964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 3197964Sigor@sysoev.ru 3198630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 3199630Svbart@nginx.com 3200131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 3201131Smax.romanov@nginx.com 320265Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 320353Sigor@sysoev.ru } 320453Sigor@sysoev.ru } 320553Sigor@sysoev.ru 320653Sigor@sysoev.ru 320753Sigor@sysoev.ru static void 3208630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 3209630Svbart@nginx.com nxt_router_access_log_t *access_log) 3210630Svbart@nginx.com { 3211630Svbart@nginx.com size_t size; 3212630Svbart@nginx.com u_char *buf, *p; 3213630Svbart@nginx.com nxt_off_t bytes; 3214630Svbart@nginx.com 3215630Svbart@nginx.com static nxt_time_string_t date_cache = { 3216630Svbart@nginx.com (nxt_atomic_uint_t) -1, 3217630Svbart@nginx.com nxt_router_access_log_date, 3218630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 3219703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 3220630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 3221630Svbart@nginx.com NXT_THREAD_TIME_SEC, 3222630Svbart@nginx.com }; 3223630Svbart@nginx.com 3224630Svbart@nginx.com size = r->remote->address_length 3225630Svbart@nginx.com + 6 /* ' - - [' */ 3226630Svbart@nginx.com + date_cache.size 3227630Svbart@nginx.com + 3 /* '] "' */ 3228630Svbart@nginx.com + r->method->length 3229630Svbart@nginx.com + 1 /* space */ 3230630Svbart@nginx.com + r->target.length 3231630Svbart@nginx.com + 1 /* space */ 3232630Svbart@nginx.com + r->version.length 3233630Svbart@nginx.com + 2 /* '" ' */ 3234630Svbart@nginx.com + 3 /* status */ 3235630Svbart@nginx.com + 1 /* space */ 3236630Svbart@nginx.com + NXT_OFF_T_LEN 3237630Svbart@nginx.com + 2 /* ' "' */ 3238630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3239630Svbart@nginx.com + 3 /* '" "' */ 3240630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3241630Svbart@nginx.com + 2 /* '"\n' */ 3242630Svbart@nginx.com ; 3243630Svbart@nginx.com 3244630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3245630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3246630Svbart@nginx.com return; 3247630Svbart@nginx.com } 3248630Svbart@nginx.com 3249630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3250630Svbart@nginx.com r->remote->address_length); 3251630Svbart@nginx.com 3252630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3253630Svbart@nginx.com 3254630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3255630Svbart@nginx.com 3256630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3257630Svbart@nginx.com 3258630Svbart@nginx.com if (r->method->length != 0) { 3259630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3260630Svbart@nginx.com 3261630Svbart@nginx.com if (r->target.length != 0) { 3262630Svbart@nginx.com *p++ = ' '; 3263630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3264630Svbart@nginx.com 3265630Svbart@nginx.com if (r->version.length != 0) { 3266630Svbart@nginx.com *p++ = ' '; 3267630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3268630Svbart@nginx.com } 3269630Svbart@nginx.com } 3270630Svbart@nginx.com 3271630Svbart@nginx.com } else { 3272630Svbart@nginx.com *p++ = '-'; 3273630Svbart@nginx.com } 3274630Svbart@nginx.com 3275630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3276630Svbart@nginx.com 3277630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3278630Svbart@nginx.com 3279630Svbart@nginx.com *p++ = ' '; 3280630Svbart@nginx.com 32811112Sigor@sysoev.ru bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); 3282630Svbart@nginx.com 3283630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3284630Svbart@nginx.com 3285630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3286630Svbart@nginx.com 3287630Svbart@nginx.com if (r->referer != NULL) { 3288630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3289630Svbart@nginx.com 3290630Svbart@nginx.com } else { 3291630Svbart@nginx.com *p++ = '-'; 3292630Svbart@nginx.com } 3293630Svbart@nginx.com 3294630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3295630Svbart@nginx.com 3296630Svbart@nginx.com if (r->user_agent != NULL) { 3297630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3298630Svbart@nginx.com 3299630Svbart@nginx.com } else { 3300630Svbart@nginx.com *p++ = '-'; 3301630Svbart@nginx.com } 3302630Svbart@nginx.com 3303630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3304630Svbart@nginx.com 3305630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3306630Svbart@nginx.com } 3307630Svbart@nginx.com 3308630Svbart@nginx.com 3309630Svbart@nginx.com static u_char * 3310630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3311630Svbart@nginx.com size_t size, const char *format) 3312630Svbart@nginx.com { 3313630Svbart@nginx.com u_char sign; 3314630Svbart@nginx.com time_t gmtoff; 3315630Svbart@nginx.com 3316630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3317630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3318630Svbart@nginx.com 3319630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3320630Svbart@nginx.com 3321630Svbart@nginx.com if (gmtoff < 0) { 3322630Svbart@nginx.com gmtoff = -gmtoff; 3323630Svbart@nginx.com sign = '-'; 3324630Svbart@nginx.com 3325630Svbart@nginx.com } else { 3326630Svbart@nginx.com sign = '+'; 3327630Svbart@nginx.com } 3328630Svbart@nginx.com 3329630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3330630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3331630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3332630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3333630Svbart@nginx.com } 3334630Svbart@nginx.com 3335630Svbart@nginx.com 3336630Svbart@nginx.com static void 3337630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3338630Svbart@nginx.com { 3339630Svbart@nginx.com uint32_t stream; 3340648Svbart@nginx.com nxt_int_t ret; 3341630Svbart@nginx.com nxt_buf_t *b; 3342630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3343630Svbart@nginx.com nxt_runtime_t *rt; 3344630Svbart@nginx.com nxt_router_access_log_t *access_log; 3345630Svbart@nginx.com 3346630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3347630Svbart@nginx.com 3348630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3349630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3350630Svbart@nginx.com goto fail; 3351630Svbart@nginx.com } 3352630Svbart@nginx.com 3353630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3354630Svbart@nginx.com *b->mem.free++ = '\0'; 3355630Svbart@nginx.com 3356630Svbart@nginx.com rt = task->thread->runtime; 3357630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3358630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3359630Svbart@nginx.com 3360630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3361630Svbart@nginx.com nxt_router_access_log_ready, 3362630Svbart@nginx.com nxt_router_access_log_error, 3363630Svbart@nginx.com -1, tmcf); 3364630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3365630Svbart@nginx.com goto fail; 3366630Svbart@nginx.com } 3367630Svbart@nginx.com 3368648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3369648Svbart@nginx.com stream, router_port->id, b); 3370648Svbart@nginx.com 3371648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3372648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3373648Svbart@nginx.com goto fail; 3374648Svbart@nginx.com } 3375630Svbart@nginx.com 3376630Svbart@nginx.com return; 3377630Svbart@nginx.com 3378630Svbart@nginx.com fail: 3379630Svbart@nginx.com 3380630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3381630Svbart@nginx.com } 3382630Svbart@nginx.com 3383630Svbart@nginx.com 3384630Svbart@nginx.com static void 3385630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3386630Svbart@nginx.com void *data) 3387630Svbart@nginx.com { 3388630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3389630Svbart@nginx.com nxt_router_access_log_t *access_log; 3390630Svbart@nginx.com 3391630Svbart@nginx.com tmcf = data; 3392630Svbart@nginx.com 3393630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3394630Svbart@nginx.com 3395*1558Smax.romanov@nginx.com access_log->fd = msg->fd[0]; 3396630Svbart@nginx.com 3397630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3398630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3399630Svbart@nginx.com } 3400630Svbart@nginx.com 3401630Svbart@nginx.com 3402630Svbart@nginx.com static void 3403630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3404630Svbart@nginx.com void *data) 3405630Svbart@nginx.com { 3406630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3407630Svbart@nginx.com 3408630Svbart@nginx.com tmcf = data; 3409630Svbart@nginx.com 3410630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3411630Svbart@nginx.com } 3412630Svbart@nginx.com 3413630Svbart@nginx.com 3414630Svbart@nginx.com static void 3415630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3416630Svbart@nginx.com nxt_router_access_log_t *access_log) 3417630Svbart@nginx.com { 3418630Svbart@nginx.com if (access_log == NULL) { 3419630Svbart@nginx.com return; 3420630Svbart@nginx.com } 3421630Svbart@nginx.com 3422630Svbart@nginx.com nxt_thread_spin_lock(lock); 3423630Svbart@nginx.com 3424630Svbart@nginx.com if (--access_log->count != 0) { 3425630Svbart@nginx.com access_log = NULL; 3426630Svbart@nginx.com } 3427630Svbart@nginx.com 3428630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3429630Svbart@nginx.com 3430630Svbart@nginx.com if (access_log != NULL) { 3431630Svbart@nginx.com 3432630Svbart@nginx.com if (access_log->fd != -1) { 3433630Svbart@nginx.com nxt_fd_close(access_log->fd); 3434630Svbart@nginx.com } 3435630Svbart@nginx.com 3436630Svbart@nginx.com nxt_free(access_log); 3437630Svbart@nginx.com } 3438630Svbart@nginx.com } 3439630Svbart@nginx.com 3440630Svbart@nginx.com 3441631Svbart@nginx.com typedef struct { 3442631Svbart@nginx.com nxt_mp_t *mem_pool; 3443631Svbart@nginx.com nxt_router_access_log_t *access_log; 3444631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3445631Svbart@nginx.com 3446631Svbart@nginx.com 34471552Smax.romanov@nginx.com static void 3448631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3449631Svbart@nginx.com { 3450631Svbart@nginx.com nxt_mp_t *mp; 3451631Svbart@nginx.com uint32_t stream; 3452631Svbart@nginx.com nxt_int_t ret; 3453631Svbart@nginx.com nxt_buf_t *b; 3454631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3455631Svbart@nginx.com nxt_runtime_t *rt; 3456631Svbart@nginx.com nxt_router_access_log_t *access_log; 3457631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3458631Svbart@nginx.com 3459631Svbart@nginx.com access_log = nxt_router->access_log; 3460631Svbart@nginx.com 3461631Svbart@nginx.com if (access_log == NULL) { 3462631Svbart@nginx.com return; 3463631Svbart@nginx.com } 3464631Svbart@nginx.com 3465631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3466631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3467631Svbart@nginx.com return; 3468631Svbart@nginx.com } 3469631Svbart@nginx.com 3470631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3471631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3472631Svbart@nginx.com goto fail; 3473631Svbart@nginx.com } 3474631Svbart@nginx.com 3475631Svbart@nginx.com reopen->mem_pool = mp; 3476631Svbart@nginx.com reopen->access_log = access_log; 3477631Svbart@nginx.com 3478631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3479631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3480631Svbart@nginx.com goto fail; 3481631Svbart@nginx.com } 3482631Svbart@nginx.com 3483651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3484651Svbart@nginx.com 3485631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3486631Svbart@nginx.com *b->mem.free++ = '\0'; 3487631Svbart@nginx.com 3488631Svbart@nginx.com rt = task->thread->runtime; 3489631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3490631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3491631Svbart@nginx.com 3492631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3493631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3494631Svbart@nginx.com nxt_router_access_log_reopen_error, 3495631Svbart@nginx.com -1, reopen); 3496631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3497631Svbart@nginx.com goto fail; 3498631Svbart@nginx.com } 3499631Svbart@nginx.com 3500631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3501631Svbart@nginx.com stream, router_port->id, b); 3502631Svbart@nginx.com 3503631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3504631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3505631Svbart@nginx.com goto fail; 3506631Svbart@nginx.com } 3507631Svbart@nginx.com 3508651Svbart@nginx.com nxt_mp_retain(mp); 3509651Svbart@nginx.com 3510631Svbart@nginx.com return; 3511631Svbart@nginx.com 3512631Svbart@nginx.com fail: 3513631Svbart@nginx.com 3514631Svbart@nginx.com nxt_mp_destroy(mp); 3515631Svbart@nginx.com } 3516631Svbart@nginx.com 3517631Svbart@nginx.com 3518631Svbart@nginx.com static void 3519651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3520651Svbart@nginx.com { 3521651Svbart@nginx.com nxt_mp_t *mp; 3522651Svbart@nginx.com nxt_buf_t *b; 3523651Svbart@nginx.com 3524651Svbart@nginx.com b = obj; 3525651Svbart@nginx.com mp = b->data; 3526651Svbart@nginx.com 3527651Svbart@nginx.com nxt_mp_release(mp); 3528651Svbart@nginx.com } 3529651Svbart@nginx.com 3530651Svbart@nginx.com 3531651Svbart@nginx.com static void 3532631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3533631Svbart@nginx.com void *data) 3534631Svbart@nginx.com { 3535631Svbart@nginx.com nxt_router_access_log_t *access_log; 3536631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3537631Svbart@nginx.com 3538631Svbart@nginx.com reopen = data; 3539631Svbart@nginx.com 3540631Svbart@nginx.com access_log = reopen->access_log; 3541631Svbart@nginx.com 3542631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3543631Svbart@nginx.com 3544*1558Smax.romanov@nginx.com if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) { 3545631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3546*1558Smax.romanov@nginx.com msg->fd[0], access_log->fd, nxt_errno); 3547631Svbart@nginx.com } 3548631Svbart@nginx.com } 3549631Svbart@nginx.com 3550*1558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 3551651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3552631Svbart@nginx.com } 3553631Svbart@nginx.com 3554631Svbart@nginx.com 3555631Svbart@nginx.com static void 3556631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3557631Svbart@nginx.com void *data) 3558631Svbart@nginx.com { 3559631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3560631Svbart@nginx.com 3561631Svbart@nginx.com reopen = data; 3562631Svbart@nginx.com 3563651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3564631Svbart@nginx.com } 3565631Svbart@nginx.com 3566631Svbart@nginx.com 3567630Svbart@nginx.com static void 356853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 356953Sigor@sysoev.ru { 3570141Smax.romanov@nginx.com nxt_port_t *port; 357153Sigor@sysoev.ru nxt_thread_link_t *link; 357253Sigor@sysoev.ru nxt_event_engine_t *engine; 357353Sigor@sysoev.ru nxt_thread_handle_t handle; 357453Sigor@sysoev.ru 357558Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 357653Sigor@sysoev.ru link = data; 357753Sigor@sysoev.ru 357853Sigor@sysoev.ru nxt_thread_wait(handle); 357953Sigor@sysoev.ru 358053Sigor@sysoev.ru engine = link->engine; 358153Sigor@sysoev.ru 358253Sigor@sysoev.ru nxt_queue_remove(&engine->link); 358353Sigor@sysoev.ru 3584141Smax.romanov@nginx.com port = engine->port; 3585141Smax.romanov@nginx.com 3586141Smax.romanov@nginx.com // TODO notify all apps 3587141Smax.romanov@nginx.com 3588343Smax.romanov@nginx.com port->engine = task->thread->engine; 3589163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3590343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3591163Smax.romanov@nginx.com 3592163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 359363Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 359453Sigor@sysoev.ru 359553Sigor@sysoev.ru nxt_event_engine_free(engine); 359653Sigor@sysoev.ru 359753Sigor@sysoev.ru nxt_free(link); 359853Sigor@sysoev.ru } 359953Sigor@sysoev.ru 360053Sigor@sysoev.ru 360153Sigor@sysoev.ru static void 3602318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3603318Smax.romanov@nginx.com void *data) 360488Smax.romanov@nginx.com { 36051123Smax.romanov@nginx.com nxt_int_t ret; 36061547Smax.romanov@nginx.com nxt_app_t *app; 36071269Sigor@sysoev.ru nxt_buf_t *b, *next; 36081131Smax.romanov@nginx.com nxt_port_t *app_port; 36091123Smax.romanov@nginx.com nxt_unit_field_t *f; 36101123Smax.romanov@nginx.com nxt_http_field_t *field; 36111123Smax.romanov@nginx.com nxt_http_request_t *r; 36121123Smax.romanov@nginx.com nxt_unit_response_t *resp; 36131123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 361488Smax.romanov@nginx.com 36151123Smax.romanov@nginx.com req_rpc_data = data; 361688Smax.romanov@nginx.com 36171123Smax.romanov@nginx.com r = req_rpc_data->request; 36181007Salexander.borisov@nginx.com if (nxt_slow_path(r == NULL)) { 3619570Smax.romanov@nginx.com return; 3620570Smax.romanov@nginx.com } 3621425Smax.romanov@nginx.com 36221007Salexander.borisov@nginx.com if (r->error) { 36231123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3624608Sigor@sysoev.ru return; 3625608Sigor@sysoev.ru } 3626608Sigor@sysoev.ru 36271547Smax.romanov@nginx.com app = req_rpc_data->app; 36281547Smax.romanov@nginx.com nxt_assert(app != NULL); 36291547Smax.romanov@nginx.com 36301547Smax.romanov@nginx.com if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) { 36311547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(task, msg, req_rpc_data); 36321547Smax.romanov@nginx.com 36331547Smax.romanov@nginx.com return; 36341547Smax.romanov@nginx.com } 36351547Smax.romanov@nginx.com 36361547Smax.romanov@nginx.com b = (msg->size == 0) ? NULL : msg->buf; 36371547Smax.romanov@nginx.com 363888Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 363988Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 364088Smax.romanov@nginx.com 36411007Salexander.borisov@nginx.com nxt_buf_chain_add(&b, nxt_http_buf_last(r)); 3642167Smax.romanov@nginx.com 36431547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 36441547Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE; 36451547Smax.romanov@nginx.com 36461123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3647425Smax.romanov@nginx.com 3648425Smax.romanov@nginx.com } else { 36491547Smax.romanov@nginx.com if (app->timeout != 0) { 36501007Salexander.borisov@nginx.com r->timer.handler = nxt_router_app_timeout; 36511123Smax.romanov@nginx.com r->timer_data = req_rpc_data; 36521547Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, app->timeout); 3653425Smax.romanov@nginx.com } 365488Smax.romanov@nginx.com } 365588Smax.romanov@nginx.com 365688Smax.romanov@nginx.com if (b == NULL) { 365788Smax.romanov@nginx.com return; 365888Smax.romanov@nginx.com } 365988Smax.romanov@nginx.com 3660206Smax.romanov@nginx.com if (msg->buf == b) { 3661206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3662206Smax.romanov@nginx.com msg->buf = NULL; 3663206Smax.romanov@nginx.com } 3664194Smax.romanov@nginx.com 3665431Sigor@sysoev.ru if (r->header_sent) { 3666431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3667431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3668277Sigor@sysoev.ru 366988Smax.romanov@nginx.com } else { 3670743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3671743Smax.romanov@nginx.com 3672743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3673743Smax.romanov@nginx.com goto fail; 3674743Smax.romanov@nginx.com } 3675743Smax.romanov@nginx.com 3676743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3677743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3678743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3679743Smax.romanov@nginx.com goto fail; 3680743Smax.romanov@nginx.com } 3681743Smax.romanov@nginx.com 36821126Smax.romanov@nginx.com field = NULL; 36831126Smax.romanov@nginx.com 3684743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 36851126Smax.romanov@nginx.com if (f->skip) { 36861126Smax.romanov@nginx.com continue; 36871126Smax.romanov@nginx.com } 36881126Smax.romanov@nginx.com 36891007Salexander.borisov@nginx.com field = nxt_list_add(r->resp.fields); 3690743Smax.romanov@nginx.com 3691743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3692743Smax.romanov@nginx.com goto fail; 3693743Smax.romanov@nginx.com } 3694743Smax.romanov@nginx.com 3695743Smax.romanov@nginx.com field->hash = f->hash; 36961126Smax.romanov@nginx.com field->skip = 0; 36971270Sigor@sysoev.ru field->hopbyhop = 0; 3698743Smax.romanov@nginx.com 3699743Smax.romanov@nginx.com field->name_length = f->name_length; 3700743Smax.romanov@nginx.com field->value_length = f->value_length; 3701743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3702743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3703743Smax.romanov@nginx.com 37041126Smax.romanov@nginx.com ret = nxt_http_field_process(field, &nxt_response_fields_hash, r); 37051126Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 37061126Smax.romanov@nginx.com goto fail; 37071126Smax.romanov@nginx.com } 37081126Smax.romanov@nginx.com 37091126Smax.romanov@nginx.com nxt_debug(task, "header%s: %*s: %*s", 37101126Smax.romanov@nginx.com (field->skip ? " skipped" : ""), 3711743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3712743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 37131126Smax.romanov@nginx.com 37141126Smax.romanov@nginx.com if (field->skip) { 37151126Smax.romanov@nginx.com r->resp.fields->last->nelts--; 37161126Smax.romanov@nginx.com } 3717743Smax.romanov@nginx.com } 37181007Salexander.borisov@nginx.com 3719743Smax.romanov@nginx.com r->status = resp->status; 3720743Smax.romanov@nginx.com 3721743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3722743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3723743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3724743Smax.romanov@nginx.com 3725743Smax.romanov@nginx.com } else { 3726743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3727743Smax.romanov@nginx.com } 3728743Smax.romanov@nginx.com 3729435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 37301269Sigor@sysoev.ru next = b->next; 37311269Sigor@sysoev.ru b->next = NULL; 37321269Sigor@sysoev.ru 3733435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3734435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3735507Smax.romanov@nginx.com 37361269Sigor@sysoev.ru b = next; 3737520Smax.romanov@nginx.com } 3738520Smax.romanov@nginx.com 3739520Smax.romanov@nginx.com if (b != NULL) { 3740431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3741431Sigor@sysoev.ru } 3742431Sigor@sysoev.ru 37431270Sigor@sysoev.ru nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL); 37441127Smax.romanov@nginx.com 37451131Smax.romanov@nginx.com if (r->websocket_handshake 37461131Smax.romanov@nginx.com && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) 37471131Smax.romanov@nginx.com { 37481547Smax.romanov@nginx.com app_port = req_rpc_data->app_port; 37491131Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 37501131Smax.romanov@nginx.com goto fail; 37511131Smax.romanov@nginx.com } 37521131Smax.romanov@nginx.com 37531547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 37541547Smax.romanov@nginx.com 37551547Smax.romanov@nginx.com app_port->main_app_port->active_websockets++; 37561547Smax.romanov@nginx.com 37571547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 37581131Smax.romanov@nginx.com 37591131Smax.romanov@nginx.com nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE); 37601547Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_CLOSE; 37611547Smax.romanov@nginx.com 37621547Smax.romanov@nginx.com nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream); 37631131Smax.romanov@nginx.com 37641131Smax.romanov@nginx.com r->state = &nxt_http_websocket; 37651131Smax.romanov@nginx.com 37661131Smax.romanov@nginx.com } else { 37671131Smax.romanov@nginx.com r->state = &nxt_http_request_send_state; 37681131Smax.romanov@nginx.com } 3769431Sigor@sysoev.ru } 3770431Sigor@sysoev.ru 3771431Sigor@sysoev.ru return; 3772431Sigor@sysoev.ru 3773431Sigor@sysoev.ru fail: 3774431Sigor@sysoev.ru 3775615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3776615Smax.romanov@nginx.com 37771123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3778431Sigor@sysoev.ru } 3779431Sigor@sysoev.ru 3780431Sigor@sysoev.ru 37811547Smax.romanov@nginx.com static void 37821547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(nxt_task_t *task, 37831547Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data) 37841547Smax.romanov@nginx.com { 37851555Smax.romanov@nginx.com int res; 37861547Smax.romanov@nginx.com nxt_app_t *app; 37871547Smax.romanov@nginx.com nxt_bool_t start_process; 37881547Smax.romanov@nginx.com nxt_port_t *app_port, *main_app_port, *idle_port; 37891547Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 37901547Smax.romanov@nginx.com nxt_http_request_t *r; 37911547Smax.romanov@nginx.com 37921547Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: got ack from %PI:%d", 37931547Smax.romanov@nginx.com req_rpc_data->stream, 37941547Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 37951547Smax.romanov@nginx.com 37961547Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data, 37971547Smax.romanov@nginx.com msg->port_msg.pid); 37981547Smax.romanov@nginx.com 37991547Smax.romanov@nginx.com app = req_rpc_data->app; 38001547Smax.romanov@nginx.com 38011547Smax.romanov@nginx.com start_process = 0; 38021547Smax.romanov@nginx.com 38031547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 38041547Smax.romanov@nginx.com 38051547Smax.romanov@nginx.com app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid, 38061547Smax.romanov@nginx.com msg->port_msg.reply_port); 38071547Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 38081547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 38091547Smax.romanov@nginx.com 38101547Smax.romanov@nginx.com r = req_rpc_data->request; 38111547Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 38121547Smax.romanov@nginx.com 38131547Smax.romanov@nginx.com return; 38141547Smax.romanov@nginx.com } 38151547Smax.romanov@nginx.com 38161547Smax.romanov@nginx.com main_app_port = app_port->main_app_port; 38171547Smax.romanov@nginx.com 38181547Smax.romanov@nginx.com if (nxt_queue_chk_remove(&main_app_port->idle_link)) { 38191547Smax.romanov@nginx.com app->idle_processes--; 38201547Smax.romanov@nginx.com 38211549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)", 38221549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id, 38231549Smax.romanov@nginx.com (main_app_port->idle_start ? "idle_ports" : "spare_ports")); 38241549Smax.romanov@nginx.com 38251547Smax.romanov@nginx.com /* Check port was in 'spare_ports' using idle_start field. */ 38261547Smax.romanov@nginx.com if (main_app_port->idle_start == 0 38271547Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 38281547Smax.romanov@nginx.com { 38291547Smax.romanov@nginx.com /* 38301547Smax.romanov@nginx.com * If there is a vacant space in spare ports, 38311547Smax.romanov@nginx.com * move the last idle to spare_ports. 38321547Smax.romanov@nginx.com */ 38331547Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 38341547Smax.romanov@nginx.com 38351547Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 38361547Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 38371547Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 38381547Smax.romanov@nginx.com 38391547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 38401547Smax.romanov@nginx.com 38411547Smax.romanov@nginx.com idle_port->idle_start = 0; 38421549Smax.romanov@nginx.com 38431549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " 38441549Smax.romanov@nginx.com "to spare_ports", 38451549Smax.romanov@nginx.com &app->name, idle_port->pid, idle_port->id); 38461547Smax.romanov@nginx.com } 38471547Smax.romanov@nginx.com 38481547Smax.romanov@nginx.com if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { 38491547Smax.romanov@nginx.com app->pending_processes++; 38501547Smax.romanov@nginx.com start_process = 1; 38511547Smax.romanov@nginx.com } 38521547Smax.romanov@nginx.com } 38531547Smax.romanov@nginx.com 38541547Smax.romanov@nginx.com main_app_port->active_requests++; 38551547Smax.romanov@nginx.com 38561547Smax.romanov@nginx.com nxt_port_inc_use(app_port); 38571547Smax.romanov@nginx.com 38581547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 38591547Smax.romanov@nginx.com 38601547Smax.romanov@nginx.com if (start_process) { 38611547Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 38621547Smax.romanov@nginx.com } 38631547Smax.romanov@nginx.com 38641547Smax.romanov@nginx.com nxt_port_use(task, req_rpc_data->app_port, -1); 38651547Smax.romanov@nginx.com 38661547Smax.romanov@nginx.com req_rpc_data->app_port = app_port; 38671547Smax.romanov@nginx.com 38681555Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1) { 38691555Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream, 38701555Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd); 38711555Smax.romanov@nginx.com 38721555Smax.romanov@nginx.com lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET); 38731555Smax.romanov@nginx.com 38741555Smax.romanov@nginx.com res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY, 38751555Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd, 38761555Smax.romanov@nginx.com req_rpc_data->stream, 38771555Smax.romanov@nginx.com task->thread->engine->port->id, NULL); 38781555Smax.romanov@nginx.com 38791555Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 38801555Smax.romanov@nginx.com r = req_rpc_data->request; 38811555Smax.romanov@nginx.com 38821555Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 38831555Smax.romanov@nginx.com } 38841555Smax.romanov@nginx.com } 38851555Smax.romanov@nginx.com 38861547Smax.romanov@nginx.com if (app->timeout != 0) { 38871547Smax.romanov@nginx.com r = req_rpc_data->request; 38881547Smax.romanov@nginx.com 38891547Smax.romanov@nginx.com r->timer.handler = nxt_router_app_timeout; 38901547Smax.romanov@nginx.com r->timer_data = req_rpc_data; 38911547Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, app->timeout); 38921547Smax.romanov@nginx.com } 38931547Smax.romanov@nginx.com } 38941547Smax.romanov@nginx.com 38951547Smax.romanov@nginx.com 3896431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3897431Sigor@sysoev.ru nxt_aligned(64) = 3898431Sigor@sysoev.ru { 3899943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 3900431Sigor@sysoev.ru }; 3901431Sigor@sysoev.ru 3902431Sigor@sysoev.ru 3903431Sigor@sysoev.ru static void 3904431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3905431Sigor@sysoev.ru { 3906431Sigor@sysoev.ru nxt_buf_t *out; 3907431Sigor@sysoev.ru nxt_http_request_t *r; 3908431Sigor@sysoev.ru 3909431Sigor@sysoev.ru r = obj; 3910431Sigor@sysoev.ru 3911431Sigor@sysoev.ru out = r->out; 3912431Sigor@sysoev.ru 3913431Sigor@sysoev.ru if (out != NULL) { 3914431Sigor@sysoev.ru r->out = NULL; 3915431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 391688Smax.romanov@nginx.com } 391788Smax.romanov@nginx.com } 391888Smax.romanov@nginx.com 3919277Sigor@sysoev.ru 3920318Smax.romanov@nginx.com static void 3921318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3922318Smax.romanov@nginx.com void *data) 3923318Smax.romanov@nginx.com { 39241123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 39251123Smax.romanov@nginx.com 39261123Smax.romanov@nginx.com req_rpc_data = data; 39271123Smax.romanov@nginx.com 39281547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 39291547Smax.romanov@nginx.com 39301547Smax.romanov@nginx.com /* TODO cancel message and return if cancelled. */ 39311547Smax.romanov@nginx.com // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream); 3932425Smax.romanov@nginx.com 39331123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 39341123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 3935616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3936616Smax.romanov@nginx.com } 3937318Smax.romanov@nginx.com 39381123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3939318Smax.romanov@nginx.com } 3940318Smax.romanov@nginx.com 3941318Smax.romanov@nginx.com 3942141Smax.romanov@nginx.com static void 3943343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3944343Smax.romanov@nginx.com void *data) 3945192Smax.romanov@nginx.com { 3946753Smax.romanov@nginx.com nxt_app_t *app; 3947753Smax.romanov@nginx.com nxt_port_t *port; 3948753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3949753Smax.romanov@nginx.com 3950753Smax.romanov@nginx.com app_joint = data; 3951347Smax.romanov@nginx.com port = msg->u.new_port; 3952343Smax.romanov@nginx.com 3953753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3954343Smax.romanov@nginx.com nxt_assert(port != NULL); 39551547Smax.romanov@nginx.com nxt_assert(port->type == NXT_PROCESS_APP); 39561547Smax.romanov@nginx.com nxt_assert(port->id == 0); 3957343Smax.romanov@nginx.com 3958753Smax.romanov@nginx.com app = app_joint->app; 3959753Smax.romanov@nginx.com 3960753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3961753Smax.romanov@nginx.com 3962753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3963753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3964753Smax.romanov@nginx.com 3965753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3966753Smax.romanov@nginx.com 3967753Smax.romanov@nginx.com return; 3968753Smax.romanov@nginx.com } 3969753Smax.romanov@nginx.com 3970343Smax.romanov@nginx.com port->app = app; 39711547Smax.romanov@nginx.com port->main_app_port = port; 3972343Smax.romanov@nginx.com 3973343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3974343Smax.romanov@nginx.com 3975507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3976507Smax.romanov@nginx.com 3977507Smax.romanov@nginx.com app->pending_processes--; 3978507Smax.romanov@nginx.com app->processes++; 39791547Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 39801547Smax.romanov@nginx.com app->port_hash_count++; 3981343Smax.romanov@nginx.com 3982343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3983343Smax.romanov@nginx.com 3984507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3985507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3986343Smax.romanov@nginx.com 39871547Smax.romanov@nginx.com nxt_router_app_shared_port_send(task, port); 39881547Smax.romanov@nginx.com 39891123Smax.romanov@nginx.com nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT); 3990192Smax.romanov@nginx.com } 3991192Smax.romanov@nginx.com 3992192Smax.romanov@nginx.com 39931547Smax.romanov@nginx.com static nxt_int_t 39941547Smax.romanov@nginx.com nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port) 39951547Smax.romanov@nginx.com { 39961547Smax.romanov@nginx.com nxt_buf_t *b; 39971547Smax.romanov@nginx.com nxt_port_t *port; 39981547Smax.romanov@nginx.com nxt_port_msg_new_port_t *msg; 39991547Smax.romanov@nginx.com 40001547Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 40011547Smax.romanov@nginx.com sizeof(nxt_port_data_t)); 40021547Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 40031547Smax.romanov@nginx.com return NXT_ERROR; 40041547Smax.romanov@nginx.com } 40051547Smax.romanov@nginx.com 40061547Smax.romanov@nginx.com port = app_port->app->shared_port; 40071547Smax.romanov@nginx.com 40081547Smax.romanov@nginx.com nxt_debug(task, "send port %FD to process %PI", 40091547Smax.romanov@nginx.com port->pair[0], app_port->pid); 40101547Smax.romanov@nginx.com 40111547Smax.romanov@nginx.com b->mem.free += sizeof(nxt_port_msg_new_port_t); 40121547Smax.romanov@nginx.com msg = (nxt_port_msg_new_port_t *) b->mem.pos; 40131547Smax.romanov@nginx.com 40141547Smax.romanov@nginx.com msg->id = port->id; 40151547Smax.romanov@nginx.com msg->pid = port->pid; 40161547Smax.romanov@nginx.com msg->max_size = port->max_size; 40171547Smax.romanov@nginx.com msg->max_share = port->max_share; 40181547Smax.romanov@nginx.com msg->type = port->type; 40191547Smax.romanov@nginx.com 40201555Smax.romanov@nginx.com return nxt_port_socket_write2(task, app_port, 40211547Smax.romanov@nginx.com NXT_PORT_MSG_NEW_PORT, 40221555Smax.romanov@nginx.com port->pair[0], port->queue_fd, 40231555Smax.romanov@nginx.com 0, 0, b); 40241547Smax.romanov@nginx.com } 40251547Smax.romanov@nginx.com 40261547Smax.romanov@nginx.com 4027192Smax.romanov@nginx.com static void 4028343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4029343Smax.romanov@nginx.com void *data) 4030192Smax.romanov@nginx.com { 40311547Smax.romanov@nginx.com nxt_app_t *app; 40321547Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4033343Smax.romanov@nginx.com 4034753Smax.romanov@nginx.com app_joint = data; 4035753Smax.romanov@nginx.com 4036753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 4037753Smax.romanov@nginx.com 4038753Smax.romanov@nginx.com app = app_joint->app; 4039753Smax.romanov@nginx.com 4040753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4041753Smax.romanov@nginx.com 4042753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 4043753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 4044753Smax.romanov@nginx.com 4045753Smax.romanov@nginx.com return; 4046753Smax.romanov@nginx.com } 4047343Smax.romanov@nginx.com 4048343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 4049343Smax.romanov@nginx.com 4050343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4051343Smax.romanov@nginx.com 4052507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 4053507Smax.romanov@nginx.com 4054507Smax.romanov@nginx.com app->pending_processes--; 4055318Smax.romanov@nginx.com 4056343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4057343Smax.romanov@nginx.com 40581547Smax.romanov@nginx.com /* TODO req_app_link to cancel first pending message */ 4059192Smax.romanov@nginx.com } 4060192Smax.romanov@nginx.com 4061192Smax.romanov@nginx.com 4062343Smax.romanov@nginx.com void 4063343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 4064141Smax.romanov@nginx.com { 4065343Smax.romanov@nginx.com int c; 4066343Smax.romanov@nginx.com 4067343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 4068343Smax.romanov@nginx.com 4069343Smax.romanov@nginx.com if (i < 0 && c == -i) { 4070343Smax.romanov@nginx.com 4071753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 4072753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 4073753Smax.romanov@nginx.com 4074753Smax.romanov@nginx.com } else { 4075753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 4076753Smax.romanov@nginx.com } 4077163Smax.romanov@nginx.com } 4078343Smax.romanov@nginx.com } 4079343Smax.romanov@nginx.com 4080343Smax.romanov@nginx.com 4081507Smax.romanov@nginx.com nxt_inline nxt_port_t * 40821549Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app) 4083141Smax.romanov@nginx.com { 4084343Smax.romanov@nginx.com nxt_port_t *port; 4085141Smax.romanov@nginx.com 4086141Smax.romanov@nginx.com port = NULL; 4087141Smax.romanov@nginx.com 4088141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4089141Smax.romanov@nginx.com 4090343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 4091343Smax.romanov@nginx.com 4092507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 4093507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4094507Smax.romanov@nginx.com 4095507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4096507Smax.romanov@nginx.com app->idle_processes--; 40971549Smax.romanov@nginx.com 40981549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit", 40991549Smax.romanov@nginx.com &app->name, port->pid, port->id, 41001549Smax.romanov@nginx.com (port->idle_start ? "idle_ports" : "spare_ports")); 4101507Smax.romanov@nginx.com } 4102507Smax.romanov@nginx.com 41031547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 41041547Smax.romanov@nginx.com app->port_hash_count--; 41051547Smax.romanov@nginx.com 4106507Smax.romanov@nginx.com port->app = NULL; 4107507Smax.romanov@nginx.com app->processes--; 4108343Smax.romanov@nginx.com 4109343Smax.romanov@nginx.com break; 4110343Smax.romanov@nginx.com 4111343Smax.romanov@nginx.com } nxt_queue_loop; 4112141Smax.romanov@nginx.com 4113141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4114141Smax.romanov@nginx.com 4115141Smax.romanov@nginx.com return port; 4116141Smax.romanov@nginx.com } 4117141Smax.romanov@nginx.com 4118141Smax.romanov@nginx.com 4119141Smax.romanov@nginx.com static void 4120753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 4121507Smax.romanov@nginx.com { 4122753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 4123507Smax.romanov@nginx.com 4124507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 4125507Smax.romanov@nginx.com 4126753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4127507Smax.romanov@nginx.com } 4128507Smax.romanov@nginx.com 4129507Smax.romanov@nginx.com 4130507Smax.romanov@nginx.com static void 4131343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 41321123Smax.romanov@nginx.com nxt_apr_action_t action) 4133343Smax.romanov@nginx.com { 41341547Smax.romanov@nginx.com int inc_use; 41351547Smax.romanov@nginx.com uint32_t got_response, dec_requests; 41361547Smax.romanov@nginx.com nxt_app_t *app; 41371547Smax.romanov@nginx.com nxt_bool_t port_unchained, send_quit, adjust_idle_timer; 41381547Smax.romanov@nginx.com nxt_port_t *main_app_port; 4139343Smax.romanov@nginx.com 4140343Smax.romanov@nginx.com nxt_assert(port != NULL); 4141343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 4142343Smax.romanov@nginx.com 4143343Smax.romanov@nginx.com app = port->app; 4144343Smax.romanov@nginx.com 41451123Smax.romanov@nginx.com inc_use = 0; 41461123Smax.romanov@nginx.com got_response = 0; 41471547Smax.romanov@nginx.com dec_requests = 0; 41481123Smax.romanov@nginx.com 41491123Smax.romanov@nginx.com switch (action) { 41501123Smax.romanov@nginx.com case NXT_APR_NEW_PORT: 41511123Smax.romanov@nginx.com break; 41521123Smax.romanov@nginx.com case NXT_APR_REQUEST_FAILED: 41531547Smax.romanov@nginx.com dec_requests = 1; 41541123Smax.romanov@nginx.com inc_use = -1; 41551123Smax.romanov@nginx.com break; 41561123Smax.romanov@nginx.com case NXT_APR_GOT_RESPONSE: 41571123Smax.romanov@nginx.com got_response = 1; 41581123Smax.romanov@nginx.com inc_use = -1; 41591123Smax.romanov@nginx.com break; 41601131Smax.romanov@nginx.com case NXT_APR_UPGRADE: 41611131Smax.romanov@nginx.com got_response = 1; 41621131Smax.romanov@nginx.com break; 41631123Smax.romanov@nginx.com case NXT_APR_CLOSE: 41641123Smax.romanov@nginx.com inc_use = -1; 41651123Smax.romanov@nginx.com break; 41661123Smax.romanov@nginx.com } 41671123Smax.romanov@nginx.com 41681547Smax.romanov@nginx.com nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name, 41691547Smax.romanov@nginx.com port->pid, port->id, 41701547Smax.romanov@nginx.com (int) inc_use, (int) got_response); 41711547Smax.romanov@nginx.com 41721547Smax.romanov@nginx.com if (port == app->shared_port) { 41731547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 41741547Smax.romanov@nginx.com 41751547Smax.romanov@nginx.com app->active_requests -= got_response + dec_requests; 41761547Smax.romanov@nginx.com 41771547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 41781547Smax.romanov@nginx.com 41791547Smax.romanov@nginx.com goto adjust_use; 41801547Smax.romanov@nginx.com } 41811547Smax.romanov@nginx.com 41821547Smax.romanov@nginx.com main_app_port = port->main_app_port; 41831547Smax.romanov@nginx.com 4184343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4185343Smax.romanov@nginx.com 41861547Smax.romanov@nginx.com main_app_port->app_responses += got_response; 41871547Smax.romanov@nginx.com main_app_port->active_requests -= got_response + dec_requests; 41881547Smax.romanov@nginx.com app->active_requests -= got_response + dec_requests; 41891547Smax.romanov@nginx.com 41901547Smax.romanov@nginx.com if (main_app_port->pair[1] != -1 4191428Smax.romanov@nginx.com && (app->max_requests == 0 41921547Smax.romanov@nginx.com || main_app_port->app_responses < app->max_requests)) 4193425Smax.romanov@nginx.com { 41941547Smax.romanov@nginx.com if (main_app_port->app_link.next == NULL) { 41951547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &main_app_port->app_link); 41961547Smax.romanov@nginx.com 41971547Smax.romanov@nginx.com nxt_port_inc_use(main_app_port); 4198427Smax.romanov@nginx.com } 4199427Smax.romanov@nginx.com } 4200427Smax.romanov@nginx.com 4201753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 42021547Smax.romanov@nginx.com && main_app_port->app_responses >= app->max_requests); 4203367Smax.romanov@nginx.com 4204507Smax.romanov@nginx.com if (send_quit) { 42051547Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&main_app_port->app_link); 42061547Smax.romanov@nginx.com 42071547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, main_app_port); 42081547Smax.romanov@nginx.com app->port_hash_count--; 42091547Smax.romanov@nginx.com 42101547Smax.romanov@nginx.com main_app_port->app = NULL; 4211507Smax.romanov@nginx.com app->processes--; 4212507Smax.romanov@nginx.com 4213507Smax.romanov@nginx.com } else { 4214507Smax.romanov@nginx.com port_unchained = 0; 4215507Smax.romanov@nginx.com } 4216507Smax.romanov@nginx.com 4217507Smax.romanov@nginx.com adjust_idle_timer = 0; 4218507Smax.romanov@nginx.com 42191547Smax.romanov@nginx.com if (main_app_port->pair[1] != -1 && !send_quit 42201547Smax.romanov@nginx.com && main_app_port->active_requests == 0 42211547Smax.romanov@nginx.com && main_app_port->active_websockets == 0 42221547Smax.romanov@nginx.com && main_app_port->idle_link.next == NULL) 42231131Smax.romanov@nginx.com { 4224507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 4225507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 4226507Smax.romanov@nginx.com { 4227507Smax.romanov@nginx.com adjust_idle_timer = 1; 4228507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 4229507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 4230507Smax.romanov@nginx.com } 4231507Smax.romanov@nginx.com 4232507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 42331547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link); 4234507Smax.romanov@nginx.com 42351549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d to spare_ports", 42361549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id); 4237507Smax.romanov@nginx.com } else { 42381547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link); 42391547Smax.romanov@nginx.com 42401547Smax.romanov@nginx.com main_app_port->idle_start = task->thread->engine->timers.now; 42411549Smax.romanov@nginx.com 42421549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d to idle_ports", 42431549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id); 4244507Smax.romanov@nginx.com } 4245507Smax.romanov@nginx.com 4246507Smax.romanov@nginx.com app->idle_processes++; 4247507Smax.romanov@nginx.com } 4248507Smax.romanov@nginx.com 4249343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4250343Smax.romanov@nginx.com 4251507Smax.romanov@nginx.com if (adjust_idle_timer) { 4252507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4253507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4254507Smax.romanov@nginx.com } 4255507Smax.romanov@nginx.com 4256343Smax.romanov@nginx.com /* ? */ 42571547Smax.romanov@nginx.com if (main_app_port->pair[1] == -1) { 4258343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 42591547Smax.romanov@nginx.com &app->name, app, main_app_port, main_app_port->pid); 4260343Smax.romanov@nginx.com 4261343Smax.romanov@nginx.com goto adjust_use; 4262163Smax.romanov@nginx.com } 4263163Smax.romanov@nginx.com 4264367Smax.romanov@nginx.com if (send_quit) { 42651547Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", &app->name, app); 42661547Smax.romanov@nginx.com 42671547Smax.romanov@nginx.com nxt_port_socket_write(task, main_app_port, NXT_PORT_MSG_QUIT, -1, 0, 0, 42681547Smax.romanov@nginx.com NULL); 4269163Smax.romanov@nginx.com 4270507Smax.romanov@nginx.com if (port_unchained) { 42711547Smax.romanov@nginx.com nxt_port_use(task, main_app_port, -1); 4272507Smax.romanov@nginx.com } 4273507Smax.romanov@nginx.com 4274343Smax.romanov@nginx.com goto adjust_use; 4275163Smax.romanov@nginx.com } 4276163Smax.romanov@nginx.com 4277167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4278167Smax.romanov@nginx.com &app->name, app); 4279141Smax.romanov@nginx.com 4280343Smax.romanov@nginx.com adjust_use: 4281343Smax.romanov@nginx.com 42821123Smax.romanov@nginx.com nxt_port_use(task, port, inc_use); 4283141Smax.romanov@nginx.com } 4284141Smax.romanov@nginx.com 4285141Smax.romanov@nginx.com 4286343Smax.romanov@nginx.com void 4287343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4288141Smax.romanov@nginx.com { 4289507Smax.romanov@nginx.com nxt_app_t *app; 4290507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4291507Smax.romanov@nginx.com nxt_port_t *idle_port; 4292507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4293141Smax.romanov@nginx.com 4294141Smax.romanov@nginx.com app = port->app; 4295343Smax.romanov@nginx.com 4296343Smax.romanov@nginx.com nxt_assert(app != NULL); 4297141Smax.romanov@nginx.com 4298141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4299141Smax.romanov@nginx.com 43001547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 43011547Smax.romanov@nginx.com app->port_hash_count--; 43021547Smax.romanov@nginx.com 43031547Smax.romanov@nginx.com if (port->id != 0) { 43041547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 43051547Smax.romanov@nginx.com 43061547Smax.romanov@nginx.com nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name, 43071547Smax.romanov@nginx.com port->pid, port->id); 43081547Smax.romanov@nginx.com 43091547Smax.romanov@nginx.com return; 43101547Smax.romanov@nginx.com } 43111547Smax.romanov@nginx.com 4312507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4313507Smax.romanov@nginx.com 4314507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4315507Smax.romanov@nginx.com app->idle_processes--; 4316507Smax.romanov@nginx.com 43171549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s before close", 43181549Smax.romanov@nginx.com &app->name, port->pid, port->id, 43191549Smax.romanov@nginx.com (port->idle_start ? "idle_ports" : "spare_ports")); 43201549Smax.romanov@nginx.com 4321507Smax.romanov@nginx.com if (port->idle_start == 0 4322507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4323507Smax.romanov@nginx.com { 4324507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4325507Smax.romanov@nginx.com 4326507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4327507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4328507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4329507Smax.romanov@nginx.com 4330507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4331507Smax.romanov@nginx.com 4332507Smax.romanov@nginx.com idle_port->idle_start = 0; 43331549Smax.romanov@nginx.com 43341549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " 43351549Smax.romanov@nginx.com "to spare_ports", 43361549Smax.romanov@nginx.com &app->name, idle_port->pid, idle_port->id); 4337507Smax.romanov@nginx.com } 4338343Smax.romanov@nginx.com } 4339343Smax.romanov@nginx.com 4340507Smax.romanov@nginx.com app->processes--; 4341507Smax.romanov@nginx.com 4342753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4343507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 43441547Smax.romanov@nginx.com && nxt_router_app_need_start(app); 4345507Smax.romanov@nginx.com 4346507Smax.romanov@nginx.com if (start_process) { 4347507Smax.romanov@nginx.com app->pending_processes++; 4348163Smax.romanov@nginx.com } 4349141Smax.romanov@nginx.com 4350141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4351163Smax.romanov@nginx.com 4352507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4353343Smax.romanov@nginx.com 4354343Smax.romanov@nginx.com if (unchain) { 4355343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4356163Smax.romanov@nginx.com } 4357163Smax.romanov@nginx.com 4358507Smax.romanov@nginx.com if (start_process) { 4359507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4360507Smax.romanov@nginx.com } 4361507Smax.romanov@nginx.com } 4362507Smax.romanov@nginx.com 4363507Smax.romanov@nginx.com 4364507Smax.romanov@nginx.com static void 4365507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4366507Smax.romanov@nginx.com { 4367507Smax.romanov@nginx.com nxt_app_t *app; 4368507Smax.romanov@nginx.com nxt_bool_t queued; 4369507Smax.romanov@nginx.com nxt_port_t *port; 4370507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4371507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4372507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4373507Smax.romanov@nginx.com 4374507Smax.romanov@nginx.com app = obj; 4375507Smax.romanov@nginx.com queued = (data == app); 4376507Smax.romanov@nginx.com 4377507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4378507Smax.romanov@nginx.com &app->name, queued); 4379507Smax.romanov@nginx.com 4380507Smax.romanov@nginx.com engine = task->thread->engine; 4381507Smax.romanov@nginx.com 4382507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 4383507Smax.romanov@nginx.com 4384811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 4385507Smax.romanov@nginx.com timeout = 0; 4386507Smax.romanov@nginx.com 4387507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4388507Smax.romanov@nginx.com 4389507Smax.romanov@nginx.com if (queued) { 4390507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 4391343Smax.romanov@nginx.com } 4392507Smax.romanov@nginx.com 43931547Smax.romanov@nginx.com nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d", 43941547Smax.romanov@nginx.com &app->name, 43951547Smax.romanov@nginx.com (int) app->idle_processes, (int) app->spare_processes); 43961547Smax.romanov@nginx.com 4397507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 4398507Smax.romanov@nginx.com 4399551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4400507Smax.romanov@nginx.com 4401507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 4402507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 4403507Smax.romanov@nginx.com 4404507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 4405507Smax.romanov@nginx.com 44061547Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M", 44071547Smax.romanov@nginx.com &app->name, port->pid, 44081547Smax.romanov@nginx.com port->idle_start, timeout, threshold); 44091547Smax.romanov@nginx.com 4410507Smax.romanov@nginx.com if (timeout > threshold) { 4411507Smax.romanov@nginx.com break; 4412507Smax.romanov@nginx.com } 4413507Smax.romanov@nginx.com 4414507Smax.romanov@nginx.com nxt_queue_remove(lnk); 4415507Smax.romanov@nginx.com lnk->next = NULL; 4416507Smax.romanov@nginx.com 44171549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)", 44181549Smax.romanov@nginx.com &app->name, port->pid, port->id); 44191549Smax.romanov@nginx.com 4420507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4421507Smax.romanov@nginx.com 44221547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 44231547Smax.romanov@nginx.com app->port_hash_count--; 44241547Smax.romanov@nginx.com 4425507Smax.romanov@nginx.com app->idle_processes--; 4426507Smax.romanov@nginx.com app->processes--; 4427507Smax.romanov@nginx.com port->app = NULL; 4428507Smax.romanov@nginx.com 4429507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4430507Smax.romanov@nginx.com 4431507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4432507Smax.romanov@nginx.com &app->name, port->pid); 4433507Smax.romanov@nginx.com 4434507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4435507Smax.romanov@nginx.com 4436507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4437507Smax.romanov@nginx.com 4438507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4439507Smax.romanov@nginx.com } 4440507Smax.romanov@nginx.com 4441507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4442507Smax.romanov@nginx.com 4443507Smax.romanov@nginx.com if (timeout > threshold) { 4444753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4445507Smax.romanov@nginx.com 4446507Smax.romanov@nginx.com } else { 4447753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4448507Smax.romanov@nginx.com } 4449507Smax.romanov@nginx.com 4450507Smax.romanov@nginx.com if (queued) { 4451507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4452507Smax.romanov@nginx.com } 4453507Smax.romanov@nginx.com } 4454507Smax.romanov@nginx.com 4455507Smax.romanov@nginx.com 4456507Smax.romanov@nginx.com static void 4457507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4458507Smax.romanov@nginx.com { 4459753Smax.romanov@nginx.com nxt_timer_t *timer; 4460753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4461507Smax.romanov@nginx.com 4462507Smax.romanov@nginx.com timer = obj; 4463753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4464753Smax.romanov@nginx.com 4465753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4466753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4467753Smax.romanov@nginx.com } 4468753Smax.romanov@nginx.com } 4469753Smax.romanov@nginx.com 4470753Smax.romanov@nginx.com 4471753Smax.romanov@nginx.com static void 4472753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4473753Smax.romanov@nginx.com { 4474753Smax.romanov@nginx.com nxt_timer_t *timer; 4475753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4476753Smax.romanov@nginx.com 4477753Smax.romanov@nginx.com timer = obj; 4478753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4479753Smax.romanov@nginx.com 4480753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4481507Smax.romanov@nginx.com } 4482507Smax.romanov@nginx.com 4483507Smax.romanov@nginx.com 4484507Smax.romanov@nginx.com static void 4485753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4486507Smax.romanov@nginx.com { 4487753Smax.romanov@nginx.com nxt_app_t *app; 4488753Smax.romanov@nginx.com nxt_port_t *port; 4489753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4490753Smax.romanov@nginx.com 4491753Smax.romanov@nginx.com app_joint = obj; 4492753Smax.romanov@nginx.com app = app_joint->app; 4493753Smax.romanov@nginx.com 4494753Smax.romanov@nginx.com for ( ;; ) { 44951549Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(task, app); 4496753Smax.romanov@nginx.com if (port == NULL) { 4497753Smax.romanov@nginx.com break; 4498753Smax.romanov@nginx.com } 4499753Smax.romanov@nginx.com 4500753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4501753Smax.romanov@nginx.com 4502753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4503753Smax.romanov@nginx.com 4504753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4505753Smax.romanov@nginx.com } 4506753Smax.romanov@nginx.com 4507753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 45081547Smax.romanov@nginx.com nxt_assert(app->active_requests == 0); 45091547Smax.romanov@nginx.com nxt_assert(app->port_hash_count == 0); 4510753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4511753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4512753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4513753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4514753Smax.romanov@nginx.com 45151547Smax.romanov@nginx.com nxt_port_mmaps_destroy(&app->outgoing, 1); 45161547Smax.romanov@nginx.com 45171547Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->outgoing.mutex); 45181547Smax.romanov@nginx.com 45191547Smax.romanov@nginx.com if (app->shared_port != NULL) { 45201547Smax.romanov@nginx.com app->shared_port->app = NULL; 45211547Smax.romanov@nginx.com nxt_port_close(task, app->shared_port); 45221547Smax.romanov@nginx.com nxt_port_use(task, app->shared_port, -1); 45231547Smax.romanov@nginx.com } 45241547Smax.romanov@nginx.com 4525753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 45261473Svbart@nginx.com nxt_mp_destroy(app->mem_pool); 4527753Smax.romanov@nginx.com 4528753Smax.romanov@nginx.com app_joint->app = NULL; 4529753Smax.romanov@nginx.com 4530753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4531753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4532753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4533753Smax.romanov@nginx.com 4534753Smax.romanov@nginx.com } else { 4535753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4536753Smax.romanov@nginx.com } 4537141Smax.romanov@nginx.com } 4538141Smax.romanov@nginx.com 4539141Smax.romanov@nginx.com 4540427Smax.romanov@nginx.com static void 45411547Smax.romanov@nginx.com nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, 45421547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 4543141Smax.romanov@nginx.com { 45441547Smax.romanov@nginx.com nxt_bool_t start_process; 45451547Smax.romanov@nginx.com nxt_port_t *port; 45461547Smax.romanov@nginx.com 45471547Smax.romanov@nginx.com start_process = 0; 4548427Smax.romanov@nginx.com 4549427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4550427Smax.romanov@nginx.com 45511547Smax.romanov@nginx.com port = app->shared_port; 45521547Smax.romanov@nginx.com nxt_port_inc_use(port); 45531547Smax.romanov@nginx.com 45541547Smax.romanov@nginx.com app->active_requests++; 45551547Smax.romanov@nginx.com 45561547Smax.romanov@nginx.com if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { 45571547Smax.romanov@nginx.com app->pending_processes++; 45581547Smax.romanov@nginx.com start_process = 1; 45591547Smax.romanov@nginx.com } 4560427Smax.romanov@nginx.com 4561427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4562427Smax.romanov@nginx.com 45631547Smax.romanov@nginx.com req_rpc_data->app_port = port; 45641547Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED; 45651547Smax.romanov@nginx.com 45661547Smax.romanov@nginx.com if (start_process) { 45671547Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 45681547Smax.romanov@nginx.com } 4569427Smax.romanov@nginx.com } 4570427Smax.romanov@nginx.com 4571427Smax.romanov@nginx.com 4572431Sigor@sysoev.ru void 45731007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, 4574964Sigor@sysoev.ru nxt_app_t *app) 457553Sigor@sysoev.ru { 45761123Smax.romanov@nginx.com nxt_event_engine_t *engine; 45771123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 4578431Sigor@sysoev.ru 457988Smax.romanov@nginx.com engine = task->thread->engine; 458088Smax.romanov@nginx.com 45811123Smax.romanov@nginx.com req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port, 4582318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4583318Smax.romanov@nginx.com nxt_router_response_error_handler, 45841123Smax.romanov@nginx.com sizeof(nxt_request_rpc_data_t)); 45851123Smax.romanov@nginx.com if (nxt_slow_path(req_rpc_data == NULL)) { 4586431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4587141Smax.romanov@nginx.com return; 458888Smax.romanov@nginx.com } 458988Smax.romanov@nginx.com 45901402Smax.romanov@nginx.com /* 45911402Smax.romanov@nginx.com * At this point we have request req_rpc_data allocated and registered 45921402Smax.romanov@nginx.com * in port handlers. Need to fixup request memory pool. Counterpart 45931402Smax.romanov@nginx.com * release will be called via following call chain: 45941402Smax.romanov@nginx.com * nxt_request_rpc_data_unlink() -> 45951547Smax.romanov@nginx.com * nxt_router_http_request_release_post() -> 45961402Smax.romanov@nginx.com * nxt_router_http_request_release() 45971402Smax.romanov@nginx.com */ 45981402Smax.romanov@nginx.com nxt_mp_retain(r->mem_pool); 45991402Smax.romanov@nginx.com 46001402Smax.romanov@nginx.com r->timer.task = &engine->task; 46011402Smax.romanov@nginx.com r->timer.work_queue = &engine->fast_work_queue; 46021402Smax.romanov@nginx.com r->timer.log = engine->task.log; 46031402Smax.romanov@nginx.com r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 46041402Smax.romanov@nginx.com 46051123Smax.romanov@nginx.com req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data); 46061123Smax.romanov@nginx.com req_rpc_data->app = app; 46071547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 46081547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 1; 4609425Smax.romanov@nginx.com 4610425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4611425Smax.romanov@nginx.com 46121123Smax.romanov@nginx.com req_rpc_data->request = r; 46131131Smax.romanov@nginx.com r->req_rpc_data = req_rpc_data; 46141123Smax.romanov@nginx.com 46151547Smax.romanov@nginx.com if (r->last != NULL) { 46161547Smax.romanov@nginx.com r->last->completion_handler = nxt_router_http_request_done; 46171547Smax.romanov@nginx.com } 46181547Smax.romanov@nginx.com 46191547Smax.romanov@nginx.com nxt_router_app_port_get(task, app, req_rpc_data); 46201547Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_rpc_data); 46211547Smax.romanov@nginx.com } 46221547Smax.romanov@nginx.com 46231547Smax.romanov@nginx.com 46241547Smax.romanov@nginx.com static void 46251547Smax.romanov@nginx.com nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data) 46261547Smax.romanov@nginx.com { 46271547Smax.romanov@nginx.com nxt_http_request_t *r; 46281547Smax.romanov@nginx.com 46291547Smax.romanov@nginx.com r = data; 46301547Smax.romanov@nginx.com 46311547Smax.romanov@nginx.com nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data); 46321547Smax.romanov@nginx.com 46331547Smax.romanov@nginx.com if (r->req_rpc_data) { 46341547Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, r->req_rpc_data); 46351547Smax.romanov@nginx.com } 46361547Smax.romanov@nginx.com 46371547Smax.romanov@nginx.com nxt_http_request_close_handler(task, r, r->proto.any); 4638167Smax.romanov@nginx.com } 4639167Smax.romanov@nginx.com 4640167Smax.romanov@nginx.com 4641167Smax.romanov@nginx.com static void 4642423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4643423Smax.romanov@nginx.com { 4644423Smax.romanov@nginx.com } 4645423Smax.romanov@nginx.com 4646423Smax.romanov@nginx.com 4647423Smax.romanov@nginx.com static void 46481123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, 46491547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 4650167Smax.romanov@nginx.com { 46511547Smax.romanov@nginx.com nxt_app_t *app; 46521547Smax.romanov@nginx.com nxt_buf_t *buf, *body; 46531123Smax.romanov@nginx.com nxt_int_t res; 46541545Smax.romanov@nginx.com nxt_port_t *port, *reply_port; 46551547Smax.romanov@nginx.com 46561555Smax.romanov@nginx.com int notify; 46571555Smax.romanov@nginx.com struct { 46581555Smax.romanov@nginx.com nxt_port_msg_t pm; 46591555Smax.romanov@nginx.com nxt_port_mmap_msg_t mm; 46601555Smax.romanov@nginx.com } msg; 46611555Smax.romanov@nginx.com 46621555Smax.romanov@nginx.com 46631547Smax.romanov@nginx.com app = req_rpc_data->app; 46641547Smax.romanov@nginx.com 46651547Smax.romanov@nginx.com nxt_assert(app != NULL); 46661547Smax.romanov@nginx.com 46671547Smax.romanov@nginx.com port = req_rpc_data->app_port; 46681547Smax.romanov@nginx.com 46691547Smax.romanov@nginx.com nxt_assert(port != NULL); 46701555Smax.romanov@nginx.com nxt_assert(port->queue != NULL); 46711547Smax.romanov@nginx.com 46721547Smax.romanov@nginx.com reply_port = task->thread->engine->port; 46731547Smax.romanov@nginx.com 46741547Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, req_rpc_data->request, app, 46751547Smax.romanov@nginx.com nxt_app_msg_prefix[app->type]); 4676743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 46771547Smax.romanov@nginx.com nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message", 46781547Smax.romanov@nginx.com req_rpc_data->stream, &app->name); 46791547Smax.romanov@nginx.com 46801547Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 46811547Smax.romanov@nginx.com NXT_HTTP_INTERNAL_SERVER_ERROR); 46821547Smax.romanov@nginx.com 46831547Smax.romanov@nginx.com return; 4684122Smax.romanov@nginx.com } 468588Smax.romanov@nginx.com 4686507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4687743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4688743Smax.romanov@nginx.com port->socket.fd); 468988Smax.romanov@nginx.com 46901547Smax.romanov@nginx.com req_rpc_data->msg_info.buf = buf; 46911547Smax.romanov@nginx.com req_rpc_data->msg_info.completion_handler = buf->completion_handler; 46921547Smax.romanov@nginx.com 46931547Smax.romanov@nginx.com do { 4694743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 46951547Smax.romanov@nginx.com buf = buf->next; 46961547Smax.romanov@nginx.com } while (buf != NULL); 46971547Smax.romanov@nginx.com 46981547Smax.romanov@nginx.com buf = req_rpc_data->msg_info.buf; 46991547Smax.romanov@nginx.com 47001547Smax.romanov@nginx.com body = req_rpc_data->request->body; 47011547Smax.romanov@nginx.com 47021547Smax.romanov@nginx.com if (body != NULL && nxt_buf_is_file(body)) { 47031547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = body->file->fd; 47041547Smax.romanov@nginx.com 47051547Smax.romanov@nginx.com body->file->fd = -1; 47061547Smax.romanov@nginx.com 47071547Smax.romanov@nginx.com } else { 47081547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 47091547Smax.romanov@nginx.com } 47101547Smax.romanov@nginx.com 47111555Smax.romanov@nginx.com msg.pm.stream = req_rpc_data->stream; 47121555Smax.romanov@nginx.com msg.pm.pid = reply_port->pid; 47131555Smax.romanov@nginx.com msg.pm.reply_port = reply_port->id; 47141555Smax.romanov@nginx.com msg.pm.type = NXT_PORT_MSG_REQ_HEADERS; 47151555Smax.romanov@nginx.com msg.pm.last = 0; 47161555Smax.romanov@nginx.com msg.pm.mmap = 1; 47171555Smax.romanov@nginx.com msg.pm.nf = 0; 47181555Smax.romanov@nginx.com msg.pm.mf = 0; 47191555Smax.romanov@nginx.com msg.pm.tracking = 0; 47201555Smax.romanov@nginx.com 47211555Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler = buf->parent; 47221555Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr = mmap_handler->hdr; 47231555Smax.romanov@nginx.com 47241555Smax.romanov@nginx.com msg.mm.mmap_id = hdr->id; 47251555Smax.romanov@nginx.com msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos); 47261555Smax.romanov@nginx.com msg.mm.size = nxt_buf_used_size(buf); 47271555Smax.romanov@nginx.com 47281555Smax.romanov@nginx.com res = nxt_app_queue_send(port->queue, &msg, sizeof(msg), 47291555Smax.romanov@nginx.com req_rpc_data->stream, ¬ify, 47301555Smax.romanov@nginx.com &req_rpc_data->msg_info.tracking_cookie); 47311555Smax.romanov@nginx.com if (nxt_fast_path(res == NXT_OK)) { 47321555Smax.romanov@nginx.com if (notify != 0) { 47331555Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, 47341555Smax.romanov@nginx.com NXT_PORT_MSG_READ_QUEUE, 47351555Smax.romanov@nginx.com -1, req_rpc_data->stream, 47361555Smax.romanov@nginx.com reply_port->id, NULL); 47371555Smax.romanov@nginx.com 47381555Smax.romanov@nginx.com } else { 47391555Smax.romanov@nginx.com nxt_debug(task, "queue is not empty"); 47401555Smax.romanov@nginx.com } 47411555Smax.romanov@nginx.com 47421555Smax.romanov@nginx.com } else { 47431547Smax.romanov@nginx.com nxt_alert(task, "stream #%uD, app '%V': failed to send app message", 47441547Smax.romanov@nginx.com req_rpc_data->stream, &app->name); 47451547Smax.romanov@nginx.com 47461547Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 47471547Smax.romanov@nginx.com NXT_HTTP_INTERNAL_SERVER_ERROR); 47481547Smax.romanov@nginx.com } 474953Sigor@sysoev.ru } 475053Sigor@sysoev.ru 475153Sigor@sysoev.ru 4752743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4753743Smax.romanov@nginx.com nxt_list_part_t *part; 4754743Smax.romanov@nginx.com nxt_http_field_t *field; 4755743Smax.romanov@nginx.com }; 4756743Smax.romanov@nginx.com 4757743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4758743Smax.romanov@nginx.com 4759743Smax.romanov@nginx.com 4760743Smax.romanov@nginx.com static nxt_http_field_t * 4761743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4762216Sigor@sysoev.ru { 4763743Smax.romanov@nginx.com if (part == NULL) { 4764743Smax.romanov@nginx.com return NULL; 4765216Sigor@sysoev.ru } 4766216Sigor@sysoev.ru 4767743Smax.romanov@nginx.com while (part->nelts == 0) { 4768743Smax.romanov@nginx.com part = part->next; 4769743Smax.romanov@nginx.com if (part == NULL) { 4770743Smax.romanov@nginx.com return NULL; 4771743Smax.romanov@nginx.com } 4772216Sigor@sysoev.ru } 4773216Sigor@sysoev.ru 4774743Smax.romanov@nginx.com i->part = part; 4775743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4776743Smax.romanov@nginx.com 4777743Smax.romanov@nginx.com return i->field; 4778743Smax.romanov@nginx.com } 4779743Smax.romanov@nginx.com 4780743Smax.romanov@nginx.com 4781743Smax.romanov@nginx.com static nxt_http_field_t * 4782743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4783743Smax.romanov@nginx.com { 4784743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4785743Smax.romanov@nginx.com } 4786743Smax.romanov@nginx.com 4787743Smax.romanov@nginx.com 4788743Smax.romanov@nginx.com static nxt_http_field_t * 4789743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4790743Smax.romanov@nginx.com { 4791743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4792743Smax.romanov@nginx.com 4793743Smax.romanov@nginx.com end += i->part->nelts; 4794743Smax.romanov@nginx.com i->field++; 4795743Smax.romanov@nginx.com 4796743Smax.romanov@nginx.com if (i->field < end) { 4797743Smax.romanov@nginx.com return i->field; 4798216Sigor@sysoev.ru } 4799216Sigor@sysoev.ru 4800743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4801216Sigor@sysoev.ru } 4802216Sigor@sysoev.ru 4803216Sigor@sysoev.ru 4804743Smax.romanov@nginx.com static nxt_buf_t * 48051007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, 48061547Smax.romanov@nginx.com nxt_app_t *app, const nxt_str_t *prefix) 4807216Sigor@sysoev.ru { 48081007Salexander.borisov@nginx.com void *target_pos, *query_pos; 48091007Salexander.borisov@nginx.com u_char *pos, *end, *p, c; 48101007Salexander.borisov@nginx.com size_t fields_count, req_size, size, free_size; 48111007Salexander.borisov@nginx.com size_t copy_size; 48121007Salexander.borisov@nginx.com nxt_off_t content_length; 48131007Salexander.borisov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 48141007Salexander.borisov@nginx.com nxt_http_field_t *field, *dup; 48151007Salexander.borisov@nginx.com nxt_unit_field_t *dst_field; 48161007Salexander.borisov@nginx.com nxt_fields_iter_t iter, dup_iter; 48171007Salexander.borisov@nginx.com nxt_unit_request_t *req; 4818216Sigor@sysoev.ru 4819743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 48201007Salexander.borisov@nginx.com + r->method->length + 1 48211007Salexander.borisov@nginx.com + r->version.length + 1 48221007Salexander.borisov@nginx.com + r->remote->length + 1 48231007Salexander.borisov@nginx.com + r->local->length + 1 48241007Salexander.borisov@nginx.com + r->server_name.length + 1 48251007Salexander.borisov@nginx.com + r->target.length + 1 48261007Salexander.borisov@nginx.com + (r->path->start != r->target.start ? r->path->length + 1 : 0); 48271007Salexander.borisov@nginx.com 48281007Salexander.borisov@nginx.com content_length = r->content_length_n < 0 ? 0 : r->content_length_n; 4829743Smax.romanov@nginx.com fields_count = 0; 4830743Smax.romanov@nginx.com 48311007Salexander.borisov@nginx.com nxt_list_each(field, r->fields) { 4832743Smax.romanov@nginx.com fields_count++; 4833743Smax.romanov@nginx.com 4834743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4835743Smax.romanov@nginx.com + field->value_length + 1; 4836743Smax.romanov@nginx.com } nxt_list_loop; 4837743Smax.romanov@nginx.com 4838743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4839743Smax.romanov@nginx.com 4840743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4841743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4842743Smax.romanov@nginx.com (int) req_size); 4843743Smax.romanov@nginx.com 4844743Smax.romanov@nginx.com return NULL; 4845743Smax.romanov@nginx.com } 4846743Smax.romanov@nginx.com 48471547Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, &app->outgoing, 48481007Salexander.borisov@nginx.com nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); 4849743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4850743Smax.romanov@nginx.com return NULL; 4851743Smax.romanov@nginx.com } 4852743Smax.romanov@nginx.com 4853743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4854743Smax.romanov@nginx.com out->mem.free += req_size; 4855743Smax.romanov@nginx.com 48561473Svbart@nginx.com req->app_target = r->app_target; 48571473Svbart@nginx.com 48581007Salexander.borisov@nginx.com req->content_length = content_length; 4859743Smax.romanov@nginx.com 4860743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4861743Smax.romanov@nginx.com 4862743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4863743Smax.romanov@nginx.com 48641007Salexander.borisov@nginx.com req->method_length = r->method->length; 4865743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 48661007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 4867743Smax.romanov@nginx.com *p++ = '\0'; 4868743Smax.romanov@nginx.com 48691007Salexander.borisov@nginx.com req->version_length = r->version.length; 4870743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 48711007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 4872743Smax.romanov@nginx.com *p++ = '\0'; 4873743Smax.romanov@nginx.com 48741007Salexander.borisov@nginx.com req->remote_length = r->remote->address_length; 4875743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 48761007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), 48771007Salexander.borisov@nginx.com r->remote->address_length); 4878743Smax.romanov@nginx.com *p++ = '\0'; 4879743Smax.romanov@nginx.com 48801007Salexander.borisov@nginx.com req->local_length = r->local->address_length; 4881743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 48821007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); 4883743Smax.romanov@nginx.com *p++ = '\0'; 4884743Smax.romanov@nginx.com 48851011Smax.romanov@nginx.com req->tls = (r->tls != NULL); 48861131Smax.romanov@nginx.com req->websocket_handshake = r->websocket_handshake; 48871011Smax.romanov@nginx.com 48881007Salexander.borisov@nginx.com req->server_name_length = r->server_name.length; 4889967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 48901007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->server_name.start, r->server_name.length); 4891967Svbart@nginx.com *p++ = '\0'; 4892967Svbart@nginx.com 4893743Smax.romanov@nginx.com target_pos = p; 48941007Salexander.borisov@nginx.com req->target_length = (uint32_t) r->target.length; 4895743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 48961007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 4897743Smax.romanov@nginx.com *p++ = '\0'; 4898743Smax.romanov@nginx.com 48991007Salexander.borisov@nginx.com req->path_length = (uint32_t) r->path->length; 49001007Salexander.borisov@nginx.com if (r->path->start == r->target.start) { 4901743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 4902277Sigor@sysoev.ru 4903216Sigor@sysoev.ru } else { 4904743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 49051007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 4906743Smax.romanov@nginx.com *p++ = '\0'; 4907305Smax.romanov@nginx.com } 4908216Sigor@sysoev.ru 49091007Salexander.borisov@nginx.com req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0; 49101007Salexander.borisov@nginx.com if (r->args != NULL && r->args->start != NULL) { 4911743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 49121007Salexander.borisov@nginx.com r->args->start - r->target.start); 4913743Smax.romanov@nginx.com 4914743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 4915277Sigor@sysoev.ru 4916216Sigor@sysoev.ru } else { 4917743Smax.romanov@nginx.com req->query.offset = 0; 4918216Sigor@sysoev.ru } 4919216Sigor@sysoev.ru 4920743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 4921743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 4922743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 4923743Smax.romanov@nginx.com 4924743Smax.romanov@nginx.com dst_field = req->fields; 4925743Smax.romanov@nginx.com 49261007Salexander.borisov@nginx.com for (field = nxt_fields_first(r->fields, &iter); 4927743Smax.romanov@nginx.com field != NULL; 4928743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 4929743Smax.romanov@nginx.com { 4930743Smax.romanov@nginx.com if (field->skip) { 4931743Smax.romanov@nginx.com continue; 4932743Smax.romanov@nginx.com } 4933743Smax.romanov@nginx.com 4934743Smax.romanov@nginx.com dst_field->hash = field->hash; 4935743Smax.romanov@nginx.com dst_field->skip = 0; 4936743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 4937743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 4938743Smax.romanov@nginx.com 49391007Salexander.borisov@nginx.com if (field == r->content_length) { 4940743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 4941743Smax.romanov@nginx.com 49421007Salexander.borisov@nginx.com } else if (field == r->content_type) { 4943743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 4944743Smax.romanov@nginx.com 49451007Salexander.borisov@nginx.com } else if (field == r->cookie) { 4946743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 4947743Smax.romanov@nginx.com } 4948743Smax.romanov@nginx.com 4949743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 4950743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 4951743Smax.romanov@nginx.com (int) field->name_length, field->name, 4952743Smax.romanov@nginx.com (int) field->value_length, field->value); 4953743Smax.romanov@nginx.com 4954743Smax.romanov@nginx.com if (prefix->length != 0) { 4955743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4956743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 4957743Smax.romanov@nginx.com 4958743Smax.romanov@nginx.com end = field->name + field->name_length; 4959743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 4960743Smax.romanov@nginx.com c = *pos; 4961743Smax.romanov@nginx.com 4962743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 4963743Smax.romanov@nginx.com *p++ = (c & ~0x20); 4964743Smax.romanov@nginx.com continue; 4965743Smax.romanov@nginx.com } 4966743Smax.romanov@nginx.com 4967743Smax.romanov@nginx.com if (c == '-') { 4968743Smax.romanov@nginx.com *p++ = '_'; 4969743Smax.romanov@nginx.com continue; 4970743Smax.romanov@nginx.com } 4971743Smax.romanov@nginx.com 4972743Smax.romanov@nginx.com *p++ = c; 4973743Smax.romanov@nginx.com } 4974743Smax.romanov@nginx.com 4975743Smax.romanov@nginx.com } else { 4976743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4977743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 4978743Smax.romanov@nginx.com } 4979743Smax.romanov@nginx.com 4980743Smax.romanov@nginx.com *p++ = '\0'; 4981743Smax.romanov@nginx.com 4982743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 4983743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 4984743Smax.romanov@nginx.com 4985743Smax.romanov@nginx.com if (prefix->length != 0) { 4986743Smax.romanov@nginx.com dup_iter = iter; 4987743Smax.romanov@nginx.com 4988743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 4989743Smax.romanov@nginx.com dup != NULL; 4990743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 4991743Smax.romanov@nginx.com { 4992743Smax.romanov@nginx.com if (dup->name_length != field->name_length 4993743Smax.romanov@nginx.com || dup->skip 4994743Smax.romanov@nginx.com || dup->hash != field->hash 4995743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 4996743Smax.romanov@nginx.com { 4997743Smax.romanov@nginx.com continue; 4998743Smax.romanov@nginx.com } 4999743Smax.romanov@nginx.com 5000743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 5001743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 5002743Smax.romanov@nginx.com 5003743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 5004743Smax.romanov@nginx.com 5005743Smax.romanov@nginx.com dup->skip = 1; 5006743Smax.romanov@nginx.com } 5007743Smax.romanov@nginx.com } 5008743Smax.romanov@nginx.com 5009743Smax.romanov@nginx.com *p++ = '\0'; 5010743Smax.romanov@nginx.com 5011743Smax.romanov@nginx.com dst_field++; 5012743Smax.romanov@nginx.com } 5013743Smax.romanov@nginx.com 50141007Salexander.borisov@nginx.com req->fields_count = (uint32_t) (dst_field - req->fields); 5015743Smax.romanov@nginx.com 5016743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 5017743Smax.romanov@nginx.com 5018743Smax.romanov@nginx.com buf = out; 5019743Smax.romanov@nginx.com tail = &buf->next; 5020216Sigor@sysoev.ru 50211007Salexander.borisov@nginx.com for (b = r->body; b != NULL; b = b->next) { 5022743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 5023743Smax.romanov@nginx.com pos = b->mem.pos; 5024743Smax.romanov@nginx.com 5025743Smax.romanov@nginx.com while (size > 0) { 5026743Smax.romanov@nginx.com if (buf == NULL) { 5027743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 5028743Smax.romanov@nginx.com 50291547Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size); 5030743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 5031743Smax.romanov@nginx.com while (out != NULL) { 5032743Smax.romanov@nginx.com buf = out->next; 50331269Sigor@sysoev.ru out->next = NULL; 5034743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 5035743Smax.romanov@nginx.com out = buf; 5036743Smax.romanov@nginx.com } 5037743Smax.romanov@nginx.com return NULL; 5038743Smax.romanov@nginx.com } 5039743Smax.romanov@nginx.com 5040743Smax.romanov@nginx.com *tail = buf; 5041743Smax.romanov@nginx.com tail = &buf->next; 5042743Smax.romanov@nginx.com 5043743Smax.romanov@nginx.com } else { 5044743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5045743Smax.romanov@nginx.com if (free_size < size 5046743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 5047743Smax.romanov@nginx.com == NXT_OK) 5048743Smax.romanov@nginx.com { 5049743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5050743Smax.romanov@nginx.com } 5051743Smax.romanov@nginx.com } 5052743Smax.romanov@nginx.com 5053743Smax.romanov@nginx.com if (free_size > 0) { 5054743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 5055743Smax.romanov@nginx.com 5056743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 5057743Smax.romanov@nginx.com 5058743Smax.romanov@nginx.com size -= copy_size; 5059743Smax.romanov@nginx.com pos += copy_size; 5060743Smax.romanov@nginx.com 5061743Smax.romanov@nginx.com if (size == 0) { 5062743Smax.romanov@nginx.com break; 5063743Smax.romanov@nginx.com } 5064743Smax.romanov@nginx.com } 5065743Smax.romanov@nginx.com 5066743Smax.romanov@nginx.com buf = NULL; 5067743Smax.romanov@nginx.com } 5068216Sigor@sysoev.ru } 5069216Sigor@sysoev.ru 5070743Smax.romanov@nginx.com return out; 5071584Salexander.borisov@nginx.com } 5072584Salexander.borisov@nginx.com 5073584Salexander.borisov@nginx.com 507453Sigor@sysoev.ru static void 5075318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 5076318Smax.romanov@nginx.com { 5077615Smax.romanov@nginx.com nxt_timer_t *timer; 50781007Salexander.borisov@nginx.com nxt_http_request_t *r; 50791123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5080318Smax.romanov@nginx.com 5081318Smax.romanov@nginx.com timer = obj; 5082318Smax.romanov@nginx.com 5083318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 5084318Smax.romanov@nginx.com 50851007Salexander.borisov@nginx.com r = nxt_timer_data(timer, nxt_http_request_t, timer); 50861123Smax.romanov@nginx.com req_rpc_data = r->timer_data; 5087615Smax.romanov@nginx.com 50881007Salexander.borisov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 5089615Smax.romanov@nginx.com 50901123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 5091318Smax.romanov@nginx.com } 50921007Salexander.borisov@nginx.com 50931007Salexander.borisov@nginx.com 50941547Smax.romanov@nginx.com static void 50951547Smax.romanov@nginx.com nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r) 50961007Salexander.borisov@nginx.com { 50971007Salexander.borisov@nginx.com r->timer.handler = nxt_router_http_request_release; 50981007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 0); 50991007Salexander.borisov@nginx.com } 51001007Salexander.borisov@nginx.com 51011007Salexander.borisov@nginx.com 51021007Salexander.borisov@nginx.com static void 51031007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) 51041007Salexander.borisov@nginx.com { 51051007Salexander.borisov@nginx.com nxt_http_request_t *r; 51061007Salexander.borisov@nginx.com 51071547Smax.romanov@nginx.com nxt_debug(task, "http request pool release"); 51081007Salexander.borisov@nginx.com 51091007Salexander.borisov@nginx.com r = nxt_timer_data(obj, nxt_http_request_t, timer); 51101007Salexander.borisov@nginx.com 51111007Salexander.borisov@nginx.com nxt_mp_release(r->mem_pool); 51121007Salexander.borisov@nginx.com } 51131321Smax.romanov@nginx.com 51141321Smax.romanov@nginx.com 51151321Smax.romanov@nginx.com static void 51161321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 51171321Smax.romanov@nginx.com { 51181321Smax.romanov@nginx.com size_t mi; 51191321Smax.romanov@nginx.com uint32_t i; 51201321Smax.romanov@nginx.com nxt_bool_t ack; 51211321Smax.romanov@nginx.com nxt_process_t *process; 51221321Smax.romanov@nginx.com nxt_free_map_t *m; 51231321Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 51241321Smax.romanov@nginx.com 51251321Smax.romanov@nginx.com nxt_debug(task, "oosm in %PI", msg->port_msg.pid); 51261321Smax.romanov@nginx.com 51271321Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, 51281321Smax.romanov@nginx.com msg->port_msg.pid); 51291321Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 51301321Smax.romanov@nginx.com return; 51311321Smax.romanov@nginx.com } 51321321Smax.romanov@nginx.com 51331321Smax.romanov@nginx.com ack = 0; 51341321Smax.romanov@nginx.com 51351321Smax.romanov@nginx.com /* 51361321Smax.romanov@nginx.com * To mitigate possible racing condition (when OOSM message received 51371321Smax.romanov@nginx.com * after some of the memory was already freed), need to try to find 51381321Smax.romanov@nginx.com * first free segment in shared memory and send ACK if found. 51391321Smax.romanov@nginx.com */ 51401321Smax.romanov@nginx.com 51411321Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 51421321Smax.romanov@nginx.com 51431321Smax.romanov@nginx.com for (i = 0; i < process->incoming.size; i++) { 51441321Smax.romanov@nginx.com hdr = process->incoming.elts[i].mmap_handler->hdr; 51451321Smax.romanov@nginx.com m = hdr->free_map; 51461321Smax.romanov@nginx.com 51471321Smax.romanov@nginx.com for (mi = 0; mi < MAX_FREE_IDX; mi++) { 51481321Smax.romanov@nginx.com if (m[mi] != 0) { 51491321Smax.romanov@nginx.com ack = 1; 51501321Smax.romanov@nginx.com 51511321Smax.romanov@nginx.com nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA", 51521321Smax.romanov@nginx.com i, mi, m[mi]); 51531321Smax.romanov@nginx.com 51541321Smax.romanov@nginx.com break; 51551321Smax.romanov@nginx.com } 51561321Smax.romanov@nginx.com } 51571321Smax.romanov@nginx.com } 51581321Smax.romanov@nginx.com 51591321Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 51601321Smax.romanov@nginx.com 51611321Smax.romanov@nginx.com if (ack) { 51621321Smax.romanov@nginx.com (void) nxt_port_socket_write(task, msg->port, NXT_PORT_MSG_SHM_ACK, 51631321Smax.romanov@nginx.com -1, 0, 0, NULL); 51641321Smax.romanov@nginx.com } 51651321Smax.romanov@nginx.com } 51661545Smax.romanov@nginx.com 51671545Smax.romanov@nginx.com 51681545Smax.romanov@nginx.com static void 51691546Smax.romanov@nginx.com nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 51701546Smax.romanov@nginx.com { 51711546Smax.romanov@nginx.com nxt_fd_t fd; 51721546Smax.romanov@nginx.com nxt_port_t *port; 51731546Smax.romanov@nginx.com nxt_runtime_t *rt; 51741546Smax.romanov@nginx.com nxt_port_mmaps_t *mmaps; 51751546Smax.romanov@nginx.com nxt_port_msg_get_mmap_t *get_mmap_msg; 51761546Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 51771546Smax.romanov@nginx.com 51781546Smax.romanov@nginx.com rt = task->thread->runtime; 51791546Smax.romanov@nginx.com 51801546Smax.romanov@nginx.com port = nxt_runtime_port_find(rt, msg->port_msg.pid, 51811546Smax.romanov@nginx.com msg->port_msg.reply_port); 51821546Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 51831546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found", 51841546Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 51851546Smax.romanov@nginx.com 51861546Smax.romanov@nginx.com return; 51871546Smax.romanov@nginx.com } 51881546Smax.romanov@nginx.com 51891546Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_used_size(msg->buf) 51901546Smax.romanov@nginx.com < (int) sizeof(nxt_port_msg_get_mmap_t))) 51911546Smax.romanov@nginx.com { 51921546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: message buffer too small (%d)", 51931546Smax.romanov@nginx.com (int) nxt_buf_used_size(msg->buf)); 51941546Smax.romanov@nginx.com 51951546Smax.romanov@nginx.com return; 51961546Smax.romanov@nginx.com } 51971546Smax.romanov@nginx.com 51981546Smax.romanov@nginx.com get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos; 51991546Smax.romanov@nginx.com 52001546Smax.romanov@nginx.com nxt_assert(port->type == NXT_PROCESS_APP); 52011546Smax.romanov@nginx.com 52021547Smax.romanov@nginx.com if (nxt_slow_path(port->app == NULL)) { 52031547Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d", 52041547Smax.romanov@nginx.com port->pid, port->id); 52051547Smax.romanov@nginx.com 52061547Smax.romanov@nginx.com // FIXME 52071547Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 52081547Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 52091547Smax.romanov@nginx.com 52101547Smax.romanov@nginx.com return; 52111547Smax.romanov@nginx.com } 52121547Smax.romanov@nginx.com 52131547Smax.romanov@nginx.com mmaps = &port->app->outgoing; 52141546Smax.romanov@nginx.com nxt_thread_mutex_lock(&mmaps->mutex); 52151546Smax.romanov@nginx.com 52161546Smax.romanov@nginx.com if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) { 52171546Smax.romanov@nginx.com nxt_thread_mutex_unlock(&mmaps->mutex); 52181546Smax.romanov@nginx.com 52191546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)", 52201546Smax.romanov@nginx.com (int) get_mmap_msg->id); 52211546Smax.romanov@nginx.com 52221547Smax.romanov@nginx.com // FIXME 52231547Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 52241547Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 52251546Smax.romanov@nginx.com return; 52261546Smax.romanov@nginx.com } 52271546Smax.romanov@nginx.com 52281546Smax.romanov@nginx.com mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler; 52291546Smax.romanov@nginx.com 52301546Smax.romanov@nginx.com fd = mmap_handler->fd; 52311546Smax.romanov@nginx.com 52321546Smax.romanov@nginx.com nxt_thread_mutex_unlock(&mmaps->mutex); 52331546Smax.romanov@nginx.com 52341546Smax.romanov@nginx.com nxt_debug(task, "get mmap %PI:%d found", 52351546Smax.romanov@nginx.com msg->port_msg.pid, (int) get_mmap_msg->id); 52361546Smax.romanov@nginx.com 52371546Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL); 52381546Smax.romanov@nginx.com } 52391546Smax.romanov@nginx.com 52401546Smax.romanov@nginx.com 52411546Smax.romanov@nginx.com static void 52421545Smax.romanov@nginx.com nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 52431545Smax.romanov@nginx.com { 52441545Smax.romanov@nginx.com nxt_port_t *port, *reply_port; 52451545Smax.romanov@nginx.com nxt_runtime_t *rt; 52461545Smax.romanov@nginx.com nxt_port_msg_get_port_t *get_port_msg; 52471545Smax.romanov@nginx.com 52481545Smax.romanov@nginx.com rt = task->thread->runtime; 52491545Smax.romanov@nginx.com 52501545Smax.romanov@nginx.com reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid, 52511545Smax.romanov@nginx.com msg->port_msg.reply_port); 52521545Smax.romanov@nginx.com if (nxt_slow_path(reply_port == NULL)) { 52531545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: reply_port %PI:%d not found", 52541545Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 52551545Smax.romanov@nginx.com 52561545Smax.romanov@nginx.com return; 52571545Smax.romanov@nginx.com } 52581545Smax.romanov@nginx.com 52591545Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_used_size(msg->buf) 52601545Smax.romanov@nginx.com < (int) sizeof(nxt_port_msg_get_port_t))) 52611545Smax.romanov@nginx.com { 52621545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: message buffer too small (%d)", 52631545Smax.romanov@nginx.com (int) nxt_buf_used_size(msg->buf)); 52641545Smax.romanov@nginx.com 52651545Smax.romanov@nginx.com return; 52661545Smax.romanov@nginx.com } 52671545Smax.romanov@nginx.com 52681545Smax.romanov@nginx.com get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos; 52691545Smax.romanov@nginx.com 52701545Smax.romanov@nginx.com port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id); 52711545Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 52721545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: port %PI:%d not found", 52731545Smax.romanov@nginx.com get_port_msg->pid, get_port_msg->id); 52741545Smax.romanov@nginx.com 52751545Smax.romanov@nginx.com return; 52761545Smax.romanov@nginx.com } 52771545Smax.romanov@nginx.com 52781545Smax.romanov@nginx.com nxt_debug(task, "get port %PI:%d found", get_port_msg->pid, 52791545Smax.romanov@nginx.com get_port_msg->id); 52801545Smax.romanov@nginx.com 52811545Smax.romanov@nginx.com (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream); 52821545Smax.romanov@nginx.com } 5283