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 211926Smax.romanov@nginx.com #define NXT_SHARED_PORT_ID 0xFFFFu 221926Smax.romanov@nginx.com 23115Sigor@sysoev.ru typedef struct { 24318Smax.romanov@nginx.com nxt_str_t type; 25507Smax.romanov@nginx.com uint32_t processes; 26507Smax.romanov@nginx.com uint32_t max_processes; 27507Smax.romanov@nginx.com uint32_t spare_processes; 28318Smax.romanov@nginx.com nxt_msec_t timeout; 29507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 30318Smax.romanov@nginx.com uint32_t requests; 31318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 32507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 331473Svbart@nginx.com nxt_conf_value_t *targets_value; 34133Sigor@sysoev.ru } nxt_router_app_conf_t; 35133Sigor@sysoev.ru 36133Sigor@sysoev.ru 37133Sigor@sysoev.ru typedef struct { 38964Sigor@sysoev.ru nxt_str_t pass; 39964Sigor@sysoev.ru nxt_str_t application; 40115Sigor@sysoev.ru } nxt_router_listener_conf_t; 41115Sigor@sysoev.ru 42115Sigor@sysoev.ru 43774Svbart@nginx.com #if (NXT_TLS) 44774Svbart@nginx.com 45774Svbart@nginx.com typedef struct { 461885Sa.suvorov@f5.com nxt_str_t name; 471885Sa.suvorov@f5.com nxt_socket_conf_t *socket_conf; 481885Sa.suvorov@f5.com nxt_router_temp_conf_t *temp_conf; 491920Sa.suvorov@f5.com nxt_tls_init_t *tls_init; 501885Sa.suvorov@f5.com nxt_bool_t last; 51774Svbart@nginx.com 521920Sa.suvorov@f5.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 53774Svbart@nginx.com } nxt_router_tlssock_t; 54774Svbart@nginx.com 55774Svbart@nginx.com #endif 56774Svbart@nginx.com 57774Svbart@nginx.com 58198Sigor@sysoev.ru typedef struct { 591828Sa.suvorov@f5.com nxt_str_t *name; 60198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 61198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 621828Sa.suvorov@f5.com nxt_bool_t last; 63198Sigor@sysoev.ru } nxt_socket_rpc_t; 64198Sigor@sysoev.ru 65198Sigor@sysoev.ru 66507Smax.romanov@nginx.com typedef struct { 67507Smax.romanov@nginx.com nxt_app_t *app; 68507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 69507Smax.romanov@nginx.com } nxt_app_rpc_t; 70507Smax.romanov@nginx.com 71507Smax.romanov@nginx.com 721926Smax.romanov@nginx.com typedef struct { 731926Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 741926Smax.romanov@nginx.com uint32_t generation; 751926Smax.romanov@nginx.com } nxt_app_joint_rpc_t; 761926Smax.romanov@nginx.com 771926Smax.romanov@nginx.com 781488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, 791488St.nateldemoura@f5.com nxt_mp_t *mp); 801488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data); 81662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 82662Smax.romanov@nginx.com nxt_port_t *controller_port); 83662Smax.romanov@nginx.com 84507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 85425Smax.romanov@nginx.com 861552Smax.romanov@nginx.com static void nxt_router_new_port_handler(nxt_task_t *task, 871552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 881552Smax.romanov@nginx.com static void nxt_router_conf_data_handler(nxt_task_t *task, 891552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 901926Smax.romanov@nginx.com static void nxt_router_app_restart_handler(nxt_task_t *task, 911926Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 921552Smax.romanov@nginx.com static void nxt_router_remove_pid_handler(nxt_task_t *task, 931552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 941552Smax.romanov@nginx.com static void nxt_router_access_log_reopen_handler(nxt_task_t *task, 951552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 961552Smax.romanov@nginx.com 97139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 98198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 99198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 100139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 101139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 102139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 103139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 104193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 10553Sigor@sysoev.ru 106115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 107115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 1081183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 1091183Svbart@nginx.com nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); 1101936So.canty@f5.com static nxt_int_t nxt_router_conf_process_client_ip(nxt_task_t *task, 1111936So.canty@f5.com nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf, 1121936So.canty@f5.com nxt_conf_value_t *conf); 1131563Svbart@nginx.com 114133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 1151563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data); 1161563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, 1171563Svbart@nginx.com nxt_app_t *app); 1181563Svbart@nginx.com static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, 1191563Svbart@nginx.com nxt_str_t *name); 1201563Svbart@nginx.com static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, 1211563Svbart@nginx.com int i); 1221563Svbart@nginx.com 1231555Smax.romanov@nginx.com static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task, 1241555Smax.romanov@nginx.com nxt_port_t *port); 1251555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task, 1261555Smax.romanov@nginx.com nxt_port_t *port); 1271555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task, 1281555Smax.romanov@nginx.com nxt_port_t *port, nxt_fd_t fd); 129198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 130198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 131198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 132198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 133198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 134198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 135774Svbart@nginx.com #if (NXT_TLS) 136774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task, 137774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 1381828Sa.suvorov@f5.com static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, 1391920Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init, 1401920Sa.suvorov@f5.com nxt_bool_t last); 141774Svbart@nginx.com #endif 142507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 143507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 144507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 145507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 146507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 147507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 148359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 149359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 150359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 151359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 15253Sigor@sysoev.ru 15353Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 15453Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 15553Sigor@sysoev.ru const nxt_event_interface_t *interface); 156115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 157115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 158115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 159115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 160115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 161115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 162154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 163154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 164154Sigor@sysoev.ru nxt_work_handler_t handler); 165313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 166313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 167139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 168139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 16953Sigor@sysoev.ru 17053Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 17153Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17253Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 17353Sigor@sysoev.ru nxt_event_engine_t *engine); 174343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 175133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17653Sigor@sysoev.ru 177315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 178315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 179315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 180315Sigor@sysoev.ru nxt_work_t *jobs); 18153Sigor@sysoev.ru 18253Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 1831545Smax.romanov@nginx.com static void nxt_router_rt_add_port(nxt_task_t *task, void *obj, 1841545Smax.romanov@nginx.com void *data); 18553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 18653Sigor@sysoev.ru void *data); 18753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 18853Sigor@sysoev.ru void *data); 18953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 19053Sigor@sysoev.ru void *data); 191313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 192313Sigor@sysoev.ru void *data); 19353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 19453Sigor@sysoev.ru void *data); 19553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 19653Sigor@sysoev.ru void *data); 1971547Smax.romanov@nginx.com static void nxt_router_req_headers_ack_handler(nxt_task_t *task, 1981547Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data); 199359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 200359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 20153Sigor@sysoev.ru 202630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 203630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 204630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 205630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 206630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 207630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 208630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 209630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 210630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 211630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 212630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 213630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 214651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 215651Svbart@nginx.com void *data); 216631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 217631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 218631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 219631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 220630Svbart@nginx.com 221343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 222343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 2231547Smax.romanov@nginx.com static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task, 2241547Smax.romanov@nginx.com nxt_port_t *app_port); 225343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 226343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 227343Smax.romanov@nginx.com 2281563Svbart@nginx.com static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i); 229753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 2301123Smax.romanov@nginx.com 231*1978Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, 232*1978Smax.romanov@nginx.com nxt_port_t *port, nxt_apr_action_t action); 2331547Smax.romanov@nginx.com static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, 2341547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2351561Smax.romanov@nginx.com static void nxt_router_http_request_error(nxt_task_t *task, void *obj, 2361561Smax.romanov@nginx.com void *data); 2371547Smax.romanov@nginx.com static void nxt_router_http_request_done(nxt_task_t *task, void *obj, 2381547Smax.romanov@nginx.com void *data); 239141Smax.romanov@nginx.com 240425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 2411547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2421007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 2431547Smax.romanov@nginx.com nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix); 244510Salexander.borisov@nginx.com 245318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 246507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 247507Smax.romanov@nginx.com void *data); 248507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 249507Smax.romanov@nginx.com void *data); 250753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 251507Smax.romanov@nginx.com void *data); 252753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 253431Sigor@sysoev.ru 254431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 255431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 256141Smax.romanov@nginx.com 257753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 258753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 259753Smax.romanov@nginx.com 2601547Smax.romanov@nginx.com static void nxt_router_http_request_release_post(nxt_task_t *task, 2611007Salexander.borisov@nginx.com nxt_http_request_t *r); 2621007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 2631007Salexander.borisov@nginx.com void *data); 2641321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 2651545Smax.romanov@nginx.com static void nxt_router_get_port_handler(nxt_task_t *task, 2661545Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2671546Smax.romanov@nginx.com static void nxt_router_get_mmap_handler(nxt_task_t *task, 2681546Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2691007Salexander.borisov@nginx.com 2701149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2711131Smax.romanov@nginx.com 272119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 27320Sigor@sysoev.ru 274743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 275743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 276743Smax.romanov@nginx.com 277743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 278804Svbart@nginx.com &empty_prefix, 2791594Smax.romanov@nginx.com &empty_prefix, 280743Smax.romanov@nginx.com &http_prefix, 281743Smax.romanov@nginx.com &http_prefix, 282743Smax.romanov@nginx.com &http_prefix, 283977Smax.romanov@gmail.com &empty_prefix, 284216Sigor@sysoev.ru }; 285216Sigor@sysoev.ru 286216Sigor@sysoev.ru 2871488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_router_process_port_handlers = { 2881488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 289662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 2901545Smax.romanov@nginx.com .get_port = nxt_router_get_port_handler, 291662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 292662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2931546Smax.romanov@nginx.com .get_mmap = nxt_router_get_mmap_handler, 294662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 2951926Smax.romanov@nginx.com .app_restart = nxt_router_app_restart_handler, 296662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 297662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 298662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 299662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 3001321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 301662Smax.romanov@nginx.com }; 302662Smax.romanov@nginx.com 303662Smax.romanov@nginx.com 3041488St.nateldemoura@f5.com const nxt_process_init_t nxt_router_process = { 3051488St.nateldemoura@f5.com .name = "router", 3061488St.nateldemoura@f5.com .type = NXT_PROCESS_ROUTER, 3071488St.nateldemoura@f5.com .prefork = nxt_router_prefork, 3081488St.nateldemoura@f5.com .restart = 1, 3091488St.nateldemoura@f5.com .setup = nxt_process_core_setup, 3101488St.nateldemoura@f5.com .start = nxt_router_start, 3111488St.nateldemoura@f5.com .port_handlers = &nxt_router_process_port_handlers, 3121488St.nateldemoura@f5.com .signals = nxt_process_signals, 3131488St.nateldemoura@f5.com }; 3141488St.nateldemoura@f5.com 3151488St.nateldemoura@f5.com 3161509Sigor@sysoev.ru /* Queues of nxt_socket_conf_t */ 3171509Sigor@sysoev.ru nxt_queue_t creating_sockets; 3181509Sigor@sysoev.ru nxt_queue_t pending_sockets; 3191509Sigor@sysoev.ru nxt_queue_t updating_sockets; 3201509Sigor@sysoev.ru nxt_queue_t keeping_sockets; 3211509Sigor@sysoev.ru nxt_queue_t deleting_sockets; 3221509Sigor@sysoev.ru 3231509Sigor@sysoev.ru 3241488St.nateldemoura@f5.com static nxt_int_t 3251488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) 3261488St.nateldemoura@f5.com { 3271488St.nateldemoura@f5.com nxt_runtime_stop_app_processes(task, task->thread->runtime); 3281488St.nateldemoura@f5.com 3291488St.nateldemoura@f5.com return NXT_OK; 3301488St.nateldemoura@f5.com } 3311488St.nateldemoura@f5.com 3321488St.nateldemoura@f5.com 3331488St.nateldemoura@f5.com static nxt_int_t 3341488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data) 33520Sigor@sysoev.ru { 336141Smax.romanov@nginx.com nxt_int_t ret; 337662Smax.romanov@nginx.com nxt_port_t *controller_port; 338141Smax.romanov@nginx.com nxt_router_t *router; 339141Smax.romanov@nginx.com nxt_runtime_t *rt; 340141Smax.romanov@nginx.com 341141Smax.romanov@nginx.com rt = task->thread->runtime; 34253Sigor@sysoev.ru 3431488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "router started"); 3441488St.nateldemoura@f5.com 345771Sigor@sysoev.ru #if (NXT_TLS) 346771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 347771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 348771Sigor@sysoev.ru return NXT_ERROR; 349771Sigor@sysoev.ru } 350771Sigor@sysoev.ru 351771Sigor@sysoev.ru ret = rt->tls->library_init(task); 352771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 353771Sigor@sysoev.ru return ret; 354771Sigor@sysoev.ru } 355771Sigor@sysoev.ru #endif 356771Sigor@sysoev.ru 3571459Smax.romanov@nginx.com ret = nxt_http_init(task); 35888Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 35988Smax.romanov@nginx.com return ret; 36088Smax.romanov@nginx.com } 36188Smax.romanov@nginx.com 36253Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 36353Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 36453Sigor@sysoev.ru return NXT_ERROR; 36553Sigor@sysoev.ru } 36653Sigor@sysoev.ru 36753Sigor@sysoev.ru nxt_queue_init(&router->engines); 36853Sigor@sysoev.ru nxt_queue_init(&router->sockets); 369133Sigor@sysoev.ru nxt_queue_init(&router->apps); 37053Sigor@sysoev.ru 371119Smax.romanov@nginx.com nxt_router = router; 372119Smax.romanov@nginx.com 373662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 374662Smax.romanov@nginx.com if (controller_port != NULL) { 375662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 376662Smax.romanov@nginx.com } 377662Smax.romanov@nginx.com 378115Sigor@sysoev.ru return NXT_OK; 379115Sigor@sysoev.ru } 380115Sigor@sysoev.ru 381115Sigor@sysoev.ru 382343Smax.romanov@nginx.com static void 383662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 384662Smax.romanov@nginx.com { 385662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 386662Smax.romanov@nginx.com -1, 0, 0, NULL); 387662Smax.romanov@nginx.com } 388662Smax.romanov@nginx.com 389662Smax.romanov@nginx.com 390662Smax.romanov@nginx.com static void 391507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 392507Smax.romanov@nginx.com void *data) 393167Smax.romanov@nginx.com { 3941926Smax.romanov@nginx.com size_t size; 3951926Smax.romanov@nginx.com uint32_t stream; 3961926Smax.romanov@nginx.com nxt_mp_t *mp; 3971926Smax.romanov@nginx.com nxt_int_t ret; 3981926Smax.romanov@nginx.com nxt_app_t *app; 3991926Smax.romanov@nginx.com nxt_buf_t *b; 4001926Smax.romanov@nginx.com nxt_port_t *main_port; 4011926Smax.romanov@nginx.com nxt_runtime_t *rt; 4021926Smax.romanov@nginx.com nxt_app_joint_rpc_t *app_joint_rpc; 403343Smax.romanov@nginx.com 404343Smax.romanov@nginx.com app = data; 405167Smax.romanov@nginx.com 406167Smax.romanov@nginx.com rt = task->thread->runtime; 407240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 408167Smax.romanov@nginx.com 409507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 410343Smax.romanov@nginx.com 411343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 412343Smax.romanov@nginx.com 413343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 414343Smax.romanov@nginx.com 415343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 416343Smax.romanov@nginx.com goto failed; 417167Smax.romanov@nginx.com } 418167Smax.romanov@nginx.com 419343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 420343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 421343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 422343Smax.romanov@nginx.com 4231926Smax.romanov@nginx.com app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port, 4241926Smax.romanov@nginx.com nxt_router_app_port_ready, 4251926Smax.romanov@nginx.com nxt_router_app_port_error, 4261926Smax.romanov@nginx.com sizeof(nxt_app_joint_rpc_t)); 4271926Smax.romanov@nginx.com if (nxt_slow_path(app_joint_rpc == NULL)) { 428343Smax.romanov@nginx.com goto failed; 429343Smax.romanov@nginx.com } 430343Smax.romanov@nginx.com 4311926Smax.romanov@nginx.com stream = nxt_port_rpc_ex_stream(app_joint_rpc); 4321926Smax.romanov@nginx.com 4331488St.nateldemoura@f5.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS, 4341488St.nateldemoura@f5.com -1, stream, port->id, b); 435648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 436648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 437753Smax.romanov@nginx.com 438648Svbart@nginx.com goto failed; 439648Svbart@nginx.com } 440343Smax.romanov@nginx.com 4411926Smax.romanov@nginx.com app_joint_rpc->app_joint = app->joint; 4421926Smax.romanov@nginx.com app_joint_rpc->generation = app->generation; 4431926Smax.romanov@nginx.com 4441926Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 4451926Smax.romanov@nginx.com 446753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 447753Smax.romanov@nginx.com 448343Smax.romanov@nginx.com return; 449343Smax.romanov@nginx.com 450343Smax.romanov@nginx.com failed: 451343Smax.romanov@nginx.com 452648Svbart@nginx.com if (b != NULL) { 453648Svbart@nginx.com mp = b->data; 454648Svbart@nginx.com nxt_mp_free(mp, b); 455648Svbart@nginx.com nxt_mp_release(mp); 456648Svbart@nginx.com } 457648Svbart@nginx.com 458343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 459343Smax.romanov@nginx.com 460507Smax.romanov@nginx.com app->pending_processes--; 461343Smax.romanov@nginx.com 462343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 463343Smax.romanov@nginx.com 464343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 465167Smax.romanov@nginx.com } 466167Smax.romanov@nginx.com 467167Smax.romanov@nginx.com 468753Smax.romanov@nginx.com static void 469753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 470753Smax.romanov@nginx.com { 471753Smax.romanov@nginx.com app_joint->use_count += i; 472753Smax.romanov@nginx.com 473753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 474753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 475753Smax.romanov@nginx.com 476753Smax.romanov@nginx.com nxt_free(app_joint); 477753Smax.romanov@nginx.com } 478753Smax.romanov@nginx.com } 479753Smax.romanov@nginx.com 480753Smax.romanov@nginx.com 481343Smax.romanov@nginx.com static nxt_int_t 482507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 483141Smax.romanov@nginx.com { 484343Smax.romanov@nginx.com nxt_int_t res; 485343Smax.romanov@nginx.com nxt_port_t *router_port; 486343Smax.romanov@nginx.com nxt_runtime_t *rt; 487343Smax.romanov@nginx.com 4881549Smax.romanov@nginx.com nxt_debug(task, "app '%V' start process", &app->name); 4891549Smax.romanov@nginx.com 490343Smax.romanov@nginx.com rt = task->thread->runtime; 491343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 492343Smax.romanov@nginx.com 493343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 494343Smax.romanov@nginx.com 495507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 496343Smax.romanov@nginx.com app); 497343Smax.romanov@nginx.com 498343Smax.romanov@nginx.com if (res == NXT_OK) { 499343Smax.romanov@nginx.com return res; 500318Smax.romanov@nginx.com } 501318Smax.romanov@nginx.com 502343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 503343Smax.romanov@nginx.com 504507Smax.romanov@nginx.com app->pending_processes--; 505343Smax.romanov@nginx.com 506343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 507343Smax.romanov@nginx.com 508343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 509343Smax.romanov@nginx.com 510343Smax.romanov@nginx.com return NXT_ERROR; 511318Smax.romanov@nginx.com } 512318Smax.romanov@nginx.com 513318Smax.romanov@nginx.com 514423Smax.romanov@nginx.com nxt_inline nxt_bool_t 5151555Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data) 516423Smax.romanov@nginx.com { 5171555Smax.romanov@nginx.com nxt_buf_t *b, *next; 5181555Smax.romanov@nginx.com nxt_bool_t cancelled; 5191926Smax.romanov@nginx.com nxt_port_t *app_port; 5201555Smax.romanov@nginx.com nxt_msg_info_t *msg_info; 5211555Smax.romanov@nginx.com 5221555Smax.romanov@nginx.com msg_info = &req_rpc_data->msg_info; 523423Smax.romanov@nginx.com 524423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 525423Smax.romanov@nginx.com return 0; 526423Smax.romanov@nginx.com } 527423Smax.romanov@nginx.com 5281926Smax.romanov@nginx.com app_port = req_rpc_data->app_port; 5291926Smax.romanov@nginx.com 5301926Smax.romanov@nginx.com if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) { 5311926Smax.romanov@nginx.com cancelled = nxt_app_queue_cancel(app_port->queue, 5321926Smax.romanov@nginx.com msg_info->tracking_cookie, 5331926Smax.romanov@nginx.com req_rpc_data->stream); 5341926Smax.romanov@nginx.com 5351926Smax.romanov@nginx.com if (cancelled) { 5361926Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", 5371926Smax.romanov@nginx.com req_rpc_data->stream); 5381926Smax.romanov@nginx.com } 5391926Smax.romanov@nginx.com 5401926Smax.romanov@nginx.com } else { 5411926Smax.romanov@nginx.com cancelled = 0; 542423Smax.romanov@nginx.com } 543423Smax.romanov@nginx.com 544423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 545423Smax.romanov@nginx.com next = b->next; 5461269Sigor@sysoev.ru b->next = NULL; 547423Smax.romanov@nginx.com 548423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 549423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 550423Smax.romanov@nginx.com } 5511829Smax.romanov@nginx.com 5521829Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 553423Smax.romanov@nginx.com } 554423Smax.romanov@nginx.com 555423Smax.romanov@nginx.com msg_info->buf = NULL; 556423Smax.romanov@nginx.com 557423Smax.romanov@nginx.com return cancelled; 558423Smax.romanov@nginx.com } 559423Smax.romanov@nginx.com 560423Smax.romanov@nginx.com 561425Smax.romanov@nginx.com nxt_inline nxt_bool_t 562425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 563425Smax.romanov@nginx.com { 564425Smax.romanov@nginx.com if (lnk->next != NULL) { 565425Smax.romanov@nginx.com nxt_queue_remove(lnk); 566425Smax.romanov@nginx.com 567425Smax.romanov@nginx.com lnk->next = NULL; 568425Smax.romanov@nginx.com 569425Smax.romanov@nginx.com return 1; 570425Smax.romanov@nginx.com } 571425Smax.romanov@nginx.com 572425Smax.romanov@nginx.com return 0; 573425Smax.romanov@nginx.com } 574425Smax.romanov@nginx.com 575425Smax.romanov@nginx.com 576343Smax.romanov@nginx.com nxt_inline void 5771123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task, 5781123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 579343Smax.romanov@nginx.com { 5801561Smax.romanov@nginx.com nxt_app_t *app; 5811561Smax.romanov@nginx.com nxt_bool_t unlinked; 5821547Smax.romanov@nginx.com nxt_http_request_t *r; 5831547Smax.romanov@nginx.com 5841555Smax.romanov@nginx.com nxt_router_msg_cancel(task, req_rpc_data); 5851123Smax.romanov@nginx.com 586*1978Smax.romanov@nginx.com app = req_rpc_data->app; 587*1978Smax.romanov@nginx.com 5881123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 589*1978Smax.romanov@nginx.com nxt_router_app_port_release(task, app, req_rpc_data->app_port, 5901123Smax.romanov@nginx.com req_rpc_data->apr_action); 5911123Smax.romanov@nginx.com 5921123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 5931123Smax.romanov@nginx.com } 5941123Smax.romanov@nginx.com 5951547Smax.romanov@nginx.com r = req_rpc_data->request; 5961547Smax.romanov@nginx.com 5971547Smax.romanov@nginx.com if (r != NULL) { 5981547Smax.romanov@nginx.com r->timer_data = NULL; 5991547Smax.romanov@nginx.com 6001547Smax.romanov@nginx.com nxt_router_http_request_release_post(task, r); 6011547Smax.romanov@nginx.com 6021547Smax.romanov@nginx.com r->req_rpc_data = NULL; 6031123Smax.romanov@nginx.com req_rpc_data->request = NULL; 6041561Smax.romanov@nginx.com 6051561Smax.romanov@nginx.com if (app != NULL) { 6061561Smax.romanov@nginx.com unlinked = 0; 6071561Smax.romanov@nginx.com 6081561Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 6091561Smax.romanov@nginx.com 6101561Smax.romanov@nginx.com if (r->app_link.next != NULL) { 6111561Smax.romanov@nginx.com nxt_queue_remove(&r->app_link); 6121561Smax.romanov@nginx.com r->app_link.next = NULL; 6131561Smax.romanov@nginx.com 6141561Smax.romanov@nginx.com unlinked = 1; 6151561Smax.romanov@nginx.com } 6161561Smax.romanov@nginx.com 6171561Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 6181561Smax.romanov@nginx.com 6191561Smax.romanov@nginx.com if (unlinked) { 6201561Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 6211561Smax.romanov@nginx.com } 6221561Smax.romanov@nginx.com } 6231561Smax.romanov@nginx.com } 6241561Smax.romanov@nginx.com 6251561Smax.romanov@nginx.com if (app != NULL) { 6261561Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 6271561Smax.romanov@nginx.com 6281561Smax.romanov@nginx.com req_rpc_data->app = NULL; 629346Smax.romanov@nginx.com } 6301547Smax.romanov@nginx.com 6311547Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1) { 6321547Smax.romanov@nginx.com nxt_fd_close(req_rpc_data->msg_info.body_fd); 6331547Smax.romanov@nginx.com 6341547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 6351547Smax.romanov@nginx.com } 6361547Smax.romanov@nginx.com 6371547Smax.romanov@nginx.com if (req_rpc_data->rpc_cancel) { 6381547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 6391547Smax.romanov@nginx.com 6401547Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, 6411547Smax.romanov@nginx.com req_rpc_data->stream); 6421547Smax.romanov@nginx.com } 643343Smax.romanov@nginx.com } 644343Smax.romanov@nginx.com 645343Smax.romanov@nginx.com 6461552Smax.romanov@nginx.com static void 647141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 648141Smax.romanov@nginx.com { 6491555Smax.romanov@nginx.com nxt_int_t res; 6501547Smax.romanov@nginx.com nxt_app_t *app; 6511547Smax.romanov@nginx.com nxt_port_t *port, *main_app_port; 6521547Smax.romanov@nginx.com nxt_runtime_t *rt; 6531547Smax.romanov@nginx.com 654141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 655141Smax.romanov@nginx.com 6561547Smax.romanov@nginx.com port = msg->u.new_port; 6571547Smax.romanov@nginx.com 6581547Smax.romanov@nginx.com if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) { 659662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 660662Smax.romanov@nginx.com } 661662Smax.romanov@nginx.com 6621547Smax.romanov@nginx.com if (port == NULL || port->type != NXT_PROCESS_APP) { 6631547Smax.romanov@nginx.com 6641547Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 6651547Smax.romanov@nginx.com return; 6661547Smax.romanov@nginx.com } 6671547Smax.romanov@nginx.com 6681547Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 6691555Smax.romanov@nginx.com 6701555Smax.romanov@nginx.com } else { 6711558Smax.romanov@nginx.com if (msg->fd[1] != -1) { 6721558Smax.romanov@nginx.com res = nxt_router_port_queue_map(task, port, msg->fd[1]); 6731555Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 6741555Smax.romanov@nginx.com return; 6751555Smax.romanov@nginx.com } 6761555Smax.romanov@nginx.com 6771558Smax.romanov@nginx.com nxt_fd_close(msg->fd[1]); 6781558Smax.romanov@nginx.com msg->fd[1] = -1; 6791555Smax.romanov@nginx.com } 6801547Smax.romanov@nginx.com } 6811547Smax.romanov@nginx.com 6821547Smax.romanov@nginx.com if (msg->port_msg.stream != 0) { 6831547Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 684141Smax.romanov@nginx.com return; 685141Smax.romanov@nginx.com } 686141Smax.romanov@nginx.com 6871547Smax.romanov@nginx.com /* 6881547Smax.romanov@nginx.com * Port with "id == 0" is application 'main' port and it always 6891547Smax.romanov@nginx.com * should come with non-zero stream. 6901547Smax.romanov@nginx.com */ 6911547Smax.romanov@nginx.com nxt_assert(port->id != 0); 6921547Smax.romanov@nginx.com 6931547Smax.romanov@nginx.com /* Find 'main' app port and get app reference. */ 6941547Smax.romanov@nginx.com rt = task->thread->runtime; 6951547Smax.romanov@nginx.com 6961547Smax.romanov@nginx.com /* 6971547Smax.romanov@nginx.com * It is safe to access 'runtime->ports' hash because 'NEW_PORT' 6981547Smax.romanov@nginx.com * sent to main port (with id == 0) and processed in main thread. 6991547Smax.romanov@nginx.com */ 7001547Smax.romanov@nginx.com main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0); 7011547Smax.romanov@nginx.com nxt_assert(main_app_port != NULL); 7021547Smax.romanov@nginx.com 7031547Smax.romanov@nginx.com app = main_app_port->app; 7041915Smax.romanov@nginx.com 7051915Smax.romanov@nginx.com if (nxt_fast_path(app != NULL)) { 7061915Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 7071915Smax.romanov@nginx.com 7081915Smax.romanov@nginx.com /* TODO here should be find-and-add code because there can be 7091915Smax.romanov@nginx.com port waiters in port_hash */ 7101915Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 7111915Smax.romanov@nginx.com app->port_hash_count++; 7121915Smax.romanov@nginx.com 7131915Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 7141915Smax.romanov@nginx.com 7151915Smax.romanov@nginx.com port->app = app; 716