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 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 { 451885Sa.suvorov@f5.com nxt_str_t name; 461885Sa.suvorov@f5.com nxt_socket_conf_t *socket_conf; 471885Sa.suvorov@f5.com nxt_router_temp_conf_t *temp_conf; 481920Sa.suvorov@f5.com nxt_tls_init_t *tls_init; 491885Sa.suvorov@f5.com nxt_bool_t last; 50774Svbart@nginx.com 511920Sa.suvorov@f5.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 52774Svbart@nginx.com } nxt_router_tlssock_t; 53774Svbart@nginx.com 54774Svbart@nginx.com #endif 55774Svbart@nginx.com 56774Svbart@nginx.com 57198Sigor@sysoev.ru typedef struct { 581828Sa.suvorov@f5.com nxt_str_t *name; 59198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 60198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 611828Sa.suvorov@f5.com nxt_bool_t last; 62198Sigor@sysoev.ru } nxt_socket_rpc_t; 63198Sigor@sysoev.ru 64198Sigor@sysoev.ru 65507Smax.romanov@nginx.com typedef struct { 66507Smax.romanov@nginx.com nxt_app_t *app; 67507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 68*1998St.nateldemoura@f5.com uint8_t proto; /* 1 bit */ 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; 75*1998St.nateldemoura@f5.com uint8_t proto; /* 1 bit */ 761926Smax.romanov@nginx.com } nxt_app_joint_rpc_t; 771926Smax.romanov@nginx.com 781926Smax.romanov@nginx.com 791488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, 801488St.nateldemoura@f5.com nxt_mp_t *mp); 811488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data); 82662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 83662Smax.romanov@nginx.com nxt_port_t *controller_port); 84662Smax.romanov@nginx.com 85507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 86425Smax.romanov@nginx.com 871552Smax.romanov@nginx.com static void nxt_router_new_port_handler(nxt_task_t *task, 881552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 891552Smax.romanov@nginx.com static void nxt_router_conf_data_handler(nxt_task_t *task, 901552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 911926Smax.romanov@nginx.com static void nxt_router_app_restart_handler(nxt_task_t *task, 921926Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 931552Smax.romanov@nginx.com static void nxt_router_remove_pid_handler(nxt_task_t *task, 941552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 951552Smax.romanov@nginx.com static void nxt_router_access_log_reopen_handler(nxt_task_t *task, 961552Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 971552Smax.romanov@nginx.com 98139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 99198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 100198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 101139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 102139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 103139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 104139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 105193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 10653Sigor@sysoev.ru 107115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 108115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 1091183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 1101183Svbart@nginx.com nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); 1111936So.canty@f5.com static nxt_int_t nxt_router_conf_process_client_ip(nxt_task_t *task, 1121936So.canty@f5.com nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf, 1131936So.canty@f5.com nxt_conf_value_t *conf); 1141563Svbart@nginx.com 115133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 1161563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data); 1171563Svbart@nginx.com static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, 1181563Svbart@nginx.com nxt_app_t *app); 1191563Svbart@nginx.com static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, 1201563Svbart@nginx.com nxt_str_t *name); 1211563Svbart@nginx.com static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, 1221563Svbart@nginx.com int i); 1231563Svbart@nginx.com 1241555Smax.romanov@nginx.com static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task, 1251555Smax.romanov@nginx.com nxt_port_t *port); 1261555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task, 1271555Smax.romanov@nginx.com nxt_port_t *port); 1281555Smax.romanov@nginx.com static nxt_int_t nxt_router_port_queue_map(nxt_task_t *task, 1291555Smax.romanov@nginx.com nxt_port_t *port, nxt_fd_t fd); 130198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 131198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 132198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 133198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 134198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 135198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 136774Svbart@nginx.com #if (NXT_TLS) 137774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task, 138774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 1391828Sa.suvorov@f5.com static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, 1401920Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init, 1411920Sa.suvorov@f5.com nxt_bool_t last); 142774Svbart@nginx.com #endif 143507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 144507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 145507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 146507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 147507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 148507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 149359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 150359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 151359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 152359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 15353Sigor@sysoev.ru 15453Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 15553Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 15653Sigor@sysoev.ru const nxt_event_interface_t *interface); 157115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 158115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 159115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 160115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 161115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 162115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 163154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 164154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 165154Sigor@sysoev.ru nxt_work_handler_t handler); 166313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 167313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 168139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 169139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 17053Sigor@sysoev.ru 17153Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 17253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17353Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 17453Sigor@sysoev.ru nxt_event_engine_t *engine); 175343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 176133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17753Sigor@sysoev.ru 178315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 179315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 180315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 181315Sigor@sysoev.ru nxt_work_t *jobs); 18253Sigor@sysoev.ru 18353Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 1841545Smax.romanov@nginx.com static void nxt_router_rt_add_port(nxt_task_t *task, void *obj, 1851545Smax.romanov@nginx.com void *data); 18653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 18753Sigor@sysoev.ru void *data); 18853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 18953Sigor@sysoev.ru void *data); 19053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 19153Sigor@sysoev.ru void *data); 192313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 193313Sigor@sysoev.ru void *data); 19453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 19553Sigor@sysoev.ru void *data); 19653Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 19753Sigor@sysoev.ru void *data); 1981547Smax.romanov@nginx.com static void nxt_router_req_headers_ack_handler(nxt_task_t *task, 1991547Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data); 200359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 201359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 20253Sigor@sysoev.ru 203630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 204630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 205630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 206630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 207630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 208630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 209630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 210630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 211630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 212630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 213630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 214630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 215651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 216651Svbart@nginx.com void *data); 217631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 218631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 219631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 220631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 221630Svbart@nginx.com 222343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 223343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 2241547Smax.romanov@nginx.com static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task, 2251547Smax.romanov@nginx.com nxt_port_t *app_port); 226343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 227343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 228343Smax.romanov@nginx.com 2291563Svbart@nginx.com static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i); 230753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 2311123Smax.romanov@nginx.com 2321978Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, 2331978Smax.romanov@nginx.com nxt_port_t *port, nxt_apr_action_t action); 2341547Smax.romanov@nginx.com static void nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, 2351547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2361561Smax.romanov@nginx.com static void nxt_router_http_request_error(nxt_task_t *task, void *obj, 2371561Smax.romanov@nginx.com void *data); 2381547Smax.romanov@nginx.com static void nxt_router_http_request_done(nxt_task_t *task, void *obj, 2391547Smax.romanov@nginx.com void *data); 240141Smax.romanov@nginx.com 241425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 2421547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data); 2431007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 2441547Smax.romanov@nginx.com nxt_http_request_t *r, nxt_app_t *app, const nxt_str_t *prefix); 245510Salexander.borisov@nginx.com 246318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 247507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 248507Smax.romanov@nginx.com void *data); 249507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 250507Smax.romanov@nginx.com void *data); 251753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 252507Smax.romanov@nginx.com void *data); 253753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 254431Sigor@sysoev.ru 255431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 256431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 257141Smax.romanov@nginx.com 258753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 259753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 260753Smax.romanov@nginx.com 2611547Smax.romanov@nginx.com static void nxt_router_http_request_release_post(nxt_task_t *task, 2621007Salexander.borisov@nginx.com nxt_http_request_t *r); 2631007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 2641007Salexander.borisov@nginx.com void *data); 2651321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 2661545Smax.romanov@nginx.com static void nxt_router_get_port_handler(nxt_task_t *task, 2671545Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2681546Smax.romanov@nginx.com static void nxt_router_get_mmap_handler(nxt_task_t *task, 2691546Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 2701007Salexander.borisov@nginx.com 2711149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2721131Smax.romanov@nginx.com 273119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 27420Sigor@sysoev.ru 275743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 276743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 277743Smax.romanov@nginx.com 278743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 279804Svbart@nginx.com &empty_prefix, 2801594Smax.romanov@nginx.com &empty_prefix, 281743Smax.romanov@nginx.com &http_prefix, 282743Smax.romanov@nginx.com &http_prefix, 283743Smax.romanov@nginx.com &http_prefix, 284977Smax.romanov@gmail.com &empty_prefix, 285216Sigor@sysoev.ru }; 286216Sigor@sysoev.ru 287216Sigor@sysoev.ru 2881488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_router_process_port_handlers = { 2891488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 290662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 2911545Smax.romanov@nginx.com .get_port = nxt_router_get_port_handler, 292662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 293662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2941546Smax.romanov@nginx.com .get_mmap = nxt_router_get_mmap_handler, 295662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 2961926Smax.romanov@nginx.com .app_restart = nxt_router_app_restart_handler, 297662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 298662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 299662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 300662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 3011321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 302662Smax.romanov@nginx.com }; 303662Smax.romanov@nginx.com 304662Smax.romanov@nginx.com 3051488St.nateldemoura@f5.com const nxt_process_init_t nxt_router_process = { 3061488St.nateldemoura@f5.com .name = "router", 3071488St.nateldemoura@f5.com .type = NXT_PROCESS_ROUTER, 3081488St.nateldemoura@f5.com .prefork = nxt_router_prefork, 3091488St.nateldemoura@f5.com .restart = 1, 3101488St.nateldemoura@f5.com .setup = nxt_process_core_setup, 3111488St.nateldemoura@f5.com .start = nxt_router_start, 3121488St.nateldemoura@f5.com .port_handlers = &nxt_router_process_port_handlers, 3131488St.nateldemoura@f5.com .signals = nxt_process_signals, 3141488St.nateldemoura@f5.com }; 3151488St.nateldemoura@f5.com 3161488St.nateldemoura@f5.com 3171509Sigor@sysoev.ru /* Queues of nxt_socket_conf_t */ 3181509Sigor@sysoev.ru nxt_queue_t creating_sockets; 3191509Sigor@sysoev.ru nxt_queue_t pending_sockets; 3201509Sigor@sysoev.ru nxt_queue_t updating_sockets; 3211509Sigor@sysoev.ru nxt_queue_t keeping_sockets; 3221509Sigor@sysoev.ru nxt_queue_t deleting_sockets; 3231509Sigor@sysoev.ru 3241509Sigor@sysoev.ru 3251488St.nateldemoura@f5.com static nxt_int_t 3261488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) 3271488St.nateldemoura@f5.com { 3281488St.nateldemoura@f5.com nxt_runtime_stop_app_processes(task, task->thread->runtime); 3291488St.nateldemoura@f5.com 3301488St.nateldemoura@f5.com return NXT_OK; 3311488St.nateldemoura@f5.com } 3321488St.nateldemoura@f5.com 3331488St.nateldemoura@f5.com 3341488St.nateldemoura@f5.com static nxt_int_t 3351488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data) 33620Sigor@sysoev.ru { 337141Smax.romanov@nginx.com nxt_int_t ret; 338662Smax.romanov@nginx.com nxt_port_t *controller_port; 339141Smax.romanov@nginx.com nxt_router_t *router; 340141Smax.romanov@nginx.com nxt_runtime_t *rt; 341141Smax.romanov@nginx.com 342141Smax.romanov@nginx.com rt = task->thread->runtime; 34353Sigor@sysoev.ru 3441488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "router started"); 3451488St.nateldemoura@f5.com 346771Sigor@sysoev.ru #if (NXT_TLS) 347771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 348771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 349771Sigor@sysoev.ru return NXT_ERROR; 350771Sigor@sysoev.ru } 351771Sigor@sysoev.ru 352771Sigor@sysoev.ru ret = rt->tls->library_init(task); 353771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 354771Sigor@sysoev.ru return ret; 355771Sigor@sysoev.ru } 356771Sigor@sysoev.ru #endif 357771Sigor@sysoev.ru 3581459Smax.romanov@nginx.com ret = nxt_http_init(task); 35988Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 36088Smax.romanov@nginx.com return ret; 36188Smax.romanov@nginx.com } 36288Smax.romanov@nginx.com 36353Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 36453Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 36553Sigor@sysoev.ru return NXT_ERROR; 36653Sigor@sysoev.ru } 36753Sigor@sysoev.ru 36853Sigor@sysoev.ru nxt_queue_init(&router->engines); 36953Sigor@sysoev.ru nxt_queue_init(&router->sockets); 370133Sigor@sysoev.ru nxt_queue_init(&router->apps); 37153Sigor@sysoev.ru 372119Smax.romanov@nginx.com nxt_router = router; 373119Smax.romanov@nginx.com 374662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 375662Smax.romanov@nginx.com if (controller_port != NULL) { 376662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 377662Smax.romanov@nginx.com } 378662Smax.romanov@nginx.com 379115Sigor@sysoev.ru return NXT_OK; 380115Sigor@sysoev.ru } 381115Sigor@sysoev.ru 382115Sigor@sysoev.ru 383343Smax.romanov@nginx.com static void 384662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 385662Smax.romanov@nginx.com { 386662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 387662Smax.romanov@nginx.com -1, 0, 0, NULL); 388662Smax.romanov@nginx.com } 389662Smax.romanov@nginx.com 390662Smax.romanov@nginx.com 391662Smax.romanov@nginx.com static void 392507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 393507Smax.romanov@nginx.com void *data) 394167Smax.romanov@nginx.com { 3951926Smax.romanov@nginx.com size_t size; 3961926Smax.romanov@nginx.com uint32_t stream; 3971926Smax.romanov@nginx.com nxt_int_t ret; 3981926Smax.romanov@nginx.com nxt_app_t *app; 3991926Smax.romanov@nginx.com nxt_buf_t *b; 400*1998St.nateldemoura@f5.com nxt_port_t *dport; 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 406*1998St.nateldemoura@f5.com nxt_thread_mutex_lock(&app->mutex); 407*1998St.nateldemoura@f5.com 408*1998St.nateldemoura@f5.com dport = app->proto_port; 409*1998St.nateldemoura@f5.com 410*1998St.nateldemoura@f5.com nxt_thread_mutex_unlock(&app->mutex); 411*1998St.nateldemoura@f5.com 412*1998St.nateldemoura@f5.com if (dport != NULL) { 413*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 414*1998St.nateldemoura@f5.com 415*1998St.nateldemoura@f5.com b = NULL; 416*1998St.nateldemoura@f5.com 417*1998St.nateldemoura@f5.com } else { 418*1998St.nateldemoura@f5.com if (app->proto_port_requests > 0) { 419*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' %p wait for prototype process", 420*1998St.nateldemoura@f5.com &app->name, app); 421*1998St.nateldemoura@f5.com 422*1998St.nateldemoura@f5.com app->proto_port_requests++; 423*1998St.nateldemoura@f5.com 424*1998St.nateldemoura@f5.com goto skip; 425*1998St.nateldemoura@f5.com } 426*1998St.nateldemoura@f5.com 427*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' %p start prototype process", &app->name, app); 428*1998St.nateldemoura@f5.com 429*1998St.nateldemoura@f5.com rt = task->thread->runtime; 430*1998St.nateldemoura@f5.com dport = rt->port_by_type[NXT_PROCESS_MAIN]; 431*1998St.nateldemoura@f5.com 432*1998St.nateldemoura@f5.com size = app->name.length + 1 + app->conf.length; 433*1998St.nateldemoura@f5.com 434*1998St.nateldemoura@f5.com b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, size, 0); 435*1998St.nateldemoura@f5.com if (nxt_slow_path(b == NULL)) { 436*1998St.nateldemoura@f5.com goto failed; 437*1998St.nateldemoura@f5.com } 438*1998St.nateldemoura@f5.com 439*1998St.nateldemoura@f5.com nxt_buf_cpystr(b, &app->name); 440*1998St.nateldemoura@f5.com *b->mem.free++ = '\0'; 441*1998St.nateldemoura@f5.com nxt_buf_cpystr(b, &app->conf); 442*1998St.nateldemoura@f5.com } 443343Smax.romanov@nginx.com 4441926Smax.romanov@nginx.com app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port, 4451926Smax.romanov@nginx.com nxt_router_app_port_ready, 4461926Smax.romanov@nginx.com nxt_router_app_port_error, 4471926Smax.romanov@nginx.com sizeof(nxt_app_joint_rpc_t)); 4481926Smax.romanov@nginx.com if (nxt_slow_path(app_joint_rpc == NULL)) { 449343Smax.romanov@nginx.com goto failed; 450343Smax.romanov@nginx.com } 451343Smax.romanov@nginx.com 4521926Smax.romanov@nginx.com stream = nxt_port_rpc_ex_stream(app_joint_rpc); 4531926Smax.romanov@nginx.com 454*1998St.nateldemoura@f5.com ret = nxt_port_socket_write(task, dport, NXT_PORT_MSG_START_PROCESS, 4551488St.nateldemoura@f5.com -1, stream, port->id, b); 456648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 457648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 458753Smax.romanov@nginx.com 459648Svbart@nginx.com goto failed; 460648Svbart@nginx.com } 461343Smax.romanov@nginx.com 4621926Smax.romanov@nginx.com app_joint_rpc->app_joint = app->joint; 4631926Smax.romanov@nginx.com app_joint_rpc->generation = app->generation; 464*1998St.nateldemoura@f5.com app_joint_rpc->proto = (b != NULL); 465*1998St.nateldemoura@f5.com 466*1998St.nateldemoura@f5.com if (b != NULL) { 467*1998St.nateldemoura@f5.com app->proto_port_requests++; 468*1998St.nateldemoura@f5.com 469*1998St.nateldemoura@f5.com b = NULL; 470*1998St.nateldemoura@f5.com } 4711926Smax.romanov@nginx.com 4721926Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 4731926Smax.romanov@nginx.com 474343Smax.romanov@nginx.com failed: 475343Smax.romanov@nginx.com 476648Svbart@nginx.com if (b != NULL) { 477*1998St.nateldemoura@f5.com nxt_mp_free(b->data, b); 478*1998St.nateldemoura@f5.com } 479*1998St.nateldemoura@f5.com 480*1998St.nateldemoura@f5.com skip: 481343Smax.romanov@nginx.com 482343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 483167Smax.romanov@nginx.com } 484167Smax.romanov@nginx.com 485167Smax.romanov@nginx.com 486753Smax.romanov@nginx.com static void 487753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 488753Smax.romanov@nginx.com { 489753Smax.romanov@nginx.com app_joint->use_count += i; 490753Smax.romanov@nginx.com 491753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 492753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 493753Smax.romanov@nginx.com 494753Smax.romanov@nginx.com nxt_free(app_joint); 495753Smax.romanov@nginx.com } 496753Smax.romanov@nginx.com } 497753Smax.romanov@nginx.com 498753Smax.romanov@nginx.com 499343Smax.romanov@nginx.com static nxt_int_t 500507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 501141Smax.romanov@nginx.com { 502343Smax.romanov@nginx.com nxt_int_t res; 503343Smax.romanov@nginx.com nxt_port_t *router_port; 504343Smax.romanov@nginx.com nxt_runtime_t *rt; 505343Smax.romanov@nginx.com 5061549Smax.romanov@nginx.com nxt_debug(task, "app '%V' start process", &app->name); 5071549Smax.romanov@nginx.com 508343Smax.romanov@nginx.com rt = task->thread->runtime; 509343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 510343Smax.romanov@nginx.com 511343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 512343Smax.romanov@nginx.com 513507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 514343Smax.romanov@nginx.com app); 515343Smax.romanov@nginx.com 516343Smax.romanov@nginx.com if (res == NXT_OK) { 517343Smax.romanov@nginx.com return res; 518318Smax.romanov@nginx.com } 519318Smax.romanov@nginx.com 520343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 521343Smax.romanov@nginx.com 522507Smax.romanov@nginx.com app->pending_processes--; 523343Smax.romanov@nginx.com 524343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 525343Smax.romanov@nginx.com 526343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 527343Smax.romanov@nginx.com 528343Smax.romanov@nginx.com return NXT_ERROR; 529318Smax.romanov@nginx.com } 530318Smax.romanov@nginx.com 531318Smax.romanov@nginx.com 532423Smax.romanov@nginx.com nxt_inline nxt_bool_t 5331555Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data) 534423Smax.romanov@nginx.com { 5351555Smax.romanov@nginx.com nxt_buf_t *b, *next; 5361555Smax.romanov@nginx.com nxt_bool_t cancelled; 5371926Smax.romanov@nginx.com nxt_port_t *app_port; 5381555Smax.romanov@nginx.com nxt_msg_info_t *msg_info; 5391555Smax.romanov@nginx.com 5401555Smax.romanov@nginx.com msg_info = &req_rpc_data->msg_info; 541423Smax.romanov@nginx.com 542423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 543423Smax.romanov@nginx.com return 0; 544423Smax.romanov@nginx.com } 545423Smax.romanov@nginx.com 5461926Smax.romanov@nginx.com app_port = req_rpc_data->app_port; 5471926Smax.romanov@nginx.com 5481926Smax.romanov@nginx.com if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) { 5491926Smax.romanov@nginx.com cancelled = nxt_app_queue_cancel(app_port->queue, 5501926Smax.romanov@nginx.com msg_info->tracking_cookie, 5511926Smax.romanov@nginx.com req_rpc_data->stream); 5521926Smax.romanov@nginx.com 5531926Smax.romanov@nginx.com if (cancelled) { 5541926Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", 5551926Smax.romanov@nginx.com req_rpc_data->stream); 5561926Smax.romanov@nginx.com } 5571926Smax.romanov@nginx.com 5581926Smax.romanov@nginx.com } else { 5591926Smax.romanov@nginx.com cancelled = 0; 560423Smax.romanov@nginx.com } 561423Smax.romanov@nginx.com 562423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 563423Smax.romanov@nginx.com next = b->next; 5641269Sigor@sysoev.ru b->next = NULL; 565423Smax.romanov@nginx.com 566423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 567423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 568423Smax.romanov@nginx.com } 5691829Smax.romanov@nginx.com 5701829Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 571423Smax.romanov@nginx.com } 572423Smax.romanov@nginx.com 573423Smax.romanov@nginx.com msg_info->buf = NULL; 574423Smax.romanov@nginx.com 575423Smax.romanov@nginx.com return cancelled; 576423Smax.romanov@nginx.com } 577423Smax.romanov@nginx.com 578423Smax.romanov@nginx.com 579425Smax.romanov@nginx.com nxt_inline nxt_bool_t 580425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 581425Smax.romanov@nginx.com { 582425Smax.romanov@nginx.com if (lnk->next != NULL) { 583425Smax.romanov@nginx.com nxt_queue_remove(lnk); 584425Smax.romanov@nginx.com 585425Smax.romanov@nginx.com lnk->next = NULL; 586425Smax.romanov@nginx.com 587425Smax.romanov@nginx.com return 1; 588425Smax.romanov@nginx.com } 589425Smax.romanov@nginx.com 590425Smax.romanov@nginx.com return 0; 591425Smax.romanov@nginx.com } 592425Smax.romanov@nginx.com 593425Smax.romanov@nginx.com 594343Smax.romanov@nginx.com nxt_inline void 5951123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task, 5961123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 597343Smax.romanov@nginx.com { 5981561Smax.romanov@nginx.com nxt_app_t *app; 5991561Smax.romanov@nginx.com nxt_bool_t unlinked; 6001547Smax.romanov@nginx.com nxt_http_request_t *r; 6011547Smax.romanov@nginx.com 6021555Smax.romanov@nginx.com nxt_router_msg_cancel(task, req_rpc_data); 6031123Smax.romanov@nginx.com 6041978Smax.romanov@nginx.com app = req_rpc_data->app; 6051978Smax.romanov@nginx.com 6061123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 6071978Smax.romanov@nginx.com nxt_router_app_port_release(task, app, req_rpc_data->app_port, 6081123Smax.romanov@nginx.com req_rpc_data->apr_action); 6091123Smax.romanov@nginx.com 6101123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 6111123Smax.romanov@nginx.com } 6121123Smax.romanov@nginx.com 6131547Smax.romanov@nginx.com r = req_rpc_data->request; 6141547Smax.romanov@nginx.com 6151547Smax.romanov@nginx.com if (r != NULL) { 6161547Smax.romanov@nginx.com r->timer_data = NULL; 6171547Smax.romanov@nginx.com 6181547Smax.romanov@nginx.com nxt_router_http_request_release_post(task, r); 6191547Smax.romanov@nginx.com 6201547Smax.romanov@nginx.com r->req_rpc_data = NULL; 6211123Smax.romanov@nginx.com req_rpc_data->request = NULL; 6221561Smax.romanov@nginx.com 6231561Smax.romanov@nginx.com if (app != NULL) { 6241561Smax.romanov@nginx.com unlinked = 0; 6251561Smax.romanov@nginx.com 6261561Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 6271561Smax.romanov@nginx.com 6281561Smax.romanov@nginx.com if (r->app_link.next != NULL) { 6291561Smax.romanov@nginx.com nxt_queue_remove(&r->app_link); 6301561Smax.romanov@nginx.com r->app_link.next = NULL; 6311561Smax.romanov@nginx.com 6321561Smax.romanov@nginx.com unlinked = 1; 6331561Smax.romanov@nginx.com } 6341561Smax.romanov@nginx.com 6351561Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 6361561Smax.romanov@nginx.com 6371561Smax.romanov@nginx.com if (unlinked) { 6381561Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 6391561Smax.romanov@nginx.com } 6401561Smax.romanov@nginx.com } 6411561Smax.romanov@nginx.com } 6421561Smax.romanov@nginx.com 6431561Smax.romanov@nginx.com if (app != NULL) { 6441561Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 6451561Smax.romanov@nginx.com 6461561Smax.romanov@nginx.com req_rpc_data->app = NULL; 647346Smax.romanov@nginx.com } 6481547Smax.romanov@nginx.com 6491547Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1) { 6501547Smax.romanov@nginx.com nxt_fd_close(req_rpc_data->msg_info.body_fd); 6511547Smax.romanov@nginx.com 6521547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 6531547Smax.romanov@nginx.com } 6541547Smax.romanov@nginx.com 6551547Smax.romanov@nginx.com if (req_rpc_data->rpc_cancel) { 6561547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 6571547Smax.romanov@nginx.com 6581547Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, 6591547Smax.romanov@nginx.com req_rpc_data->stream); 6601547Smax.romanov@nginx.com } 661343Smax.romanov@nginx.com } 662343Smax.romanov@nginx.com 663343Smax.romanov@nginx.com 6641552Smax.romanov@nginx.com static void 665141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 666141Smax.romanov@nginx.com { 6671555Smax.romanov@nginx.com nxt_int_t res; 6681547Smax.romanov@nginx.com nxt_app_t *app; 6691547Smax.romanov@nginx.com nxt_port_t *port, *main_app_port; 6701547Smax.romanov@nginx.com nxt_runtime_t *rt; 6711547Smax.romanov@nginx.com 672141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 673141Smax.romanov@nginx.com 6741547Smax.romanov@nginx.com port = msg->u.new_port; 6751547Smax.romanov@nginx.com 6761547Smax.romanov@nginx.com if (port != NULL && port->type == NXT_PROCESS_CONTROLLER) { 677662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 678662Smax.romanov@nginx.com } 679662Smax.romanov@nginx.com 680*1998St.nateldemoura@f5.com if (port != NULL && port->type == NXT_PROCESS_PROTOTYPE) { 681*1998St.nateldemoura@f5.com nxt_port_rpc_handler(task, msg); 682*1998St.nateldemoura@f5.com 683*1998St.nateldemoura@f5.com return; 684*1998St.nateldemoura@f5.com } 685*1998St.nateldemoura@f5.com 6861547Smax.romanov@nginx.com if (port == NULL || port->type != NXT_PROCESS_APP) { 6871547Smax.romanov@nginx.com 6881547Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 6891547Smax.romanov@nginx.com return; 6901547Smax.romanov@nginx.com } 6911547Smax.romanov@nginx.com 6921547Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 6931555Smax.romanov@nginx.com 6941555Smax.romanov@nginx.com } else { 6951558Smax.romanov@nginx.com if (msg->fd[1] != -1) { 6961558Smax.romanov@nginx.com res = nxt_router_port_queue_map(task, port, msg->fd[1]); 6971555Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 6981555Smax.romanov@nginx.com return; 6991555Smax.romanov@nginx.com } 7001555Smax.romanov@nginx.com 7011558Smax.romanov@nginx.com nxt_fd_close(msg->fd[1]); 7021558Smax.romanov@nginx.com msg->fd[1] = -1; 7031555Smax.romanov@nginx.com } 7041547Smax.romanov@nginx.com } 7051547Smax.romanov@nginx.com 7061547Smax.romanov@nginx.com if (msg->port_msg.stream != 0) { 7071547Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 708141Smax.romanov@nginx.com return; 709141Smax.romanov@nginx.com } 710141Smax.romanov@nginx.com 711*1998St.nateldemoura@f5.com nxt_debug(task, "new port id %d (%d)", port->id, port->type); 712*1998St.nateldemoura@f5.com 7131547Smax.romanov@nginx.com /* 7141547Smax.romanov@nginx.com * Port with "id == 0" is application 'main' port and it always 7151547Smax.romanov@nginx.com * should come with non-zero stream. 7161547Smax.romanov@nginx.com */ 7171547Smax.romanov@nginx.com nxt_assert(port->id != 0); 7181547Smax.romanov@nginx.com 7191547Smax.romanov@nginx.com /* Find 'main' app port and get app reference. */ 7201547Smax.romanov@nginx.com rt = task->thread->runtime; 7211547Smax.romanov@nginx.com 7221547Smax.romanov@nginx.com /* 7231547Smax.romanov@nginx.com * It is safe to access 'runtime->ports' hash because 'NEW_PORT' 7241547Smax.romanov@nginx.com * sent to main port (with id == 0) and processed in main thread. 7251547Smax.romanov@nginx.com */ 7261547Smax.romanov@nginx.com main_app_port = nxt_port_hash_find(&rt->ports, port->pid, 0); 7271547Smax.romanov@nginx.com nxt_assert(main_app_port != NULL); 7281547Smax.romanov@nginx.com 7291547Smax.romanov@nginx.com app = main_app_port->app; 7301915Smax.romanov@nginx.com 7311915Smax.romanov@nginx.com if (nxt_fast_path(app != NULL)) { 7321915Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 7331915Smax.romanov@nginx.com 7341915Smax.romanov@nginx.com /* TODO here should be find-and-add code because there can be 7351915Smax.romanov@nginx.com port waiters in port_hash */ 7361915Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 7371915Smax.romanov@nginx.com app->port_hash_count++; 7381915Smax.romanov@nginx.com 7391915Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 7401915Smax.romanov@nginx.com 7411915Smax.romanov@nginx.com port->app = app; 7421915Smax.romanov@nginx.com } 7431915Smax.romanov@nginx.com 7441547Smax.romanov@nginx.com port->main_app_port = main_app_port; 7451666Smax.romanov@nginx.com 7461666Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL); 747141Smax.romanov@nginx.com } 748141Smax.romanov@nginx.com 749141Smax.romanov@nginx.com 7501552Smax.romanov@nginx.com static void 751139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 752115Sigor@sysoev.ru { 7531526Smax.romanov@nginx.com void *p; 7541526Smax.romanov@nginx.com size_t size; 755198Sigor@sysoev.ru nxt_int_t ret; 7561779Smax.romanov@nginx.com nxt_port_t *port; 757139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 758139Sigor@sysoev.ru 7591779Smax.romanov@nginx.com port = nxt_runtime_port_find(task->thread->runtime, 7601779Smax.romanov@nginx.com msg->port_msg.pid, 7611779Smax.romanov@nginx.com msg->port_msg.reply_port); 7621779Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 7631779Smax.romanov@nginx.com nxt_alert(task, "conf_data_handler: reply port not found"); 7641779Smax.romanov@nginx.com return; 7651779Smax.romanov@nginx.com } 7661779Smax.romanov@nginx.com 7671779Smax.romanov@nginx.com p = MAP_FAILED; 7681779Smax.romanov@nginx.com 7691779Smax.romanov@nginx.com /* 7701779Smax.romanov@nginx.com * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be 7711779Smax.romanov@nginx.com * initialized in 'cleanup' section. 7721779Smax.romanov@nginx.com */ 7731779Smax.romanov@nginx.com size = 0; 7741779Smax.romanov@nginx.com 775139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 776139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 7771779Smax.romanov@nginx.com goto fail; 77853Sigor@sysoev.ru } 77953Sigor@sysoev.ru 7801558Smax.romanov@nginx.com if (nxt_slow_path(msg->fd[0] == -1)) { 7811779Smax.romanov@nginx.com nxt_alert(task, "conf_data_handler: invalid shm fd"); 7821779Smax.romanov@nginx.com goto fail; 7831526Smax.romanov@nginx.com } 7841526Smax.romanov@nginx.com 7851526Smax.romanov@nginx.com if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) { 7861526Smax.romanov@nginx.com nxt_alert(task, "conf_data_handler: unexpected buffer size (%d)", 7871526Smax.romanov@nginx.com (int) nxt_buf_mem_used_size(&msg->buf->mem)); 7881779Smax.romanov@nginx.com goto fail; 7891526Smax.romanov@nginx.com } 7901526Smax.romanov@nginx.com 7911526Smax.romanov@nginx.com nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t)); 7921526Smax.romanov@nginx.com 7931558Smax.romanov@nginx.com p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0); 7941558Smax.romanov@nginx.com 7951558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 7961558Smax.romanov@nginx.com msg->fd[0] = -1; 7971526Smax.romanov@nginx.com 7981526Smax.romanov@nginx.com if (nxt_slow_path(p == MAP_FAILED)) { 7991779Smax.romanov@nginx.com goto fail; 8001526Smax.romanov@nginx.com } 8011526Smax.romanov@nginx.com 8021526Smax.romanov@nginx.com nxt_debug(task, "conf_data_handler(%uz): %*s", size, size, p); 803423Smax.romanov@nginx.com 804591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 805139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 8061779Smax.romanov@nginx.com tmcf->port = port; 807779Smax.romanov@nginx.com 808779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 809779Smax.romanov@nginx.com 8101526Smax.romanov@nginx.com ret = nxt_router_conf_create(task, tmcf, p, nxt_pointer_to(p, size)); 811198Sigor@sysoev.ru 812198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 813198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 814198Sigor@sysoev.ru 815198Sigor@sysoev.ru } else { 816198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 817139Sigor@sysoev.ru } 8181526Smax.romanov@nginx.com 8191779Smax.romanov@nginx.com goto cleanup; 8201779Smax.romanov@nginx.com 8211526Smax.romanov@nginx.com fail: 8221526Smax.romanov@nginx.com 8231779Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, 8241779Smax.romanov@nginx.com msg->port_msg.stream, 0, NULL); 8251779Smax.romanov@nginx.com 8261779Smax.romanov@nginx.com if (tmcf != NULL) { 8271869Sa.suvorov@f5.com nxt_mp_release(tmcf->mem_pool); 8281779Smax.romanov@nginx.com } 8291779Smax.romanov@nginx.com 8301779Smax.romanov@nginx.com cleanup: 8311779Smax.romanov@nginx.com 8321779Smax.romanov@nginx.com if (p != MAP_FAILED) { 8331779Smax.romanov@nginx.com nxt_mem_munmap(p, size); 8341779Smax.romanov@nginx.com } 8351779Smax.romanov@nginx.com 8361779Smax.romanov@nginx.com if (msg->fd[0] != -1) { 8371779Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 8381779Smax.romanov@nginx.com msg->fd[0] = -1; 8391779Smax.romanov@nginx.com } 84053Sigor@sysoev.ru } 84153Sigor@sysoev.ru 84253Sigor@sysoev.ru 843347Smax.romanov@nginx.com static void 8441926Smax.romanov@nginx.com nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 8451926Smax.romanov@nginx.com { 8461926Smax.romanov@nginx.com nxt_app_t *app; 8471926Smax.romanov@nginx.com nxt_int_t ret; 8481926Smax.romanov@nginx.com nxt_str_t app_name; 849*1998St.nateldemoura@f5.com nxt_port_t *reply_port, *shared_port, *old_shared_port; 850*1998St.nateldemoura@f5.com nxt_port_t *proto_port; 8511926Smax.romanov@nginx.com nxt_port_msg_type_t reply; 8521926Smax.romanov@nginx.com 8531926Smax.romanov@nginx.com reply_port = nxt_runtime_port_find(task->thread->runtime, 8541926Smax.romanov@nginx.com msg->port_msg.pid, 8551926Smax.romanov@nginx.com msg->port_msg.reply_port); 8561926Smax.romanov@nginx.com if (nxt_slow_path(reply_port == NULL)) { 8571926Smax.romanov@nginx.com nxt_alert(task, "app_restart_handler: reply port not found"); 8581926Smax.romanov@nginx.com return; 8591926Smax.romanov@nginx.com } 8601926Smax.romanov@nginx.com 8611926Smax.romanov@nginx.com app_name.length = nxt_buf_mem_used_size(&msg->buf->mem); 8621926Smax.romanov@nginx.com app_name.start = msg->buf->mem.pos; 8631926Smax.romanov@nginx.com 8641926Smax.romanov@nginx.com nxt_debug(task, "app_restart_handler: %V", &app_name); 8651926Smax.romanov@nginx.com 8661926Smax.romanov@nginx.com app = nxt_router_app_find(&nxt_router->apps, &app_name); 8671926Smax.romanov@nginx.com 8681926Smax.romanov@nginx.com if (nxt_fast_path(app != NULL)) { 8691926Smax.romanov@nginx.com shared_port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid, 8701926Smax.romanov@nginx.com NXT_PROCESS_APP); 8711926Smax.romanov@nginx.com if (nxt_slow_path(shared_port == NULL)) { 8721926Smax.romanov@nginx.com goto fail; 8731926Smax.romanov@nginx.com } 8741926Smax.romanov@nginx.com 8751926Smax.romanov@nginx.com ret = nxt_port_socket_init(task, shared_port, 0); 8761926Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 8771926Smax.romanov@nginx.com nxt_port_use(task, shared_port, -1); 8781926Smax.romanov@nginx.com goto fail; 8791926Smax.romanov@nginx.com } 8801926Smax.romanov@nginx.com 8811926Smax.romanov@nginx.com ret = nxt_router_app_queue_init(task, shared_port); 8821926Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 8831926Smax.romanov@nginx.com nxt_port_write_close(shared_port); 8841926Smax.romanov@nginx.com nxt_port_read_close(shared_port); 8851926Smax.romanov@nginx.com nxt_port_use(task, shared_port, -1); 8861926Smax.romanov@nginx.com goto fail; 8871926Smax.romanov@nginx.com } 8881926Smax.romanov@nginx.com 8891926Smax.romanov@nginx.com nxt_port_write_enable(task, shared_port); 8901926Smax.romanov@nginx.com 8911926Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 8921926Smax.romanov@nginx.com 893*1998St.nateldemoura@f5.com proto_port = app->proto_port; 894*1998St.nateldemoura@f5.com 895*1998St.nateldemoura@f5.com if (proto_port != NULL) { 896*1998St.nateldemoura@f5.com nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name, 897*1998St.nateldemoura@f5.com proto_port->pid); 898*1998St.nateldemoura@f5.com 899*1998St.nateldemoura@f5.com app->proto_port = NULL; 900*1998St.nateldemoura@f5.com proto_port->app = NULL; 901*1998St.nateldemoura@f5.com } 9021926Smax.romanov@nginx.com 9031926Smax.romanov@nginx.com app->generation++; 9041926Smax.romanov@nginx.com 9051926Smax.romanov@nginx.com shared_port->app = app; 9061926Smax.romanov@nginx.com 9071926Smax.romanov@nginx.com old_shared_port = app->shared_port; 9081926Smax.romanov@nginx.com old_shared_port->app = NULL; 9091926Smax.romanov@nginx.com 9101926Smax.romanov@nginx.com app->shared_port = shared_port; 9111926Smax.romanov@nginx.com 9121926Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 9131926Smax.romanov@nginx.com 9141926Smax.romanov@nginx.com nxt_port_close(task, old_shared_port); 9151926Smax.romanov@nginx.com nxt_port_use(task, old_shared_port, -1); 9161926Smax.romanov@nginx.com 917*1998St.nateldemoura@f5.com if (proto_port != NULL) { 918*1998St.nateldemoura@f5.com (void) nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT, 919*1998St.nateldemoura@f5.com -1, 0, 0, NULL); 920*1998St.nateldemoura@f5.com 921*1998St.nateldemoura@f5.com nxt_port_close(task, proto_port); 922*1998St.nateldemoura@f5.com 923*1998St.nateldemoura@f5.com nxt_port_use(task, proto_port, -1); 924*1998St.nateldemoura@f5.com } 925*1998St.nateldemoura@f5.com 9261926Smax.romanov@nginx.com reply = NXT_PORT_MSG_RPC_READY_LAST; 9271926Smax.romanov@nginx.com 9281926Smax.romanov@nginx.com } else { 9291926Smax.romanov@nginx.com 9301926Smax.romanov@nginx.com fail: 9311926Smax.romanov@nginx.com 9321926Smax.romanov@nginx.com reply = NXT_PORT_MSG_RPC_ERROR; 9331926Smax.romanov@nginx.com } 9341926Smax.romanov@nginx.com 9351926Smax.romanov@nginx.com nxt_port_socket_write(task, reply_port, reply, -1, msg->port_msg.stream, 9361926Smax.romanov@nginx.com 0, NULL); 9371926Smax.romanov@nginx.com } 9381926Smax.romanov@nginx.com 9391926Smax.romanov@nginx.com 9401926Smax.romanov@nginx.com static void 941507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 942507Smax.romanov@nginx.com void *data) 943347Smax.romanov@nginx.com { 944347Smax.romanov@nginx.com union { 945347Smax.romanov@nginx.com nxt_pid_t removed_pid; 946347Smax.romanov@nginx.com void *data; 947347Smax.romanov@nginx.com } u; 948347Smax.romanov@nginx.com 949347Smax.romanov@nginx.com u.data = data; 950347Smax.romanov@nginx.com 951347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 952347Smax.romanov@nginx.com } 953347Smax.romanov@nginx.com 954347Smax.romanov@nginx.com 9551552Smax.romanov@nginx.com static void 956192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 957192Smax.romanov@nginx.com { 958347Smax.romanov@nginx.com nxt_event_engine_t *engine; 959318Smax.romanov@nginx.com 960192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 961192Smax.romanov@nginx.com 962318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 963318Smax.romanov@nginx.com { 9641486Smax.romanov@nginx.com if (nxt_fast_path(engine->port != NULL)) { 9651486Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 9661486Smax.romanov@nginx.com msg->u.data); 9671486Smax.romanov@nginx.com } 968318Smax.romanov@nginx.com } 969318Smax.romanov@nginx.com nxt_queue_loop; 970318Smax.romanov@nginx.com 9711085Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 9721085Smax.romanov@nginx.com return; 9731085Smax.romanov@nginx.com } 9741085Smax.romanov@nginx.com 975192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 976192Smax.romanov@nginx.com 977192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 978192Smax.romanov@nginx.com } 979192Smax.romanov@nginx.com 980192Smax.romanov@nginx.com 98153Sigor@sysoev.ru static nxt_router_temp_conf_t * 982139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 98353Sigor@sysoev.ru { 98465Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 98553Sigor@sysoev.ru nxt_router_conf_t *rtcf; 98653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 98753Sigor@sysoev.ru 98865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 98953Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 99053Sigor@sysoev.ru return NULL; 99153Sigor@sysoev.ru } 99253Sigor@sysoev.ru 99365Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 99453Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 99553Sigor@sysoev.ru goto fail; 99653Sigor@sysoev.ru } 99753Sigor@sysoev.ru 99853Sigor@sysoev.ru rtcf->mem_pool = mp; 99953Sigor@sysoev.ru 100065Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 100153Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 100253Sigor@sysoev.ru goto fail; 100353Sigor@sysoev.ru } 100453Sigor@sysoev.ru 100565Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 100653Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 100753Sigor@sysoev.ru goto temp_fail; 100853Sigor@sysoev.ru } 100953Sigor@sysoev.ru 101053Sigor@sysoev.ru tmcf->mem_pool = tmp; 1011591Sigor@sysoev.ru tmcf->router_conf = rtcf; 1012139Sigor@sysoev.ru tmcf->count = 1; 1013139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 101453Sigor@sysoev.ru 101553Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 101653Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 101753Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 101853Sigor@sysoev.ru goto temp_fail; 101953Sigor@sysoev.ru } 102053Sigor@sysoev.ru 10211509Sigor@sysoev.ru nxt_queue_init(&creating_sockets); 10221509Sigor@sysoev.ru nxt_queue_init(&pending_sockets); 10231509Sigor@sysoev.ru nxt_queue_init(&updating_sockets); 10241509Sigor@sysoev.ru nxt_queue_init(&keeping_sockets); 10251509Sigor@sysoev.ru nxt_queue_init(&deleting_sockets); 1026416Smax.romanov@nginx.com 1027774Svbart@nginx.com #if (NXT_TLS) 1028774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 1029774Svbart@nginx.com #endif 1030774Svbart@nginx.com 1031133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 1032133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 103353Sigor@sysoev.ru 103453Sigor@sysoev.ru return tmcf; 103553Sigor@sysoev.ru 103653Sigor@sysoev.ru temp_fail: 103753Sigor@sysoev.ru 103865Sigor@sysoev.ru nxt_mp_destroy(tmp); 103953Sigor@sysoev.ru 104053Sigor@sysoev.ru fail: 104153Sigor@sysoev.ru 104265Sigor@sysoev.ru nxt_mp_destroy(mp); 104353Sigor@sysoev.ru 104453Sigor@sysoev.ru return NULL; 104553Sigor@sysoev.ru } 104653Sigor@sysoev.ru 104753Sigor@sysoev.ru 1048507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1049507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 1050507Smax.romanov@nginx.com { 1051507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 1052507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 1053507Smax.romanov@nginx.com } 1054507Smax.romanov@nginx.com 1055507Smax.romanov@nginx.com 1056507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1057507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 1058507Smax.romanov@nginx.com { 10591547Smax.romanov@nginx.com return (app->active_requests 10601547Smax.romanov@nginx.com > app->port_hash_count + app->pending_processes) 10611547Smax.romanov@nginx.com || (app->spare_processes 10621547Smax.romanov@nginx.com > app->idle_processes + app->pending_processes); 1063507Smax.romanov@nginx.com } 1064507Smax.romanov@nginx.com 1065507Smax.romanov@nginx.com 1066198Sigor@sysoev.ru static void 1067198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 1068139Sigor@sysoev.ru { 1069139Sigor@sysoev.ru nxt_int_t ret; 1070507Smax.romanov@nginx.com nxt_app_t *app; 1071139Sigor@sysoev.ru nxt_router_t *router; 1072139Sigor@sysoev.ru nxt_runtime_t *rt; 1073198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1074198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1075630Svbart@nginx.com nxt_router_conf_t *rtcf; 1076198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1077139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1078774Svbart@nginx.com #if (NXT_TLS) 1079774Svbart@nginx.com nxt_router_tlssock_t *tls; 1080774Svbart@nginx.com #endif 1081139Sigor@sysoev.ru 1082198Sigor@sysoev.ru tmcf = obj; 1083198Sigor@sysoev.ru 10841509Sigor@sysoev.ru qlk = nxt_queue_first(&pending_sockets); 10851509Sigor@sysoev.ru 10861509Sigor@sysoev.ru if (qlk != nxt_queue_tail(&pending_sockets)) { 1087198Sigor@sysoev.ru nxt_queue_remove(qlk); 10881509Sigor@sysoev.ru nxt_queue_insert_tail(&creating_sockets, qlk); 1089198Sigor@sysoev.ru 1090198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1091198Sigor@sysoev.ru 1092198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1093198Sigor@sysoev.ru 1094198Sigor@sysoev.ru return; 1095139Sigor@sysoev.ru } 1096139Sigor@sysoev.ru 1097774Svbart@nginx.com #if (NXT_TLS) 10981828Sa.suvorov@f5.com qlk = nxt_queue_last(&tmcf->tls); 10991828Sa.suvorov@f5.com 11001828Sa.suvorov@f5.com if (qlk != nxt_queue_head(&tmcf->tls)) { 1101774Svbart@nginx.com nxt_queue_remove(qlk); 1102774Svbart@nginx.com 1103774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 1104774Svbart@nginx.com 11051885Sa.suvorov@f5.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 11061885Sa.suvorov@f5.com nxt_router_tls_rpc_handler, tls); 1107774Svbart@nginx.com return; 1108774Svbart@nginx.com } 1109774Svbart@nginx.com #endif 1110774Svbart@nginx.com 1111507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1112507Smax.romanov@nginx.com 1113507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1114507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1115507Smax.romanov@nginx.com return; 1116507Smax.romanov@nginx.com } 1117507Smax.romanov@nginx.com 1118507Smax.romanov@nginx.com } nxt_queue_loop; 1119507Smax.romanov@nginx.com 1120630Svbart@nginx.com rtcf = tmcf->router_conf; 1121630Svbart@nginx.com 1122630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1123630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1124630Svbart@nginx.com return; 1125630Svbart@nginx.com } 1126630Svbart@nginx.com 1127139Sigor@sysoev.ru rt = task->thread->runtime; 1128139Sigor@sysoev.ru 1129139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1130139Sigor@sysoev.ru 1131630Svbart@nginx.com router = rtcf->router; 1132198Sigor@sysoev.ru 1133139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1134139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1135198Sigor@sysoev.ru goto fail; 1136139Sigor@sysoev.ru } 1137139Sigor@sysoev.ru 1138139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1139139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1140198Sigor@sysoev.ru goto fail; 1141139Sigor@sysoev.ru } 1142139Sigor@sysoev.ru 1143343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1144139Sigor@sysoev.ru 11451828Sa.suvorov@f5.com nxt_router_apps_hash_use(task, rtcf, 1); 11461563Svbart@nginx.com 1147315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1148139Sigor@sysoev.ru 11491509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &updating_sockets); 11501509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &creating_sockets); 1151139Sigor@sysoev.ru 1152630Svbart@nginx.com router->access_log = rtcf->access_log; 1153630Svbart@nginx.com 1154198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1155198Sigor@sysoev.ru 1156198Sigor@sysoev.ru return; 1157198Sigor@sysoev.ru 1158198Sigor@sysoev.ru fail: 1159198Sigor@sysoev.ru 1160198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1161198Sigor@sysoev.ru 1162198Sigor@sysoev.ru return; 1163139Sigor@sysoev.ru } 1164139Sigor@sysoev.ru 1165139Sigor@sysoev.ru 1166139Sigor@sysoev.ru static void 1167139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1168139Sigor@sysoev.ru { 1169153Sigor@sysoev.ru nxt_joint_job_t *job; 1170153Sigor@sysoev.ru 1171153Sigor@sysoev.ru job = obj; 1172153Sigor@sysoev.ru 1173198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1174139Sigor@sysoev.ru } 1175139Sigor@sysoev.ru 1176139Sigor@sysoev.ru 1177139Sigor@sysoev.ru static void 1178198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1179139Sigor@sysoev.ru { 11801542Smax.romanov@nginx.com uint32_t count; 11811542Smax.romanov@nginx.com nxt_router_conf_t *rtcf; 11821542Smax.romanov@nginx.com nxt_thread_spinlock_t *lock; 11831542Smax.romanov@nginx.com 11841542Smax.romanov@nginx.com nxt_debug(task, "temp conf %p count: %D", tmcf, tmcf->count); 11851542Smax.romanov@nginx.com 11861542Smax.romanov@nginx.com if (--tmcf->count > 0) { 11871542Smax.romanov@nginx.com return; 11881542Smax.romanov@nginx.com } 11891542Smax.romanov@nginx.com 11901542Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 11911542Smax.romanov@nginx.com 11921542Smax.romanov@nginx.com rtcf = tmcf->router_conf; 11931542Smax.romanov@nginx.com 11941542Smax.romanov@nginx.com lock = &rtcf->router->lock; 11951542Smax.romanov@nginx.com 11961542Smax.romanov@nginx.com nxt_thread_spin_lock(lock); 11971542Smax.romanov@nginx.com 11981542Smax.romanov@nginx.com count = rtcf->count; 11991542Smax.romanov@nginx.com 12001542Smax.romanov@nginx.com nxt_thread_spin_unlock(lock); 12011542Smax.romanov@nginx.com 12021542Smax.romanov@nginx.com nxt_debug(task, "rtcf %p: %D", rtcf, count); 12031542Smax.romanov@nginx.com 12041542Smax.romanov@nginx.com if (count == 0) { 12051563Svbart@nginx.com nxt_router_apps_hash_use(task, rtcf, -1); 12061542Smax.romanov@nginx.com 12071542Smax.romanov@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 12081542Smax.romanov@nginx.com 12091542Smax.romanov@nginx.com nxt_mp_destroy(rtcf->mem_pool); 12101542Smax.romanov@nginx.com } 12111542Smax.romanov@nginx.com 12121869Sa.suvorov@f5.com nxt_mp_release(tmcf->mem_pool); 1213139Sigor@sysoev.ru } 1214139Sigor@sysoev.ru 1215139Sigor@sysoev.ru 1216139Sigor@sysoev.ru static void 1217139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1218139Sigor@sysoev.ru { 1219507Smax.romanov@nginx.com nxt_app_t *app; 1220568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1221148Sigor@sysoev.ru nxt_socket_t s; 1222149Sigor@sysoev.ru nxt_router_t *router; 1223148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1224148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1225630Svbart@nginx.com nxt_router_conf_t *rtcf; 1226148Sigor@sysoev.ru 1227564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1228198Sigor@sysoev.ru 12291509Sigor@sysoev.ru for (qlk = nxt_queue_first(&creating_sockets); 12301509Sigor@sysoev.ru qlk != nxt_queue_tail(&creating_sockets); 1231148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1232148Sigor@sysoev.ru { 1233148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1234359Sigor@sysoev.ru s = skcf->listen->socket; 1235148Sigor@sysoev.ru 1236148Sigor@sysoev.ru if (s != -1) { 1237148Sigor@sysoev.ru nxt_socket_close(task, s); 1238148Sigor@sysoev.ru } 1239148Sigor@sysoev.ru 1240359Sigor@sysoev.ru nxt_free(skcf->listen); 1241148Sigor@sysoev.ru } 1242148Sigor@sysoev.ru 1243568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 12441509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &updating_sockets); 12451509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &pending_sockets); 12461509Sigor@sysoev.ru nxt_queue_add(&new_socket_confs, &creating_sockets); 1247568Smax.romanov@nginx.com 1248964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1249964Sigor@sysoev.ru 1250507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1251507Smax.romanov@nginx.com 1252753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1253507Smax.romanov@nginx.com 1254507Smax.romanov@nginx.com } nxt_queue_loop; 1255507Smax.romanov@nginx.com 1256630Svbart@nginx.com router = rtcf->router; 1257149Sigor@sysoev.ru 12581509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &keeping_sockets); 12591509Sigor@sysoev.ru nxt_queue_add(&router->sockets, &deleting_sockets); 1260149Sigor@sysoev.ru 1261416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1262416Smax.romanov@nginx.com 1263148Sigor@sysoev.ru // TODO: new engines and threads 1264148Sigor@sysoev.ru 1265630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1266630Svbart@nginx.com 1267630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1268139Sigor@sysoev.ru 1269193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 12701509Sigor@sysoev.ru 12711869Sa.suvorov@f5.com nxt_mp_release(tmcf->mem_pool); 1272139Sigor@sysoev.ru } 1273139Sigor@sysoev.ru 1274139Sigor@sysoev.ru 1275139Sigor@sysoev.ru static void 1276139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1277193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1278139Sigor@sysoev.ru { 1279193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1280779Smax.romanov@nginx.com 1281779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1282779Smax.romanov@nginx.com 1283779Smax.romanov@nginx.com tmcf->port = NULL; 1284139Sigor@sysoev.ru } 1285139Sigor@sysoev.ru 1286139Sigor@sysoev.ru 1287115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1288115Sigor@sysoev.ru { 1289133Sigor@sysoev.ru nxt_string("listeners_threads"), 1290115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1291115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1292115Sigor@sysoev.ru }, 1293115Sigor@sysoev.ru }; 1294115Sigor@sysoev.ru 1295115Sigor@sysoev.ru 1296133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1297115Sigor@sysoev.ru { 1298133Sigor@sysoev.ru nxt_string("type"), 1299115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1300133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1301115Sigor@sysoev.ru }, 1302115Sigor@sysoev.ru 1303115Sigor@sysoev.ru { 1304507Smax.romanov@nginx.com nxt_string("limits"), 1305507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1306507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1307133Sigor@sysoev.ru }, 1308318Smax.romanov@nginx.com 1309318Smax.romanov@nginx.com { 1310507Smax.romanov@nginx.com nxt_string("processes"), 1311507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1312507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1313507Smax.romanov@nginx.com }, 1314507Smax.romanov@nginx.com 1315507Smax.romanov@nginx.com { 1316507Smax.romanov@nginx.com nxt_string("processes"), 1317318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1318507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1319318Smax.romanov@nginx.com }, 13201473Svbart@nginx.com 13211473Svbart@nginx.com { 13221473Svbart@nginx.com nxt_string("targets"), 13231473Svbart@nginx.com NXT_CONF_MAP_PTR, 13241473Svbart@nginx.com offsetof(nxt_router_app_conf_t, targets_value), 13251473Svbart@nginx.com }, 1326318Smax.romanov@nginx.com }; 1327318Smax.romanov@nginx.com 1328318Smax.romanov@nginx.com 1329318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1330318Smax.romanov@nginx.com { 1331318Smax.romanov@nginx.com nxt_string("timeout"), 1332318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1333318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1334318Smax.romanov@nginx.com }, 1335133Sigor@sysoev.ru }; 1336133Sigor@sysoev.ru 1337133Sigor@sysoev.ru 1338507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1339507Smax.romanov@nginx.com { 1340507Smax.romanov@nginx.com nxt_string("spare"), 1341507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1342507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1343507Smax.romanov@nginx.com }, 1344507Smax.romanov@nginx.com 1345507Smax.romanov@nginx.com { 1346507Smax.romanov@nginx.com nxt_string("max"), 1347507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1348507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1349507Smax.romanov@nginx.com }, 1350507Smax.romanov@nginx.com 1351507Smax.romanov@nginx.com { 1352507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1353507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1354507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1355507Smax.romanov@nginx.com }, 1356507Smax.romanov@nginx.com }; 1357507Smax.romanov@nginx.com 1358507Smax.romanov@nginx.com 1359133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1360133Sigor@sysoev.ru { 1361964Sigor@sysoev.ru nxt_string("pass"), 1362964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1363964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1364964Sigor@sysoev.ru }, 1365964Sigor@sysoev.ru 1366964Sigor@sysoev.ru { 1367133Sigor@sysoev.ru nxt_string("application"), 1368964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1369133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1370115Sigor@sysoev.ru }, 1371115Sigor@sysoev.ru }; 1372115Sigor@sysoev.ru 1373115Sigor@sysoev.ru 1374115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1375115Sigor@sysoev.ru { 1376115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1377115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1378115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1379115Sigor@sysoev.ru }, 1380115Sigor@sysoev.ru 1381115Sigor@sysoev.ru { 1382115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1383115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1384115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1385115Sigor@sysoev.ru }, 1386115Sigor@sysoev.ru 1387115Sigor@sysoev.ru { 1388206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1389206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1390206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1391206Smax.romanov@nginx.com }, 1392206Smax.romanov@nginx.com 1393206Smax.romanov@nginx.com { 1394206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1395206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1396206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1397206Smax.romanov@nginx.com }, 1398206Smax.romanov@nginx.com 1399206Smax.romanov@nginx.com { 1400206Smax.romanov@nginx.com nxt_string("max_body_size"), 1401206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1402206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1403206Smax.romanov@nginx.com }, 1404206Smax.romanov@nginx.com 1405206Smax.romanov@nginx.com { 1406431Sigor@sysoev.ru nxt_string("idle_timeout"), 1407431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1408431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1409431Sigor@sysoev.ru }, 1410431Sigor@sysoev.ru 1411431Sigor@sysoev.ru { 1412115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1413115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1414115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1415115Sigor@sysoev.ru }, 1416206Smax.romanov@nginx.com 1417206Smax.romanov@nginx.com { 1418206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1419206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1420206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1421206Smax.romanov@nginx.com }, 1422431Sigor@sysoev.ru 1423431Sigor@sysoev.ru { 1424431Sigor@sysoev.ru nxt_string("send_timeout"), 1425431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1426431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1427431Sigor@sysoev.ru }, 14281403Smax.romanov@nginx.com 14291403Smax.romanov@nginx.com { 14301403Smax.romanov@nginx.com nxt_string("body_temp_path"), 14311403Smax.romanov@nginx.com NXT_CONF_MAP_STR, 14321403Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_temp_path), 14331403Smax.romanov@nginx.com }, 14341709Svbart@nginx.com 14351709Svbart@nginx.com { 14361709Svbart@nginx.com nxt_string("discard_unsafe_fields"), 14371709Svbart@nginx.com NXT_CONF_MAP_INT8, 14381709Svbart@nginx.com offsetof(nxt_socket_conf_t, discard_unsafe_fields), 14391709Svbart@nginx.com }, 1440115Sigor@sysoev.ru }; 1441115Sigor@sysoev.ru 1442115Sigor@sysoev.ru 14431131Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_websocket_conf[] = { 14441131Smax.romanov@nginx.com { 14451131Smax.romanov@nginx.com nxt_string("max_frame_size"), 14461131Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 14471131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, max_frame_size), 14481131Smax.romanov@nginx.com }, 14491131Smax.romanov@nginx.com 14501131Smax.romanov@nginx.com { 14511131Smax.romanov@nginx.com nxt_string("read_timeout"), 14521131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 14531131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, read_timeout), 14541131Smax.romanov@nginx.com }, 14551131Smax.romanov@nginx.com 14561131Smax.romanov@nginx.com { 14571131Smax.romanov@nginx.com nxt_string("keepalive_interval"), 14581131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 14591131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, keepalive_interval), 14601131Smax.romanov@nginx.com }, 14611131Smax.romanov@nginx.com 14621131Smax.romanov@nginx.com }; 14631131Smax.romanov@nginx.com 14641131Smax.romanov@nginx.com 146553Sigor@sysoev.ru static nxt_int_t 1466115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1467115Sigor@sysoev.ru u_char *start, u_char *end) 146853Sigor@sysoev.ru { 1469133Sigor@sysoev.ru u_char *p; 1470133Sigor@sysoev.ru size_t size; 14711473Svbart@nginx.com nxt_mp_t *mp, *app_mp; 14721473Svbart@nginx.com uint32_t next, next_target; 1473115Sigor@sysoev.ru nxt_int_t ret; 14741473Svbart@nginx.com nxt_str_t name, path, target; 1475133Sigor@sysoev.ru nxt_app_t *app, *prev; 14761473Svbart@nginx.com nxt_str_t *t, *s, *targets; 14771473Svbart@nginx.com nxt_uint_t n, i; 14781547Smax.romanov@nginx.com nxt_port_t *port; 1479359Sigor@sysoev.ru nxt_router_t *router; 1480753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 14811828Sa.suvorov@f5.com #if (NXT_TLS) 14821920Sa.suvorov@f5.com nxt_tls_init_t *tls_init; 14831920Sa.suvorov@f5.com nxt_conf_value_t *certificate; 14841828Sa.suvorov@f5.com #endif 14851131Smax.romanov@nginx.com nxt_conf_value_t *conf, *http, *value, *websocket; 1486133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1487133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 14881936So.canty@f5.com nxt_conf_value_t *routes_conf, *static_conf, *client_ip_conf; 1489115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1490964Sigor@sysoev.ru nxt_http_routes_t *routes; 1491507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1492216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1493133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1494630Svbart@nginx.com nxt_router_access_log_t *access_log; 1495115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1496115Sigor@sysoev.ru 1497716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1498133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1499115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1500964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1501630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1502774Svbart@nginx.com #if (NXT_TLS) 1503774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 15041885Sa.suvorov@f5.com static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands"); 15051920Sa.suvorov@f5.com static nxt_str_t conf_cache_path = nxt_string("/tls/session/cache_size"); 15061920Sa.suvorov@f5.com static nxt_str_t conf_timeout_path = nxt_string("/tls/session/timeout"); 15071942Sa.suvorov@f5.com static nxt_str_t conf_tickets = nxt_string("/tls/session/tickets"); 1508774Svbart@nginx.com #endif 15091183Svbart@nginx.com static nxt_str_t static_path = nxt_string("/settings/http/static"); 15101131Smax.romanov@nginx.com static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); 15111936So.canty@f5.com static nxt_str_t client_ip_path = nxt_string("/client_ip"); 1512115Sigor@sysoev.ru 1513208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1514115Sigor@sysoev.ru if (conf == NULL) { 1515564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1516115Sigor@sysoev.ru return NXT_ERROR; 1517115Sigor@sysoev.ru } 1518115Sigor@sysoev.ru 1519591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1520213Svbart@nginx.com 1521213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1522591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1523115Sigor@sysoev.ru if (ret != NXT_OK) { 1524564Svbart@nginx.com nxt_alert(task, "root map error"); 1525115Sigor@sysoev.ru return NXT_ERROR; 1526115Sigor@sysoev.ru } 1527115Sigor@sysoev.ru 1528591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1529591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1530117Sigor@sysoev.ru } 1531117Sigor@sysoev.ru 15321183Svbart@nginx.com static_conf = nxt_conf_get_path(conf, &static_path); 15331183Svbart@nginx.com 15341183Svbart@nginx.com ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf); 15351183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 15361183Svbart@nginx.com return NXT_ERROR; 15371183Svbart@nginx.com } 15381183Svbart@nginx.com 15391115Svbart@nginx.com router = tmcf->router_conf->router; 15401115Svbart@nginx.com 1541133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 15421115Svbart@nginx.com 15431115Svbart@nginx.com if (applications != NULL) { 15441115Svbart@nginx.com next = 0; 15451115Svbart@nginx.com 15461115Svbart@nginx.com for ( ;; ) { 15471235Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, 15481235Sigor@sysoev.ru &name, &next); 15491115Svbart@nginx.com if (application == NULL) { 15501115Svbart@nginx.com break; 15511115Svbart@nginx.com } 15521115Svbart@nginx.com 15531115Svbart@nginx.com nxt_debug(task, "application \"%V\"", &name); 15541115Svbart@nginx.com 15551115Svbart@nginx.com size = nxt_conf_json_length(application, NULL); 15561115Svbart@nginx.com 15571473Svbart@nginx.com app_mp = nxt_mp_create(4096, 128, 1024, 64); 15581473Svbart@nginx.com if (nxt_slow_path(app_mp == NULL)) { 15591473Svbart@nginx.com goto fail; 15601473Svbart@nginx.com } 15611473Svbart@nginx.com 15621473Svbart@nginx.com app = nxt_mp_get(app_mp, sizeof(nxt_app_t) + name.length + size); 15631115Svbart@nginx.com if (app == NULL) { 15641473Svbart@nginx.com goto app_fail; 15651115Svbart@nginx.com } 15661115Svbart@nginx.com 15671115Svbart@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 15681115Svbart@nginx.com 15691473Svbart@nginx.com app->mem_pool = app_mp; 15701473Svbart@nginx.com 15711115Svbart@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 15721115Svbart@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) 15731115Svbart@nginx.com + name.length); 15741115Svbart@nginx.com 15751115Svbart@nginx.com p = nxt_conf_json_print(app->conf.start, application, NULL); 15761115Svbart@nginx.com app->conf.length = p - app->conf.start; 15771115Svbart@nginx.com 15781115Svbart@nginx.com nxt_assert(app->conf.length <= size); 15791115Svbart@nginx.com 15801115Svbart@nginx.com nxt_debug(task, "application conf \"%V\"", &app->conf); 15811115Svbart@nginx.com 15821115Svbart@nginx.com prev = nxt_router_app_find(&router->apps, &name); 15831115Svbart@nginx.com 15841115Svbart@nginx.com if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 15851473Svbart@nginx.com nxt_mp_destroy(app_mp); 15861115Svbart@nginx.com 15871115Svbart@nginx.com nxt_queue_remove(&prev->link); 15881115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->previous, &prev->link); 15891563Svbart@nginx.com 15901563Svbart@nginx.com ret = nxt_router_apps_hash_add(tmcf->router_conf, prev); 15911563Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 15921563Svbart@nginx.com goto fail; 15931563Svbart@nginx.com } 15941563Svbart@nginx.com 15951115Svbart@nginx.com continue; 15961115Svbart@nginx.com } 15971115Svbart@nginx.com 15981115Svbart@nginx.com apcf.processes = 1; 15991115Svbart@nginx.com apcf.max_processes = 1; 16001115Svbart@nginx.com apcf.spare_processes = 0; 16011115Svbart@nginx.com apcf.timeout = 0; 16021115Svbart@nginx.com apcf.idle_timeout = 15000; 16031115Svbart@nginx.com apcf.limits_value = NULL; 16041115Svbart@nginx.com apcf.processes_value = NULL; 16051473Svbart@nginx.com apcf.targets_value = NULL; 16061115Svbart@nginx.com 16071115Svbart@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 16081115Svbart@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1609318Smax.romanov@nginx.com goto app_fail; 1610318Smax.romanov@nginx.com } 1611318Smax.romanov@nginx.com 16121115Svbart@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 16131115Svbart@nginx.com 16141115Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 16151115Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1616318Smax.romanov@nginx.com if (ret != NXT_OK) { 16171115Svbart@nginx.com nxt_alert(task, "application map error"); 1618318Smax.romanov@nginx.com goto app_fail; 1619318Smax.romanov@nginx.com } 16201115Svbart@nginx.com 16211115Svbart@nginx.com if (apcf.limits_value != NULL) { 16221115Svbart@nginx.com 16231115Svbart@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 16241115Svbart@nginx.com nxt_alert(task, "application limits is not object"); 16251115Svbart@nginx.com goto app_fail; 16261115Svbart@nginx.com } 16271115Svbart@nginx.com 16281115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 16291115Svbart@nginx.com nxt_router_app_limits_conf, 16301115Svbart@nginx.com nxt_nitems(nxt_router_app_limits_conf), 16311115Svbart@nginx.com &apcf); 16321115Svbart@nginx.com if (ret != NXT_OK) { 16331115Svbart@nginx.com nxt_alert(task, "application limits map error"); 16341115Svbart@nginx.com goto app_fail; 16351115Svbart@nginx.com } 16361115Svbart@nginx.com } 16371115Svbart@nginx.com 16381115Svbart@nginx.com if (apcf.processes_value != NULL 16391115Svbart@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 16401115Svbart@nginx.com { 16411115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 16421115Svbart@nginx.com nxt_router_app_processes_conf, 16431115Svbart@nginx.com nxt_nitems(nxt_router_app_processes_conf), 16441115Svbart@nginx.com &apcf); 16451115Svbart@nginx.com if (ret != NXT_OK) { 16461115Svbart@nginx.com nxt_alert(task, "application processes map error"); 16471115Svbart@nginx.com goto app_fail; 16481115Svbart@nginx.com } 16491115Svbart@nginx.com 16501115Svbart@nginx.com } else { 16511115Svbart@nginx.com apcf.max_processes = apcf.processes; 16521115Svbart@nginx.com apcf.spare_processes = apcf.processes; 16531115Svbart@nginx.com } 16541115Svbart@nginx.com 16551473Svbart@nginx.com if (apcf.targets_value != NULL) { 16561473Svbart@nginx.com n = nxt_conf_object_members_count(apcf.targets_value); 16571473Svbart@nginx.com 16581473Svbart@nginx.com targets = nxt_mp_get(app_mp, sizeof(nxt_str_t) * n); 16591473Svbart@nginx.com if (nxt_slow_path(targets == NULL)) { 16601473Svbart@nginx.com goto app_fail; 16611473Svbart@nginx.com } 16621473Svbart@nginx.com 16631473Svbart@nginx.com next_target = 0; 16641473Svbart@nginx.com 16651473Svbart@nginx.com for (i = 0; i < n; i++) { 16661480Svbart@nginx.com (void) nxt_conf_next_object_member(apcf.targets_value, 16671480Svbart@nginx.com &target, &next_target); 16681473Svbart@nginx.com 16691473Svbart@nginx.com s = nxt_str_dup(app_mp, &targets[i], &target); 16701473Svbart@nginx.com if (nxt_slow_path(s == NULL)) { 16711473Svbart@nginx.com goto app_fail; 16721473Svbart@nginx.com } 16731473Svbart@nginx.com } 16741473Svbart@nginx.com 16751473Svbart@nginx.com } else { 16761473Svbart@nginx.com targets = NULL; 16771473Svbart@nginx.com } 16781473Svbart@nginx.com 16791115Svbart@nginx.com nxt_debug(task, "application type: %V", &apcf.type); 16801115Svbart@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 16811115Svbart@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 16821115Svbart@nginx.com 16831115Svbart@nginx.com lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 16841115Svbart@nginx.com 16851115Svbart@nginx.com if (lang == NULL) { 16861115Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1687507Smax.romanov@nginx.com goto app_fail; 1688507Smax.romanov@nginx.com } 1689507Smax.romanov@nginx.com 16901115Svbart@nginx.com nxt_debug(task, "application language module: \"%s\"", lang->file); 16911115Svbart@nginx.com 16921115Svbart@nginx.com ret = nxt_thread_mutex_create(&app->mutex); 16931115Svbart@nginx.com if (ret != NXT_OK) { 16941115Svbart@nginx.com goto app_fail; 16951115Svbart@nginx.com } 16961115Svbart@nginx.com 16971115Svbart@nginx.com nxt_queue_init(&app->ports); 16981115Svbart@nginx.com nxt_queue_init(&app->spare_ports); 16991115Svbart@nginx.com nxt_queue_init(&app->idle_ports); 17001561Smax.romanov@nginx.com nxt_queue_init(&app->ack_waiting_req); 17011115Svbart@nginx.com 17021115Svbart@nginx.com app->name.length = name.length; 17031115Svbart@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 17041115Svbart@nginx.com 17051115Svbart@nginx.com app->type = lang->type; 17061115Svbart@nginx.com app->max_processes = apcf.max_processes; 17071115Svbart@nginx.com app->spare_processes = apcf.spare_processes; 17081115Svbart@nginx.com app->max_pending_processes = apcf.spare_processes 17091115Svbart@nginx.com ? apcf.spare_processes : 1; 17101115Svbart@nginx.com app->timeout = apcf.timeout; 17111115Svbart@nginx.com app->idle_timeout = apcf.idle_timeout; 17121115Svbart@nginx.com 17131473Svbart@nginx.com app->targets = targets; 17141473Svbart@nginx.com 17151115Svbart@nginx.com engine = task->thread->engine; 17161115Svbart@nginx.com 17171115Svbart@nginx.com app->engine = engine; 17181115Svbart@nginx.com 17191115Svbart@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 17201115Svbart@nginx.com app->adjust_idle_work.task = &engine->task; 17211115Svbart@nginx.com app->adjust_idle_work.obj = app; 17221115Svbart@nginx.com 17231115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->apps, &app->link); 17241115Svbart@nginx.com 17251563Svbart@nginx.com ret = nxt_router_apps_hash_add(tmcf->router_conf, app); 17261563Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 17271563Svbart@nginx.com goto app_fail; 17281563Svbart@nginx.com } 17291563Svbart@nginx.com 17301115Svbart@nginx.com nxt_router_app_use(task, app, 1); 17311115Svbart@nginx.com 17321115Svbart@nginx.com app->joint = app_joint; 17331115Svbart@nginx.com 17341115Svbart@nginx.com app_joint->use_count = 1; 17351115Svbart@nginx.com app_joint->app = app; 17361115Svbart@nginx.com 17371115Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 17381115Svbart@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 17391115Svbart@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 17401115Svbart@nginx.com app_joint->idle_timer.task = &engine->task; 17411115Svbart@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 17421115Svbart@nginx.com 17431115Svbart@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 17441115Svbart@nginx.com app_joint->free_app_work.task = &engine->task; 17451115Svbart@nginx.com app_joint->free_app_work.obj = app_joint; 17461547Smax.romanov@nginx.com 17471926Smax.romanov@nginx.com port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid, 17481547Smax.romanov@nginx.com NXT_PROCESS_APP); 17491547Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 17501547Smax.romanov@nginx.com return NXT_ERROR; 17511547Smax.romanov@nginx.com } 17521547Smax.romanov@nginx.com 17531547Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 17541547Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 17551547Smax.romanov@nginx.com nxt_port_use(task, port, -1); 17561547Smax.romanov@nginx.com return NXT_ERROR; 17571547Smax.romanov@nginx.com } 17581547Smax.romanov@nginx.com 17591555Smax.romanov@nginx.com ret = nxt_router_app_queue_init(task, port); 17601555Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 17611777Smax.romanov@nginx.com nxt_port_write_close(port); 17621777Smax.romanov@nginx.com nxt_port_read_close(port); 17631555Smax.romanov@nginx.com nxt_port_use(task, port, -1); 17641555Smax.romanov@nginx.com return NXT_ERROR; 17651555Smax.romanov@nginx.com } 17661555Smax.romanov@nginx.com 17671547Smax.romanov@nginx.com nxt_port_write_enable(task, port); 17681547Smax.romanov@nginx.com port->app = app; 17691547Smax.romanov@nginx.com 17701547Smax.romanov@nginx.com app->shared_port = port; 17711547Smax.romanov@nginx.com 17721547Smax.romanov@nginx.com nxt_thread_mutex_create(&app->outgoing.mutex); 1773133Sigor@sysoev.ru } 1774133Sigor@sysoev.ru } 1775133Sigor@sysoev.ru 1776964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1777964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1778964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1779964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1780964Sigor@sysoev.ru return NXT_ERROR; 1781964Sigor@sysoev.ru } 1782964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1783964Sigor@sysoev.ru } 1784964Sigor@sysoev.ru 17851394Sigor@sysoev.ru ret = nxt_upstreams_create(task, tmcf, conf); 17861394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 17871394Sigor@sysoev.ru return ret; 17881394Sigor@sysoev.ru } 17891394Sigor@sysoev.ru 1790133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1791133Sigor@sysoev.ru #if 0 1792133Sigor@sysoev.ru if (http == NULL) { 1793564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1794133Sigor@sysoev.ru return NXT_ERROR; 1795133Sigor@sysoev.ru } 1796133Sigor@sysoev.ru #endif 1797133Sigor@sysoev.ru 17981131Smax.romanov@nginx.com websocket = nxt_conf_get_path(conf, &websocket_path); 17991131Smax.romanov@nginx.com 1800133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 18011115Svbart@nginx.com 18021115Svbart@nginx.com if (listeners != NULL) { 18031115Svbart@nginx.com next = 0; 18041115Svbart@nginx.com 18051115Svbart@nginx.com for ( ;; ) { 18061115Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &name, &next); 18071115Svbart@nginx.com if (listener == NULL) { 18081115Svbart@nginx.com break; 18091115Svbart@nginx.com } 18101115Svbart@nginx.com 18111115Svbart@nginx.com skcf = nxt_router_socket_conf(task, tmcf, &name); 18121115Svbart@nginx.com if (skcf == NULL) { 18131115Svbart@nginx.com goto fail; 18141115Svbart@nginx.com } 18151115Svbart@nginx.com 18161115Svbart@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 18171115Svbart@nginx.com 18181115Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 18191115Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), 18201115Svbart@nginx.com &lscf); 1821133Sigor@sysoev.ru if (ret != NXT_OK) { 18221115Svbart@nginx.com nxt_alert(task, "listener map error"); 1823133Sigor@sysoev.ru goto fail; 1824133Sigor@sysoev.ru } 18251115Svbart@nginx.com 18261115Svbart@nginx.com nxt_debug(task, "application: %V", &lscf.application); 18271115Svbart@nginx.com 18281115Svbart@nginx.com // STUB, default values if http block is not defined. 18291115Svbart@nginx.com skcf->header_buffer_size = 2048; 18301115Svbart@nginx.com skcf->large_header_buffer_size = 8192; 18311115Svbart@nginx.com skcf->large_header_buffers = 4; 18321709Svbart@nginx.com skcf->discard_unsafe_fields = 1; 18331115Svbart@nginx.com skcf->body_buffer_size = 16 * 1024; 18341115Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 18351270Sigor@sysoev.ru skcf->proxy_header_buffer_size = 64 * 1024; 18361270Sigor@sysoev.ru skcf->proxy_buffer_size = 4096; 18371270Sigor@sysoev.ru skcf->proxy_buffers = 256; 18381115Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 18391115Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 18401115Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 18411115Svbart@nginx.com skcf->send_timeout = 30 * 1000; 18421270Sigor@sysoev.ru skcf->proxy_timeout = 60 * 1000; 18431270Sigor@sysoev.ru skcf->proxy_send_timeout = 30 * 1000; 18441270Sigor@sysoev.ru skcf->proxy_read_timeout = 30 * 1000; 18451115Svbart@nginx.com 18461131Smax.romanov@nginx.com skcf->websocket_conf.max_frame_size = 1024 * 1024; 18471131Smax.romanov@nginx.com skcf->websocket_conf.read_timeout = 60 * 1000; 18481131Smax.romanov@nginx.com skcf->websocket_conf.keepalive_interval = 30 * 1000; 18491131Smax.romanov@nginx.com 18501403Smax.romanov@nginx.com nxt_str_null(&skcf->body_temp_path); 18511403Smax.romanov@nginx.com 18521115Svbart@nginx.com if (http != NULL) { 18531115Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 18541115Svbart@nginx.com nxt_nitems(nxt_router_http_conf), 18551115Svbart@nginx.com skcf); 18561115Svbart@nginx.com if (ret != NXT_OK) { 18571115Svbart@nginx.com nxt_alert(task, "http map error"); 18581115Svbart@nginx.com goto fail; 18591115Svbart@nginx.com } 18601115Svbart@nginx.com } 1861115Sigor@sysoev.ru 18621131Smax.romanov@nginx.com if (websocket != NULL) { 18631131Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, websocket, 18641131Smax.romanov@nginx.com nxt_router_websocket_conf, 18651131Smax.romanov@nginx.com nxt_nitems(nxt_router_websocket_conf), 18661131Smax.romanov@nginx.com &skcf->websocket_conf); 18671131Smax.romanov@nginx.com if (ret != NXT_OK) { 18681131Smax.romanov@nginx.com nxt_alert(task, "websocket map error"); 18691131Smax.romanov@nginx.com goto fail; 18701131Smax.romanov@nginx.com } 18711131Smax.romanov@nginx.com } 18721131Smax.romanov@nginx.com 18731403Smax.romanov@nginx.com t = &skcf->body_temp_path; 18741403Smax.romanov@nginx.com 18751403Smax.romanov@nginx.com if (t->length == 0) { 18761403Smax.romanov@nginx.com t->start = (u_char *) task->thread->runtime->tmp; 18771403Smax.romanov@nginx.com t->length = nxt_strlen(t->start); 18781403Smax.romanov@nginx.com } 18791403Smax.romanov@nginx.com 18801936So.canty@f5.com client_ip_conf = nxt_conf_get_path(listener, &client_ip_path); 18811936So.canty@f5.com ret = nxt_router_conf_process_client_ip(task, tmcf, skcf, 18821936So.canty@f5.com client_ip_conf); 18831936So.canty@f5.com if (nxt_slow_path(ret != NXT_OK)) { 18841936So.canty@f5.com return NXT_ERROR; 18851936So.canty@f5.com } 18861936So.canty@f5.com 1887774Svbart@nginx.com #if (NXT_TLS) 18881828Sa.suvorov@f5.com certificate = nxt_conf_get_path(listener, &certificate_path); 18891828Sa.suvorov@f5.com 18901828Sa.suvorov@f5.com if (certificate != NULL) { 18911920Sa.suvorov@f5.com tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t)); 18921920Sa.suvorov@f5.com if (nxt_slow_path(tls_init == NULL)) { 18931920Sa.suvorov@f5.com return NXT_ERROR; 18941920Sa.suvorov@f5.com } 18951920Sa.suvorov@f5.com 18961920Sa.suvorov@f5.com tls_init->cache_size = 0; 18971920Sa.suvorov@f5.com tls_init->timeout = 300; 18981920Sa.suvorov@f5.com 18991920Sa.suvorov@f5.com value = nxt_conf_get_path(listener, &conf_cache_path); 19001920Sa.suvorov@f5.com if (value != NULL) { 19011920Sa.suvorov@f5.com tls_init->cache_size = nxt_conf_get_number(value); 19021920Sa.suvorov@f5.com } 19031920Sa.suvorov@f5.com 19041920Sa.suvorov@f5.com value = nxt_conf_get_path(listener, &conf_timeout_path); 19051920Sa.suvorov@f5.com if (value != NULL) { 19061920Sa.suvorov@f5.com tls_init->timeout = nxt_conf_get_number(value); 19071920Sa.suvorov@f5.com } 19081920Sa.suvorov@f5.com 19091920Sa.suvorov@f5.com tls_init->conf_cmds = nxt_conf_get_path(listener, 19101920Sa.suvorov@f5.com &conf_commands_path); 19111885Sa.suvorov@f5.com 19121942Sa.suvorov@f5.com tls_init->tickets_conf = nxt_conf_get_path(listener, 19131942Sa.suvorov@f5.com &conf_tickets); 19141942Sa.suvorov@f5.com 19151828Sa.suvorov@f5.com if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) { 19161828Sa.suvorov@f5.com n = nxt_conf_array_elements_count(certificate); 19171828Sa.suvorov@f5.com 19181828Sa.suvorov@f5.com for (i = 0; i < n; i++) { 19191828Sa.suvorov@f5.com value = nxt_conf_get_array_element(certificate, i); 19201828Sa.suvorov@f5.com 19211828Sa.suvorov@f5.com nxt_assert(value != NULL); 19221828Sa.suvorov@f5.com 19231885Sa.suvorov@f5.com ret = nxt_router_conf_tls_insert(tmcf, value, skcf, 19241920Sa.suvorov@f5.com tls_init, i == 0); 19251828Sa.suvorov@f5.com if (nxt_slow_path(ret != NXT_OK)) { 19261828Sa.suvorov@f5.com goto fail; 19271828Sa.suvorov@f5.com } 19281828Sa.suvorov@f5.com } 19291828Sa.suvorov@f5.com 19301828Sa.suvorov@f5.com } else { 19311828Sa.suvorov@f5.com /* NXT_CONF_STRING */ 19321885Sa.suvorov@f5.com ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf, 19331920Sa.suvorov@f5.com tls_init, 1); 19341828Sa.suvorov@f5.com if (nxt_slow_path(ret != NXT_OK)) { 19351828Sa.suvorov@f5.com goto fail; 19361828Sa.suvorov@f5.com } 19371115Svbart@nginx.com } 1938774Svbart@nginx.com } 1939774Svbart@nginx.com #endif 1940774Svbart@nginx.com 19411115Svbart@nginx.com skcf->listen->handler = nxt_http_conn_init; 19421115Svbart@nginx.com skcf->router_conf = tmcf->router_conf; 19431115Svbart@nginx.com skcf->router_conf->count++; 19441115Svbart@nginx.com 19451115Svbart@nginx.com if (lscf.pass.length != 0) { 19461264Sigor@sysoev.ru skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass); 19471115Svbart@nginx.com 19481115Svbart@nginx.com /* COMPATIBILITY: listener application. */ 19491115Svbart@nginx.com } else if (lscf.application.length > 0) { 19501563Svbart@nginx.com skcf->action = nxt_http_pass_application(task, 19511563Svbart@nginx.com tmcf->router_conf, 19521264Sigor@sysoev.ru &lscf.application); 19531115Svbart@nginx.com } 19541597Shongzhidao@gmail.com 19551597Shongzhidao@gmail.com if (nxt_slow_path(skcf->action == NULL)) { 19561597Shongzhidao@gmail.com goto fail; 19571597Shongzhidao@gmail.com } 1958770Smax.romanov@nginx.com } 1959115Sigor@sysoev.ru } 196053Sigor@sysoev.ru 19611472Svbart@nginx.com ret = nxt_http_routes_resolve(task, tmcf); 19621472Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 19631472Svbart@nginx.com goto fail; 19641472Svbart@nginx.com } 19651472Svbart@nginx.com 1966630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1967630Svbart@nginx.com 1968630Svbart@nginx.com if (value != NULL) { 1969630Svbart@nginx.com nxt_conf_get_string(value, &path); 1970630Svbart@nginx.com 1971630Svbart@nginx.com access_log = router->access_log; 1972630Svbart@nginx.com 1973630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1974630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1975630Svbart@nginx.com access_log->count++; 1976630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1977630Svbart@nginx.com 1978630Svbart@nginx.com } else { 1979630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1980630Svbart@nginx.com + path.length); 1981630Svbart@nginx.com if (access_log == NULL) { 1982630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1983630Svbart@nginx.com goto fail; 1984630Svbart@nginx.com } 1985630Svbart@nginx.com 1986630Svbart@nginx.com access_log->fd = -1; 1987630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1988630Svbart@nginx.com access_log->count = 1; 1989630Svbart@nginx.com 1990630Svbart@nginx.com access_log->path.length = path.length; 1991630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1992630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1993630Svbart@nginx.com 1994630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1995630Svbart@nginx.com } 1996630Svbart@nginx.com 1997630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1998630Svbart@nginx.com } 1999630Svbart@nginx.com 20001509Sigor@sysoev.ru nxt_queue_add(&deleting_sockets, &router->sockets); 2001359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 2002198Sigor@sysoev.ru 200353Sigor@sysoev.ru return NXT_OK; 2004133Sigor@sysoev.ru 2005133Sigor@sysoev.ru app_fail: 2006133Sigor@sysoev.ru 20071473Svbart@nginx.com nxt_mp_destroy(app_mp); 2008133Sigor@sysoev.ru 2009133Sigor@sysoev.ru fail: 2010133Sigor@sysoev.ru 2011141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 2012141Smax.romanov@nginx.com 2013141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 2014133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 20151473Svbart@nginx.com nxt_mp_destroy(app->mem_pool); 2016141Smax.romanov@nginx.com 2017141Smax.romanov@nginx.com } nxt_queue_loop; 2018133Sigor@sysoev.ru 2019133Sigor@sysoev.ru return NXT_ERROR; 2020133Sigor@sysoev.ru } 2021133Sigor@sysoev.ru 2022133Sigor@sysoev.ru 20231828Sa.suvorov@f5.com #if (NXT_TLS) 20241828Sa.suvorov@f5.com 20251828Sa.suvorov@f5.com static nxt_int_t 20261828Sa.suvorov@f5.com nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf, 20271885Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_socket_conf_t *skcf, 20281920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last) 20291828Sa.suvorov@f5.com { 20301828Sa.suvorov@f5.com nxt_router_tlssock_t *tls; 20311828Sa.suvorov@f5.com 20321885Sa.suvorov@f5.com tls = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_router_tlssock_t)); 20331828Sa.suvorov@f5.com if (nxt_slow_path(tls == NULL)) { 20341828Sa.suvorov@f5.com return NXT_ERROR; 20351828Sa.suvorov@f5.com } 20361828Sa.suvorov@f5.com 20371920Sa.suvorov@f5.com tls->tls_init = tls_init; 20381885Sa.suvorov@f5.com tls->socket_conf = skcf; 20391885Sa.suvorov@f5.com tls->temp_conf = tmcf; 20401904Smax.romanov@nginx.com tls->last = last; 20411885Sa.suvorov@f5.com nxt_conf_get_string(value, &tls->name); 20421828Sa.suvorov@f5.com 20431828Sa.suvorov@f5.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 20441828Sa.suvorov@f5.com 20451828Sa.suvorov@f5.com return NXT_OK; 20461828Sa.suvorov@f5.com } 20471828Sa.suvorov@f5.com 20481828Sa.suvorov@f5.com #endif 20491828Sa.suvorov@f5.com 20501828Sa.suvorov@f5.com 20511183Svbart@nginx.com static nxt_int_t 20521183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, 20531183Svbart@nginx.com nxt_conf_value_t *conf) 20541183Svbart@nginx.com { 20551183Svbart@nginx.com uint32_t next, i; 20561183Svbart@nginx.com nxt_mp_t *mp; 20571923Sz.hong@f5.com nxt_str_t *type, exten, str; 20581183Svbart@nginx.com nxt_int_t ret; 20591183Svbart@nginx.com nxt_uint_t exts; 20601183Svbart@nginx.com nxt_conf_value_t *mtypes_conf, *ext_conf, *value; 20611183Svbart@nginx.com 20621183Svbart@nginx.com static nxt_str_t mtypes_path = nxt_string("/mime_types"); 20631183Svbart@nginx.com 20641183Svbart@nginx.com mp = rtcf->mem_pool; 20651183Svbart@nginx.com 20661183Svbart@nginx.com ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash); 20671183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 20681183Svbart@nginx.com return NXT_ERROR; 20691183Svbart@nginx.com } 20701183Svbart@nginx.com 20711183Svbart@nginx.com if (conf == NULL) { 20721183Svbart@nginx.com return NXT_OK; 20731183Svbart@nginx.com } 20741183Svbart@nginx.com 20751183Svbart@nginx.com mtypes_conf = nxt_conf_get_path(conf, &mtypes_path); 20761183Svbart@nginx.com 20771183Svbart@nginx.com if (mtypes_conf != NULL) { 20781183Svbart@nginx.com next = 0; 20791183Svbart@nginx.com 20801183Svbart@nginx.com for ( ;; ) { 20811183Svbart@nginx.com ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next); 20821183Svbart@nginx.com 20831183Svbart@nginx.com if (ext_conf == NULL) { 20841183Svbart@nginx.com break; 20851183Svbart@nginx.com } 20861183Svbart@nginx.com 20871183Svbart@nginx.com type = nxt_str_dup(mp, NULL, &str); 20881183Svbart@nginx.com if (nxt_slow_path(type == NULL)) { 20891183Svbart@nginx.com return NXT_ERROR; 20901183Svbart@nginx.com } 20911183Svbart@nginx.com 20921183Svbart@nginx.com if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) { 20931183Svbart@nginx.com nxt_conf_get_string(ext_conf, &str); 20941183Svbart@nginx.com 20951923Sz.hong@f5.com if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) { 20961183Svbart@nginx.com return NXT_ERROR; 20971183Svbart@nginx.com } 20981183Svbart@nginx.com 20991183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 21001923Sz.hong@f5.com &exten, type); 21011183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 21021183Svbart@nginx.com return NXT_ERROR; 21031183Svbart@nginx.com } 21041183Svbart@nginx.com 21051183Svbart@nginx.com continue; 21061183Svbart@nginx.com } 21071183Svbart@nginx.com 21081183Svbart@nginx.com exts = nxt_conf_array_elements_count(ext_conf); 21091183Svbart@nginx.com 21101183Svbart@nginx.com for (i = 0; i < exts; i++) { 21111183Svbart@nginx.com value = nxt_conf_get_array_element(ext_conf, i); 21121183Svbart@nginx.com 21131183Svbart@nginx.com nxt_conf_get_string(value, &str); 21141183Svbart@nginx.com 21151923Sz.hong@f5.com if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) { 21161183Svbart@nginx.com return NXT_ERROR; 21171183Svbart@nginx.com } 21181183Svbart@nginx.com 21191183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 21201923Sz.hong@f5.com &exten, type); 21211183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 21221183Svbart@nginx.com return NXT_ERROR; 21231183Svbart@nginx.com } 21241183Svbart@nginx.com } 21251183Svbart@nginx.com } 21261183Svbart@nginx.com } 21271183Svbart@nginx.com 21281183Svbart@nginx.com return NXT_OK; 21291183Svbart@nginx.com } 21301183Svbart@nginx.com 21311183Svbart@nginx.com 21321936So.canty@f5.com static nxt_int_t 21331936So.canty@f5.com nxt_router_conf_process_client_ip(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 21341936So.canty@f5.com nxt_socket_conf_t *skcf, nxt_conf_value_t *conf) 21351936So.canty@f5.com { 21361936So.canty@f5.com char c; 21371936So.canty@f5.com size_t i; 21381936So.canty@f5.com nxt_mp_t *mp; 21391936So.canty@f5.com uint32_t hash; 21401936So.canty@f5.com nxt_str_t header; 21411936So.canty@f5.com nxt_conf_value_t *source_conf, *header_conf, *recursive_conf; 21421936So.canty@f5.com nxt_http_client_ip_t *client_ip; 21431936So.canty@f5.com nxt_http_route_addr_rule_t *source; 21441936So.canty@f5.com 21451936So.canty@f5.com static nxt_str_t header_path = nxt_string("/header"); 21461936So.canty@f5.com static nxt_str_t source_path = nxt_string("/source"); 21471936So.canty@f5.com static nxt_str_t recursive_path = nxt_string("/recursive"); 21481936So.canty@f5.com 21491936So.canty@f5.com if (conf == NULL) { 21501936So.canty@f5.com skcf->client_ip = NULL; 21511936So.canty@f5.com 21521936So.canty@f5.com return NXT_OK; 21531936So.canty@f5.com } 21541936So.canty@f5.com 21551936So.canty@f5.com mp = tmcf->router_conf->mem_pool; 21561936So.canty@f5.com 21571936So.canty@f5.com source_conf = nxt_conf_get_path(conf, &source_path); 21581936So.canty@f5.com header_conf = nxt_conf_get_path(conf, &header_path); 21591936So.canty@f5.com recursive_conf = nxt_conf_get_path(conf, &recursive_path); 21601936So.canty@f5.com 21611936So.canty@f5.com if (source_conf == NULL || header_conf == NULL) { 21621936So.canty@f5.com return NXT_ERROR; 21631936So.canty@f5.com } 21641936So.canty@f5.com 21651936So.canty@f5.com client_ip = nxt_mp_zget(mp, sizeof(nxt_http_client_ip_t)); 21661936So.canty@f5.com if (nxt_slow_path(client_ip == NULL)) { 21671936So.canty@f5.com return NXT_ERROR; 21681936So.canty@f5.com } 21691936So.canty@f5.com 21701936So.canty@f5.com source = nxt_http_route_addr_rule_create(task, mp, source_conf); 21711936So.canty@f5.com if (nxt_slow_path(source == NULL)) { 21721936So.canty@f5.com return NXT_ERROR; 21731936So.canty@f5.com } 21741936So.canty@f5.com 21751936So.canty@f5.com client_ip->source = source; 21761936So.canty@f5.com 21771936So.canty@f5.com nxt_conf_get_string(header_conf, &header); 21781936So.canty@f5.com 21791936So.canty@f5.com if (recursive_conf != NULL) { 21801936So.canty@f5.com client_ip->recursive = nxt_conf_get_boolean(recursive_conf); 21811936So.canty@f5.com } 21821936So.canty@f5.com 21831936So.canty@f5.com client_ip->header = nxt_str_dup(mp, NULL, &header); 21841936So.canty@f5.com if (nxt_slow_path(client_ip->header == NULL)) { 21851936So.canty@f5.com return NXT_ERROR; 21861936So.canty@f5.com } 21871936So.canty@f5.com 21881936So.canty@f5.com hash = NXT_HTTP_FIELD_HASH_INIT; 21891936So.canty@f5.com 21901936So.canty@f5.com for (i = 0; i < client_ip->header->length; i++) { 21911936So.canty@f5.com c = client_ip->header->start[i]; 21921936So.canty@f5.com hash = nxt_http_field_hash_char(hash, nxt_lowcase(c)); 21931936So.canty@f5.com } 21941936So.canty@f5.com 21951936So.canty@f5.com hash = nxt_http_field_hash_end(hash) & 0xFFFF; 21961936So.canty@f5.com 21971936So.canty@f5.com client_ip->header_hash = hash; 21981936So.canty@f5.com 21991936So.canty@f5.com skcf->client_ip = client_ip; 22001936So.canty@f5.com 22011936So.canty@f5.com return NXT_OK; 22021936So.canty@f5.com } 22031936So.canty@f5.com 22041936So.canty@f5.com 2205133Sigor@sysoev.ru static nxt_app_t * 2206133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 2207133Sigor@sysoev.ru { 2208141Smax.romanov@nginx.com nxt_app_t *app; 2209141Smax.romanov@nginx.com 2210141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 2211133Sigor@sysoev.ru 2212133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 2213133Sigor@sysoev.ru return app; 2214133Sigor@sysoev.ru } 2215141Smax.romanov@nginx.com 2216141Smax.romanov@nginx.com } nxt_queue_loop; 2217133Sigor@sysoev.ru 2218133Sigor@sysoev.ru return NULL; 2219133Sigor@sysoev.ru } 2220133Sigor@sysoev.ru 2221133Sigor@sysoev.ru 22221555Smax.romanov@nginx.com static nxt_int_t 22231555Smax.romanov@nginx.com nxt_router_app_queue_init(nxt_task_t *task, nxt_port_t *port) 22241555Smax.romanov@nginx.com { 22251555Smax.romanov@nginx.com void *mem; 22261555Smax.romanov@nginx.com nxt_int_t fd; 22271555Smax.romanov@nginx.com 22281555Smax.romanov@nginx.com fd = nxt_shm_open(task, sizeof(nxt_app_queue_t)); 22291555Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 22301555Smax.romanov@nginx.com return NXT_ERROR; 22311555Smax.romanov@nginx.com } 22321555Smax.romanov@nginx.com 22331555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_app_queue_t), 22341555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 22351555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 22361555Smax.romanov@nginx.com nxt_fd_close(fd); 22371555Smax.romanov@nginx.com 22381555Smax.romanov@nginx.com return NXT_ERROR; 22391555Smax.romanov@nginx.com } 22401555Smax.romanov@nginx.com 22411555Smax.romanov@nginx.com nxt_app_queue_init(mem); 22421555Smax.romanov@nginx.com 22431555Smax.romanov@nginx.com port->queue_fd = fd; 22441555Smax.romanov@nginx.com port->queue = mem; 22451555Smax.romanov@nginx.com 22461555Smax.romanov@nginx.com return NXT_OK; 22471555Smax.romanov@nginx.com } 22481555Smax.romanov@nginx.com 22491555Smax.romanov@nginx.com 22501555Smax.romanov@nginx.com static nxt_int_t 22511555Smax.romanov@nginx.com nxt_router_port_queue_init(nxt_task_t *task, nxt_port_t *port) 22521555Smax.romanov@nginx.com { 22531555Smax.romanov@nginx.com void *mem; 22541555Smax.romanov@nginx.com nxt_int_t fd; 22551555Smax.romanov@nginx.com 22561555Smax.romanov@nginx.com fd = nxt_shm_open(task, sizeof(nxt_port_queue_t)); 22571555Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 22581555Smax.romanov@nginx.com return NXT_ERROR; 22591555Smax.romanov@nginx.com } 22601555Smax.romanov@nginx.com 22611555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), 22621555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 22631555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 22641555Smax.romanov@nginx.com nxt_fd_close(fd); 22651555Smax.romanov@nginx.com 22661555Smax.romanov@nginx.com return NXT_ERROR; 22671555Smax.romanov@nginx.com } 22681555Smax.romanov@nginx.com 22691555Smax.romanov@nginx.com nxt_port_queue_init(mem); 22701555Smax.romanov@nginx.com 22711555Smax.romanov@nginx.com port->queue_fd = fd; 22721555Smax.romanov@nginx.com port->queue = mem; 22731555Smax.romanov@nginx.com 22741555Smax.romanov@nginx.com return NXT_OK; 22751555Smax.romanov@nginx.com } 22761555Smax.romanov@nginx.com 22771555Smax.romanov@nginx.com 22781555Smax.romanov@nginx.com static nxt_int_t 22791555Smax.romanov@nginx.com nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd) 22801555Smax.romanov@nginx.com { 22811555Smax.romanov@nginx.com void *mem; 22821555Smax.romanov@nginx.com 22831555Smax.romanov@nginx.com nxt_assert(fd != -1); 22841555Smax.romanov@nginx.com 22851555Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, sizeof(nxt_port_queue_t), 22861555Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 22871555Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 22881555Smax.romanov@nginx.com 22891555Smax.romanov@nginx.com return NXT_ERROR; 22901555Smax.romanov@nginx.com } 22911555Smax.romanov@nginx.com 22921555Smax.romanov@nginx.com port->queue = mem; 22931555Smax.romanov@nginx.com 22941555Smax.romanov@nginx.com return NXT_OK; 22951555Smax.romanov@nginx.com } 22961555Smax.romanov@nginx.com 22971555Smax.romanov@nginx.com 22981563Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_router_apps_hash_proto nxt_aligned(64) = { 22991563Svbart@nginx.com NXT_LVLHSH_DEFAULT, 23001563Svbart@nginx.com nxt_router_apps_hash_test, 23011563Svbart@nginx.com nxt_mp_lvlhsh_alloc, 23021563Svbart@nginx.com nxt_mp_lvlhsh_free, 23031563Svbart@nginx.com }; 23041563Svbart@nginx.com 23051563Svbart@nginx.com 23061563Svbart@nginx.com static nxt_int_t 23071563Svbart@nginx.com nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 23081563Svbart@nginx.com { 23091563Svbart@nginx.com nxt_app_t *app; 23101563Svbart@nginx.com 23111563Svbart@nginx.com app = data; 23121563Svbart@nginx.com 23131563Svbart@nginx.com return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED; 23141563Svbart@nginx.com } 23151563Svbart@nginx.com 23161563Svbart@nginx.com 23171563Svbart@nginx.com static nxt_int_t 23181563Svbart@nginx.com nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app) 23191563Svbart@nginx.com { 23201563Svbart@nginx.com nxt_lvlhsh_query_t lhq; 23211563Svbart@nginx.com 23221563Svbart@nginx.com lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length); 23231563Svbart@nginx.com lhq.replace = 0; 23241563Svbart@nginx.com lhq.key = app->name; 23251563Svbart@nginx.com lhq.value = app; 23261563Svbart@nginx.com lhq.proto = &nxt_router_apps_hash_proto; 23271563Svbart@nginx.com lhq.pool = rtcf->mem_pool; 23281563Svbart@nginx.com 23291563Svbart@nginx.com switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) { 23301563Svbart@nginx.com 23311563Svbart@nginx.com case NXT_OK: 23321563Svbart@nginx.com return NXT_OK; 23331563Svbart@nginx.com 23341563Svbart@nginx.com case NXT_DECLINED: 23351563Svbart@nginx.com nxt_thread_log_alert("router app hash adding failed: " 23361563Svbart@nginx.com "\"%V\" is already in hash", &lhq.key); 23371563Svbart@nginx.com /* Fall through. */ 23381563Svbart@nginx.com default: 23391563Svbart@nginx.com return NXT_ERROR; 23401563Svbart@nginx.com } 23411563Svbart@nginx.com } 23421563Svbart@nginx.com 23431563Svbart@nginx.com 23441563Svbart@nginx.com static nxt_app_t * 23451563Svbart@nginx.com nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name) 23461563Svbart@nginx.com { 23471563Svbart@nginx.com nxt_lvlhsh_query_t lhq; 23481563Svbart@nginx.com 23491563Svbart@nginx.com lhq.key_hash = nxt_djb_hash(name->start, name->length); 23501563Svbart@nginx.com lhq.key = *name; 23511563Svbart@nginx.com lhq.proto = &nxt_router_apps_hash_proto; 23521563Svbart@nginx.com 23531563Svbart@nginx.com if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) { 23541563Svbart@nginx.com return NULL; 23551563Svbart@nginx.com } 23561563Svbart@nginx.com 23571563Svbart@nginx.com return lhq.value; 23581563Svbart@nginx.com } 23591563Svbart@nginx.com 23601563Svbart@nginx.com 23611563Svbart@nginx.com static void 23621563Svbart@nginx.com nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i) 23631563Svbart@nginx.com { 23641563Svbart@nginx.com nxt_app_t *app; 23651563Svbart@nginx.com nxt_lvlhsh_each_t lhe; 23661563Svbart@nginx.com 23671563Svbart@nginx.com nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto); 23681563Svbart@nginx.com 23691563Svbart@nginx.com for ( ;; ) { 23701563Svbart@nginx.com app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe); 23711563Svbart@nginx.com 23721563Svbart@nginx.com if (app == NULL) { 23731563Svbart@nginx.com break; 23741563Svbart@nginx.com } 23751563Svbart@nginx.com 23761563Svbart@nginx.com nxt_router_app_use(task, app, i); 23771563Svbart@nginx.com } 23781563Svbart@nginx.com } 23791563Svbart@nginx.com 23801563Svbart@nginx.com 23811925Sz.hong@f5.com typedef struct { 23821925Sz.hong@f5.com nxt_app_t *app; 23831925Sz.hong@f5.com nxt_int_t target; 23841925Sz.hong@f5.com } nxt_http_app_conf_t; 23851925Sz.hong@f5.com 23861563Svbart@nginx.com 23871563Svbart@nginx.com nxt_int_t 23881925Sz.hong@f5.com nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name, 23891925Sz.hong@f5.com nxt_str_t *target, nxt_http_action_t *action) 2390133Sigor@sysoev.ru { 23911925Sz.hong@f5.com nxt_app_t *app; 23921925Sz.hong@f5.com nxt_str_t *targets; 23931925Sz.hong@f5.com nxt_uint_t i; 23941925Sz.hong@f5.com nxt_http_app_conf_t *conf; 2395133Sigor@sysoev.ru 23961563Svbart@nginx.com app = nxt_router_apps_hash_get(rtcf, name); 2397133Sigor@sysoev.ru if (app == NULL) { 23981563Svbart@nginx.com return NXT_DECLINED; 2399133Sigor@sysoev.ru } 2400133Sigor@sysoev.ru 24011925Sz.hong@f5.com conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t)); 24021925Sz.hong@f5.com if (nxt_slow_path(conf == NULL)) { 24031925Sz.hong@f5.com return NXT_ERROR; 24041925Sz.hong@f5.com } 24051925Sz.hong@f5.com 24061392Sigor@sysoev.ru action->handler = nxt_http_application_handler; 24071925Sz.hong@f5.com action->u.conf = conf; 24081925Sz.hong@f5.com 24091925Sz.hong@f5.com conf->app = app; 24101925Sz.hong@f5.com 24111925Sz.hong@f5.com if (target != NULL && target->length != 0) { 24121925Sz.hong@f5.com targets = app->targets; 24131925Sz.hong@f5.com 24141925Sz.hong@f5.com for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++); 24151925Sz.hong@f5.com 24161925Sz.hong@f5.com conf->target = i; 24171925Sz.hong@f5.com 24181925Sz.hong@f5.com } else { 24191925Sz.hong@f5.com conf->target = 0; 24201925Sz.hong@f5.com } 24211563Svbart@nginx.com 24221563Svbart@nginx.com return NXT_OK; 242353Sigor@sysoev.ru } 242453Sigor@sysoev.ru 242553Sigor@sysoev.ru 242653Sigor@sysoev.ru static nxt_socket_conf_t * 2427359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2428359Sigor@sysoev.ru nxt_str_t *name) 242953Sigor@sysoev.ru { 2430359Sigor@sysoev.ru size_t size; 2431359Sigor@sysoev.ru nxt_int_t ret; 2432359Sigor@sysoev.ru nxt_bool_t wildcard; 2433359Sigor@sysoev.ru nxt_sockaddr_t *sa; 2434359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2435359Sigor@sysoev.ru nxt_listen_socket_t *ls; 2436359Sigor@sysoev.ru 2437359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 2438359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 2439564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 2440359Sigor@sysoev.ru return NULL; 2441359Sigor@sysoev.ru } 2442359Sigor@sysoev.ru 2443359Sigor@sysoev.ru sa->type = SOCK_STREAM; 2444359Sigor@sysoev.ru 2445359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 2446493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 2447359Sigor@sysoev.ru 2448591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 2449163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 245053Sigor@sysoev.ru return NULL; 245153Sigor@sysoev.ru } 245253Sigor@sysoev.ru 2453359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 2454359Sigor@sysoev.ru 2455359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 2456359Sigor@sysoev.ru 2457359Sigor@sysoev.ru if (ret != NXT_OK) { 2458359Sigor@sysoev.ru 2459359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 2460359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 2461359Sigor@sysoev.ru return NULL; 2462359Sigor@sysoev.ru } 2463359Sigor@sysoev.ru 2464359Sigor@sysoev.ru skcf->listen = ls; 2465359Sigor@sysoev.ru 2466359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 2467359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 2468359Sigor@sysoev.ru 2469359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 2470359Sigor@sysoev.ru 2471359Sigor@sysoev.ru ls->socket = -1; 2472359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 2473359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 2474359Sigor@sysoev.ru ls->read_after_accept = 1; 2475359Sigor@sysoev.ru } 2476359Sigor@sysoev.ru 2477359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 2478359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 2479359Sigor@sysoev.ru case AF_UNIX: 2480359Sigor@sysoev.ru wildcard = 0; 2481359Sigor@sysoev.ru break; 2482359Sigor@sysoev.ru #endif 2483359Sigor@sysoev.ru #if (NXT_INET6) 2484359Sigor@sysoev.ru case AF_INET6: 2485359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 2486359Sigor@sysoev.ru break; 2487359Sigor@sysoev.ru #endif 2488359Sigor@sysoev.ru case AF_INET: 2489359Sigor@sysoev.ru default: 2490359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 2491359Sigor@sysoev.ru break; 2492359Sigor@sysoev.ru } 2493359Sigor@sysoev.ru 2494359Sigor@sysoev.ru if (!wildcard) { 2495591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 2496359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 2497359Sigor@sysoev.ru return NULL; 2498359Sigor@sysoev.ru } 2499359Sigor@sysoev.ru 2500359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 2501359Sigor@sysoev.ru } 2502163Smax.romanov@nginx.com 2503163Smax.romanov@nginx.com return skcf; 250453Sigor@sysoev.ru } 250553Sigor@sysoev.ru 250653Sigor@sysoev.ru 2507359Sigor@sysoev.ru static nxt_int_t 2508359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 2509359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 251053Sigor@sysoev.ru { 2511359Sigor@sysoev.ru nxt_router_t *router; 2512359Sigor@sysoev.ru nxt_queue_link_t *qlk; 2513359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2514359Sigor@sysoev.ru 2515591Sigor@sysoev.ru router = tmcf->router_conf->router; 2516359Sigor@sysoev.ru 2517359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 2518359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 2519359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 252053Sigor@sysoev.ru { 2521359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2522359Sigor@sysoev.ru 2523359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 2524359Sigor@sysoev.ru nskcf->listen = skcf->listen; 2525359Sigor@sysoev.ru 2526359Sigor@sysoev.ru nxt_queue_remove(qlk); 25271509Sigor@sysoev.ru nxt_queue_insert_tail(&keeping_sockets, qlk); 25281509Sigor@sysoev.ru 25291509Sigor@sysoev.ru nxt_queue_insert_tail(&updating_sockets, &nskcf->link); 2530359Sigor@sysoev.ru 2531359Sigor@sysoev.ru return NXT_OK; 253253Sigor@sysoev.ru } 253353Sigor@sysoev.ru } 253453Sigor@sysoev.ru 25351509Sigor@sysoev.ru nxt_queue_insert_tail(&pending_sockets, &nskcf->link); 2536359Sigor@sysoev.ru 2537359Sigor@sysoev.ru return NXT_DECLINED; 253853Sigor@sysoev.ru } 253953Sigor@sysoev.ru 254053Sigor@sysoev.ru 2541198Sigor@sysoev.ru static void 2542198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 2543198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 2544198Sigor@sysoev.ru { 2545358Sigor@sysoev.ru size_t size; 2546198Sigor@sysoev.ru uint32_t stream; 2547648Svbart@nginx.com nxt_int_t ret; 2548198Sigor@sysoev.ru nxt_buf_t *b; 2549198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 2550198Sigor@sysoev.ru nxt_runtime_t *rt; 2551198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 2552198Sigor@sysoev.ru 2553198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2554198Sigor@sysoev.ru if (rpc == NULL) { 2555198Sigor@sysoev.ru goto fail; 2556198Sigor@sysoev.ru } 2557198Sigor@sysoev.ru 2558198Sigor@sysoev.ru rpc->socket_conf = skcf; 2559198Sigor@sysoev.ru rpc->temp_conf = tmcf; 2560198Sigor@sysoev.ru 2561359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 2562358Sigor@sysoev.ru 2563358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2564198Sigor@sysoev.ru if (b == NULL) { 2565198Sigor@sysoev.ru goto fail; 2566198Sigor@sysoev.ru } 2567198Sigor@sysoev.ru 25681940Sz.hong@f5.com b->completion_handler = nxt_buf_dummy_completion; 25691566Smax.romanov@nginx.com 2570359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 2571198Sigor@sysoev.ru 2572198Sigor@sysoev.ru rt = task->thread->runtime; 2573240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2574198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2575198Sigor@sysoev.ru 2576198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 2577198Sigor@sysoev.ru nxt_router_listen_socket_ready, 2578198Sigor@sysoev.ru nxt_router_listen_socket_error, 2579198Sigor@sysoev.ru main_port->pid, rpc); 2580645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 2581198Sigor@sysoev.ru goto fail; 2582198Sigor@sysoev.ru } 2583198Sigor@sysoev.ru 2584648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 2585648Svbart@nginx.com stream, router_port->id, b); 2586648Svbart@nginx.com 2587648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2588648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2589648Svbart@nginx.com goto fail; 2590648Svbart@nginx.com } 2591198Sigor@sysoev.ru 2592198Sigor@sysoev.ru return; 2593198Sigor@sysoev.ru 2594198Sigor@sysoev.ru fail: 2595198Sigor@sysoev.ru 2596198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 2597198Sigor@sysoev.ru } 2598198Sigor@sysoev.ru 2599198Sigor@sysoev.ru 2600198Sigor@sysoev.ru static void 2601198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2602198Sigor@sysoev.ru void *data) 260353Sigor@sysoev.ru { 2604359Sigor@sysoev.ru nxt_int_t ret; 2605359Sigor@sysoev.ru nxt_socket_t s; 2606359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 260753Sigor@sysoev.ru 2608198Sigor@sysoev.ru rpc = data; 2609198Sigor@sysoev.ru 26101558Smax.romanov@nginx.com s = msg->fd[0]; 2611198Sigor@sysoev.ru 2612198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 2613198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2614198Sigor@sysoev.ru goto fail; 261553Sigor@sysoev.ru } 261653Sigor@sysoev.ru 2617359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 2618198Sigor@sysoev.ru 2619198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 2620198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2621198Sigor@sysoev.ru goto fail; 2622198Sigor@sysoev.ru } 2623198Sigor@sysoev.ru 2624359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 2625198Sigor@sysoev.ru 2626198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2627198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2628198Sigor@sysoev.ru 2629198Sigor@sysoev.ru return; 2630148Sigor@sysoev.ru 2631148Sigor@sysoev.ru fail: 2632148Sigor@sysoev.ru 2633148Sigor@sysoev.ru nxt_socket_close(task, s); 2634148Sigor@sysoev.ru 2635198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2636198Sigor@sysoev.ru } 2637198Sigor@sysoev.ru 2638198Sigor@sysoev.ru 2639198Sigor@sysoev.ru static void 2640198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2641198Sigor@sysoev.ru void *data) 2642198Sigor@sysoev.ru { 2643955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2644955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2645955Svbart@nginx.com 2646955Svbart@nginx.com rpc = data; 2647955Svbart@nginx.com tmcf = rpc->temp_conf; 2648955Svbart@nginx.com 2649955Svbart@nginx.com #if 0 2650198Sigor@sysoev.ru u_char *p; 2651198Sigor@sysoev.ru size_t size; 2652198Sigor@sysoev.ru uint8_t error; 2653198Sigor@sysoev.ru nxt_buf_t *in, *out; 2654198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2655198Sigor@sysoev.ru 2656198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2657198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2658198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2659198Sigor@sysoev.ru nxt_string("ListenerPort"), 2660198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2661198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2662198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2663198Sigor@sysoev.ru nxt_string("ListenerPath"), 2664198Sigor@sysoev.ru }; 2665198Sigor@sysoev.ru 2666359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2667352Smax.romanov@nginx.com 2668352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2669352Smax.romanov@nginx.com 2670551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2671551Smax.romanov@nginx.com return; 2672551Smax.romanov@nginx.com } 2673352Smax.romanov@nginx.com 2674198Sigor@sysoev.ru p = in->mem.pos; 2675198Sigor@sysoev.ru 2676198Sigor@sysoev.ru error = *p++; 2677198Sigor@sysoev.ru 2678703Svbart@nginx.com size = nxt_length("listen socket error: ") 2679703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2680198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2681198Sigor@sysoev.ru 2682198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2683198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2684198Sigor@sysoev.ru return; 2685198Sigor@sysoev.ru } 2686198Sigor@sysoev.ru 2687198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2688198Sigor@sysoev.ru "listen socket error: " 2689198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2690493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2691198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2692198Sigor@sysoev.ru 2693198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2694955Svbart@nginx.com #endif 2695198Sigor@sysoev.ru 2696198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 269753Sigor@sysoev.ru } 269853Sigor@sysoev.ru 269953Sigor@sysoev.ru 2700774Svbart@nginx.com #if (NXT_TLS) 2701774Svbart@nginx.com 2702774Svbart@nginx.com static void 2703774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2704774Svbart@nginx.com void *data) 2705774Svbart@nginx.com { 27061828Sa.suvorov@f5.com nxt_mp_t *mp; 27071828Sa.suvorov@f5.com nxt_int_t ret; 27081828Sa.suvorov@f5.com nxt_tls_conf_t *tlscf; 27091885Sa.suvorov@f5.com nxt_router_tlssock_t *tls; 27101828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 27111828Sa.suvorov@f5.com nxt_router_temp_conf_t *tmcf; 2712774Svbart@nginx.com 2713774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2714774Svbart@nginx.com 27151885Sa.suvorov@f5.com tls = data; 27161885Sa.suvorov@f5.com tmcf = tls->temp_conf; 2717774Svbart@nginx.com 2718774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2719774Svbart@nginx.com goto fail; 2720774Svbart@nginx.com } 2721774Svbart@nginx.com 2722774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2723774Svbart@nginx.com 27241885Sa.suvorov@f5.com if (tls->socket_conf->tls == NULL){ 27251828Sa.suvorov@f5.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 27261828Sa.suvorov@f5.com if (nxt_slow_path(tlscf == NULL)) { 27271828Sa.suvorov@f5.com goto fail; 27281828Sa.suvorov@f5.com } 27291828Sa.suvorov@f5.com 27301884Sa.suvorov@f5.com tlscf->no_wait_shutdown = 1; 27311885Sa.suvorov@f5.com tls->socket_conf->tls = tlscf; 27321828Sa.suvorov@f5.com 27331828Sa.suvorov@f5.com } else { 27341885Sa.suvorov@f5.com tlscf = tls->socket_conf->tls; 27351828Sa.suvorov@f5.com } 27361828Sa.suvorov@f5.com 27371920Sa.suvorov@f5.com tls->tls_init->conf = tlscf; 27381920Sa.suvorov@f5.com 27391828Sa.suvorov@f5.com bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t)); 27401828Sa.suvorov@f5.com if (nxt_slow_path(bundle == NULL)) { 2741774Svbart@nginx.com goto fail; 2742774Svbart@nginx.com } 2743774Svbart@nginx.com 27441885Sa.suvorov@f5.com if (nxt_slow_path(nxt_str_dup(mp, &bundle->name, &tls->name) == NULL)) { 27451885Sa.suvorov@f5.com goto fail; 27461885Sa.suvorov@f5.com } 27471885Sa.suvorov@f5.com 27481828Sa.suvorov@f5.com bundle->chain_file = msg->fd[0]; 27491828Sa.suvorov@f5.com bundle->next = tlscf->bundle; 27501828Sa.suvorov@f5.com tlscf->bundle = bundle; 27511828Sa.suvorov@f5.com 27521920Sa.suvorov@f5.com ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init, 27531920Sa.suvorov@f5.com tls->last); 2754774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2755774Svbart@nginx.com goto fail; 2756774Svbart@nginx.com } 2757774Svbart@nginx.com 2758774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2759774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2760774Svbart@nginx.com return; 2761774Svbart@nginx.com 2762774Svbart@nginx.com fail: 2763774Svbart@nginx.com 2764774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2765774Svbart@nginx.com } 2766774Svbart@nginx.com 2767774Svbart@nginx.com #endif 2768774Svbart@nginx.com 2769774Svbart@nginx.com 2770507Smax.romanov@nginx.com static void 2771507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2772507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2773507Smax.romanov@nginx.com { 2774507Smax.romanov@nginx.com size_t size; 2775507Smax.romanov@nginx.com uint32_t stream; 2776648Svbart@nginx.com nxt_int_t ret; 2777507Smax.romanov@nginx.com nxt_buf_t *b; 2778*1998St.nateldemoura@f5.com nxt_port_t *router_port, *dport; 2779507Smax.romanov@nginx.com nxt_runtime_t *rt; 2780507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2781507Smax.romanov@nginx.com 2782*1998St.nateldemoura@f5.com rt = task->thread->runtime; 2783*1998St.nateldemoura@f5.com 2784*1998St.nateldemoura@f5.com dport = app->proto_port; 2785*1998St.nateldemoura@f5.com 2786*1998St.nateldemoura@f5.com if (dport == NULL) { 2787*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' prototype prefork", &app->name); 2788*1998St.nateldemoura@f5.com 2789*1998St.nateldemoura@f5.com size = app->name.length + 1 + app->conf.length; 2790*1998St.nateldemoura@f5.com 2791*1998St.nateldemoura@f5.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2792*1998St.nateldemoura@f5.com if (nxt_slow_path(b == NULL)) { 2793*1998St.nateldemoura@f5.com goto fail; 2794*1998St.nateldemoura@f5.com } 2795*1998St.nateldemoura@f5.com 2796*1998St.nateldemoura@f5.com b->completion_handler = nxt_buf_dummy_completion; 2797*1998St.nateldemoura@f5.com 2798*1998St.nateldemoura@f5.com nxt_buf_cpystr(b, &app->name); 2799*1998St.nateldemoura@f5.com *b->mem.free++ = '\0'; 2800*1998St.nateldemoura@f5.com nxt_buf_cpystr(b, &app->conf); 2801*1998St.nateldemoura@f5.com 2802*1998St.nateldemoura@f5.com dport = rt->port_by_type[NXT_PROCESS_MAIN]; 2803*1998St.nateldemoura@f5.com 2804*1998St.nateldemoura@f5.com } else { 2805*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' prefork", &app->name); 2806*1998St.nateldemoura@f5.com 2807*1998St.nateldemoura@f5.com b = NULL; 2808*1998St.nateldemoura@f5.com } 2809*1998St.nateldemoura@f5.com 2810*1998St.nateldemoura@f5.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2811*1998St.nateldemoura@f5.com 2812*1998St.nateldemoura@f5.com rpc = nxt_port_rpc_register_handler_ex(task, router_port, 2813*1998St.nateldemoura@f5.com nxt_router_app_prefork_ready, 2814*1998St.nateldemoura@f5.com nxt_router_app_prefork_error, 2815*1998St.nateldemoura@f5.com sizeof(nxt_app_rpc_t)); 2816*1998St.nateldemoura@f5.com if (nxt_slow_path(rpc == NULL)) { 2817507Smax.romanov@nginx.com goto fail; 2818507Smax.romanov@nginx.com } 2819507Smax.romanov@nginx.com 2820507Smax.romanov@nginx.com rpc->app = app; 2821507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2822*1998St.nateldemoura@f5.com rpc->proto = (b != NULL); 2823*1998St.nateldemoura@f5.com 2824*1998St.nateldemoura@f5.com stream = nxt_port_rpc_ex_stream(rpc); 2825*1998St.nateldemoura@f5.com 2826*1998St.nateldemoura@f5.com ret = nxt_port_socket_write(task, dport, 2827*1998St.nateldemoura@f5.com NXT_PORT_MSG_START_PROCESS, 28281488St.nateldemoura@f5.com -1, stream, router_port->id, b); 2829648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2830648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2831648Svbart@nginx.com goto fail; 2832648Svbart@nginx.com } 2833648Svbart@nginx.com 2834*1998St.nateldemoura@f5.com if (b == NULL) { 2835*1998St.nateldemoura@f5.com nxt_port_rpc_ex_set_peer(task, router_port, rpc, dport->pid); 2836*1998St.nateldemoura@f5.com 2837*1998St.nateldemoura@f5.com app->pending_processes++; 2838*1998St.nateldemoura@f5.com } 2839507Smax.romanov@nginx.com 2840507Smax.romanov@nginx.com return; 2841507Smax.romanov@nginx.com 2842507Smax.romanov@nginx.com fail: 2843507Smax.romanov@nginx.com 2844507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2845507Smax.romanov@nginx.com } 2846507Smax.romanov@nginx.com 2847507Smax.romanov@nginx.com 2848507Smax.romanov@nginx.com static void 2849507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2850507Smax.romanov@nginx.com void *data) 2851507Smax.romanov@nginx.com { 2852507Smax.romanov@nginx.com nxt_app_t *app; 2853507Smax.romanov@nginx.com nxt_port_t *port; 2854507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2855507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2856507Smax.romanov@nginx.com 2857507Smax.romanov@nginx.com rpc = data; 2858507Smax.romanov@nginx.com app = rpc->app; 2859507Smax.romanov@nginx.com 2860507Smax.romanov@nginx.com port = msg->u.new_port; 28611547Smax.romanov@nginx.com 28621547Smax.romanov@nginx.com nxt_assert(port != NULL); 2863*1998St.nateldemoura@f5.com nxt_assert(port->id == 0); 2864*1998St.nateldemoura@f5.com 2865*1998St.nateldemoura@f5.com if (rpc->proto) { 2866*1998St.nateldemoura@f5.com nxt_assert(app->proto_port == NULL); 2867*1998St.nateldemoura@f5.com nxt_assert(port->type == NXT_PROCESS_PROTOTYPE); 2868*1998St.nateldemoura@f5.com 2869*1998St.nateldemoura@f5.com nxt_port_inc_use(port); 2870*1998St.nateldemoura@f5.com 2871*1998St.nateldemoura@f5.com app->proto_port = port; 2872*1998St.nateldemoura@f5.com port->app = app; 2873*1998St.nateldemoura@f5.com 2874*1998St.nateldemoura@f5.com nxt_router_app_rpc_create(task, rpc->temp_conf, app); 2875*1998St.nateldemoura@f5.com 2876*1998St.nateldemoura@f5.com return; 2877*1998St.nateldemoura@f5.com } 2878*1998St.nateldemoura@f5.com 28791547Smax.romanov@nginx.com nxt_assert(port->type == NXT_PROCESS_APP); 28801547Smax.romanov@nginx.com 2881507Smax.romanov@nginx.com port->app = app; 28821547Smax.romanov@nginx.com port->main_app_port = port; 2883507Smax.romanov@nginx.com 2884507Smax.romanov@nginx.com app->pending_processes--; 2885507Smax.romanov@nginx.com app->processes++; 2886507Smax.romanov@nginx.com app->idle_processes++; 2887507Smax.romanov@nginx.com 2888507Smax.romanov@nginx.com engine = task->thread->engine; 2889507Smax.romanov@nginx.com 2890507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2891507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 28921549Smax.romanov@nginx.com 28931549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move new port %PI:%d to spare_ports", 28941549Smax.romanov@nginx.com &app->name, port->pid, port->id); 28951549Smax.romanov@nginx.com 28961547Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 28971547Smax.romanov@nginx.com app->port_hash_count++; 2898507Smax.romanov@nginx.com 2899507Smax.romanov@nginx.com port->idle_start = 0; 2900507Smax.romanov@nginx.com 2901507Smax.romanov@nginx.com nxt_port_inc_use(port); 2902507Smax.romanov@nginx.com 29031547Smax.romanov@nginx.com nxt_router_app_shared_port_send(task, port); 29041547Smax.romanov@nginx.com 2905507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2906507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2907507Smax.romanov@nginx.com } 2908507Smax.romanov@nginx.com 2909507Smax.romanov@nginx.com 2910507Smax.romanov@nginx.com static void 2911507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2912507Smax.romanov@nginx.com void *data) 2913507Smax.romanov@nginx.com { 2914507Smax.romanov@nginx.com nxt_app_t *app; 2915507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2916507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2917507Smax.romanov@nginx.com 2918507Smax.romanov@nginx.com rpc = data; 2919507Smax.romanov@nginx.com app = rpc->app; 2920507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2921507Smax.romanov@nginx.com 2922*1998St.nateldemoura@f5.com if (rpc->proto) { 2923*1998St.nateldemoura@f5.com nxt_log(task, NXT_LOG_WARN, "failed to start prototype \"%V\"", 2924*1998St.nateldemoura@f5.com &app->name); 2925*1998St.nateldemoura@f5.com 2926*1998St.nateldemoura@f5.com } else { 2927*1998St.nateldemoura@f5.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2928*1998St.nateldemoura@f5.com &app->name); 2929*1998St.nateldemoura@f5.com 2930*1998St.nateldemoura@f5.com app->pending_processes--; 2931*1998St.nateldemoura@f5.com } 2932507Smax.romanov@nginx.com 2933507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2934507Smax.romanov@nginx.com } 2935507Smax.romanov@nginx.com 2936507Smax.romanov@nginx.com 293753Sigor@sysoev.ru static nxt_int_t 293853Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 293953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 294053Sigor@sysoev.ru { 294153Sigor@sysoev.ru nxt_int_t ret; 294253Sigor@sysoev.ru nxt_uint_t n, threads; 294353Sigor@sysoev.ru nxt_queue_link_t *qlk; 294453Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 294553Sigor@sysoev.ru 2946591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 294753Sigor@sysoev.ru 294853Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 294953Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 295053Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 295153Sigor@sysoev.ru return NXT_ERROR; 295253Sigor@sysoev.ru } 295353Sigor@sysoev.ru 295453Sigor@sysoev.ru n = 0; 295553Sigor@sysoev.ru 295653Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 295753Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 295853Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 295953Sigor@sysoev.ru { 296053Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 296153Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 296253Sigor@sysoev.ru return NXT_ERROR; 296353Sigor@sysoev.ru } 296453Sigor@sysoev.ru 2965115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 296653Sigor@sysoev.ru 296753Sigor@sysoev.ru if (n < threads) { 2968315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2969115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 297053Sigor@sysoev.ru 297153Sigor@sysoev.ru } else { 2972315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2973115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 297453Sigor@sysoev.ru } 297553Sigor@sysoev.ru 297653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 297753Sigor@sysoev.ru return ret; 297853Sigor@sysoev.ru } 297953Sigor@sysoev.ru 298053Sigor@sysoev.ru n++; 298153Sigor@sysoev.ru } 298253Sigor@sysoev.ru 298353Sigor@sysoev.ru tmcf->new_threads = n; 298453Sigor@sysoev.ru 298553Sigor@sysoev.ru while (n < threads) { 298653Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 298753Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 298853Sigor@sysoev.ru return NXT_ERROR; 298953Sigor@sysoev.ru } 299053Sigor@sysoev.ru 2991315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2992315Sigor@sysoev.ru 299353Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 299453Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 299553Sigor@sysoev.ru return NXT_ERROR; 299653Sigor@sysoev.ru } 299753Sigor@sysoev.ru 2998115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 299953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 300053Sigor@sysoev.ru return ret; 300153Sigor@sysoev.ru } 300253Sigor@sysoev.ru 300353Sigor@sysoev.ru n++; 300453Sigor@sysoev.ru } 300553Sigor@sysoev.ru 300653Sigor@sysoev.ru return NXT_OK; 300753Sigor@sysoev.ru } 300853Sigor@sysoev.ru 300953Sigor@sysoev.ru 301053Sigor@sysoev.ru static nxt_int_t 3011115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 3012115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 301353Sigor@sysoev.ru { 3014359Sigor@sysoev.ru nxt_int_t ret; 301553Sigor@sysoev.ru 30161509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, 3017154Sigor@sysoev.ru nxt_router_listen_socket_create); 3018115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3019115Sigor@sysoev.ru return ret; 3020115Sigor@sysoev.ru } 3021115Sigor@sysoev.ru 30221509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, 3023154Sigor@sysoev.ru nxt_router_listen_socket_create); 302453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 302553Sigor@sysoev.ru return ret; 302653Sigor@sysoev.ru } 302753Sigor@sysoev.ru 3028115Sigor@sysoev.ru return ret; 302953Sigor@sysoev.ru } 303053Sigor@sysoev.ru 303153Sigor@sysoev.ru 303253Sigor@sysoev.ru static nxt_int_t 3033115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 3034115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 303553Sigor@sysoev.ru { 3036359Sigor@sysoev.ru nxt_int_t ret; 303753Sigor@sysoev.ru 30381509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &creating_sockets, 3039154Sigor@sysoev.ru nxt_router_listen_socket_create); 304053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 304153Sigor@sysoev.ru return ret; 304253Sigor@sysoev.ru } 304353Sigor@sysoev.ru 30441509Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &updating_sockets, 3045154Sigor@sysoev.ru nxt_router_listen_socket_update); 304653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 304753Sigor@sysoev.ru return ret; 304853Sigor@sysoev.ru } 304953Sigor@sysoev.ru 30501509Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); 3051115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3052115Sigor@sysoev.ru return ret; 3053115Sigor@sysoev.ru } 3054115Sigor@sysoev.ru 3055115Sigor@sysoev.ru return ret; 305653Sigor@sysoev.ru } 305753Sigor@sysoev.ru 305853Sigor@sysoev.ru 305953Sigor@sysoev.ru static nxt_int_t 3060115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 3061115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 306253Sigor@sysoev.ru { 306353Sigor@sysoev.ru nxt_int_t ret; 306453Sigor@sysoev.ru 3065313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 3066313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3067313Sigor@sysoev.ru return ret; 3068313Sigor@sysoev.ru } 3069313Sigor@sysoev.ru 30701509Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &updating_sockets); 307153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 307253Sigor@sysoev.ru return ret; 307353Sigor@sysoev.ru } 307453Sigor@sysoev.ru 30751509Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &deleting_sockets); 307653Sigor@sysoev.ru } 307753Sigor@sysoev.ru 307853Sigor@sysoev.ru 307953Sigor@sysoev.ru static nxt_int_t 3080154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 3081154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 308253Sigor@sysoev.ru nxt_work_handler_t handler) 308353Sigor@sysoev.ru { 30841394Sigor@sysoev.ru nxt_int_t ret; 3085153Sigor@sysoev.ru nxt_joint_job_t *job; 308653Sigor@sysoev.ru nxt_queue_link_t *qlk; 3087155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 308853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 308953Sigor@sysoev.ru 309053Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 309153Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 309253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 309353Sigor@sysoev.ru { 3094154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 3095153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 3096139Sigor@sysoev.ru return NXT_ERROR; 3097139Sigor@sysoev.ru } 3098139Sigor@sysoev.ru 3099154Sigor@sysoev.ru job->work.next = recf->jobs; 3100154Sigor@sysoev.ru recf->jobs = &job->work; 3101154Sigor@sysoev.ru 3102153Sigor@sysoev.ru job->task = tmcf->engine->task; 3103153Sigor@sysoev.ru job->work.handler = handler; 3104153Sigor@sysoev.ru job->work.task = &job->task; 3105153Sigor@sysoev.ru job->work.obj = job; 3106153Sigor@sysoev.ru job->tmcf = tmcf; 310753Sigor@sysoev.ru 3108154Sigor@sysoev.ru tmcf->count++; 3109154Sigor@sysoev.ru 3110591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 3111154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 311253Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 311353Sigor@sysoev.ru return NXT_ERROR; 311453Sigor@sysoev.ru } 311553Sigor@sysoev.ru 3116153Sigor@sysoev.ru job->work.data = joint; 311753Sigor@sysoev.ru 31181394Sigor@sysoev.ru ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams); 31191394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 31201394Sigor@sysoev.ru return ret; 31211394Sigor@sysoev.ru } 31221394Sigor@sysoev.ru 312353Sigor@sysoev.ru joint->count = 1; 3124155Sigor@sysoev.ru 3125155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 3126155Sigor@sysoev.ru skcf->count++; 3127155Sigor@sysoev.ru joint->socket_conf = skcf; 3128155Sigor@sysoev.ru 312988Smax.romanov@nginx.com joint->engine = recf->engine; 313053Sigor@sysoev.ru } 313153Sigor@sysoev.ru 313220Sigor@sysoev.ru return NXT_OK; 313320Sigor@sysoev.ru } 313420Sigor@sysoev.ru 313520Sigor@sysoev.ru 313620Sigor@sysoev.ru static nxt_int_t 3137313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 3138313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 3139313Sigor@sysoev.ru { 3140313Sigor@sysoev.ru nxt_joint_job_t *job; 3141313Sigor@sysoev.ru 3142313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 3143313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 3144313Sigor@sysoev.ru return NXT_ERROR; 3145313Sigor@sysoev.ru } 3146313Sigor@sysoev.ru 3147313Sigor@sysoev.ru job->work.next = recf->jobs; 3148313Sigor@sysoev.ru recf->jobs = &job->work; 3149313Sigor@sysoev.ru 3150313Sigor@sysoev.ru job->task = tmcf->engine->task; 3151313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 3152313Sigor@sysoev.ru job->work.task = &job->task; 3153313Sigor@sysoev.ru job->work.obj = NULL; 3154313Sigor@sysoev.ru job->work.data = NULL; 3155313Sigor@sysoev.ru job->tmcf = NULL; 3156313Sigor@sysoev.ru 3157313Sigor@sysoev.ru return NXT_OK; 3158313Sigor@sysoev.ru } 3159313Sigor@sysoev.ru 3160313Sigor@sysoev.ru 3161313Sigor@sysoev.ru static nxt_int_t 3162139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 3163139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 316420Sigor@sysoev.ru { 3165153Sigor@sysoev.ru nxt_joint_job_t *job; 316653Sigor@sysoev.ru nxt_queue_link_t *qlk; 316720Sigor@sysoev.ru 316853Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 316953Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 317053Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 317153Sigor@sysoev.ru { 3172154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 3173153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 3174139Sigor@sysoev.ru return NXT_ERROR; 3175139Sigor@sysoev.ru } 3176139Sigor@sysoev.ru 3177154Sigor@sysoev.ru job->work.next = recf->jobs; 3178154Sigor@sysoev.ru recf->jobs = &job->work; 3179154Sigor@sysoev.ru 3180153Sigor@sysoev.ru job->task = tmcf->engine->task; 3181153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 3182153Sigor@sysoev.ru job->work.task = &job->task; 3183153Sigor@sysoev.ru job->work.obj = job; 3184153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 3185153Sigor@sysoev.ru job->tmcf = tmcf; 3186154Sigor@sysoev.ru 3187154Sigor@sysoev.ru tmcf->count++; 318820Sigor@sysoev.ru } 318920Sigor@sysoev.ru 319053Sigor@sysoev.ru return NXT_OK; 319153Sigor@sysoev.ru } 319220Sigor@sysoev.ru 319320Sigor@sysoev.ru 319453Sigor@sysoev.ru static nxt_int_t 319553Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 319653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 319753Sigor@sysoev.ru { 319853Sigor@sysoev.ru nxt_int_t ret; 319953Sigor@sysoev.ru nxt_uint_t i, threads; 320053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 320120Sigor@sysoev.ru 320253Sigor@sysoev.ru recf = tmcf->engines->elts; 3203591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 320420Sigor@sysoev.ru 320553Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 320653Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 320753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 320853Sigor@sysoev.ru return ret; 320953Sigor@sysoev.ru } 321020Sigor@sysoev.ru } 321120Sigor@sysoev.ru 321220Sigor@sysoev.ru return NXT_OK; 321320Sigor@sysoev.ru } 321453Sigor@sysoev.ru 321553Sigor@sysoev.ru 321653Sigor@sysoev.ru static nxt_int_t 321753Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 321853Sigor@sysoev.ru nxt_event_engine_t *engine) 321953Sigor@sysoev.ru { 322053Sigor@sysoev.ru nxt_int_t ret; 322153Sigor@sysoev.ru nxt_thread_link_t *link; 322253Sigor@sysoev.ru nxt_thread_handle_t handle; 322353Sigor@sysoev.ru 322453Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 322553Sigor@sysoev.ru 322653Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 322753Sigor@sysoev.ru return NXT_ERROR; 322853Sigor@sysoev.ru } 322953Sigor@sysoev.ru 323053Sigor@sysoev.ru link->start = nxt_router_thread_start; 323153Sigor@sysoev.ru link->engine = engine; 323253Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 323353Sigor@sysoev.ru link->work.task = task; 323453Sigor@sysoev.ru link->work.data = link; 323553Sigor@sysoev.ru 323653Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 323753Sigor@sysoev.ru 323853Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 323953Sigor@sysoev.ru 324053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 324153Sigor@sysoev.ru nxt_queue_remove(&engine->link); 324253Sigor@sysoev.ru } 324353Sigor@sysoev.ru 324453Sigor@sysoev.ru return ret; 324553Sigor@sysoev.ru } 324653Sigor@sysoev.ru 324753Sigor@sysoev.ru 324853Sigor@sysoev.ru static void 3249343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 3250343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 3251133Sigor@sysoev.ru { 3252507Smax.romanov@nginx.com nxt_app_t *app; 3253141Smax.romanov@nginx.com 3254141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 3255133Sigor@sysoev.ru 3256753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 3257343Smax.romanov@nginx.com 3258141Smax.romanov@nginx.com } nxt_queue_loop; 3259133Sigor@sysoev.ru 3260133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 3261133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 3262133Sigor@sysoev.ru } 3263133Sigor@sysoev.ru 3264133Sigor@sysoev.ru 3265133Sigor@sysoev.ru static void 3266315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 326753Sigor@sysoev.ru { 326853Sigor@sysoev.ru nxt_uint_t n; 3269315Sigor@sysoev.ru nxt_event_engine_t *engine; 327053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 327153Sigor@sysoev.ru 327253Sigor@sysoev.ru recf = tmcf->engines->elts; 327353Sigor@sysoev.ru 327453Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 3275315Sigor@sysoev.ru engine = recf->engine; 3276315Sigor@sysoev.ru 3277315Sigor@sysoev.ru switch (recf->action) { 3278315Sigor@sysoev.ru 3279315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 3280315Sigor@sysoev.ru break; 3281315Sigor@sysoev.ru 3282315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 3283315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 3284315Sigor@sysoev.ru break; 3285315Sigor@sysoev.ru 3286315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 3287315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 3288315Sigor@sysoev.ru break; 3289315Sigor@sysoev.ru } 3290315Sigor@sysoev.ru 3291316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 3292316Sigor@sysoev.ru 329353Sigor@sysoev.ru recf++; 329453Sigor@sysoev.ru } 329553Sigor@sysoev.ru } 329653Sigor@sysoev.ru 329753Sigor@sysoev.ru 329853Sigor@sysoev.ru static void 3299315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 330053Sigor@sysoev.ru { 3301154Sigor@sysoev.ru nxt_work_t *work, *next; 3302154Sigor@sysoev.ru 3303315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 3304154Sigor@sysoev.ru next = work->next; 3305154Sigor@sysoev.ru work->next = NULL; 3306154Sigor@sysoev.ru 3307315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 330853Sigor@sysoev.ru } 330953Sigor@sysoev.ru } 331053Sigor@sysoev.ru 331153Sigor@sysoev.ru 3312320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 33131547Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 33141547Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 33151547Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 33161547Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 33171547Smax.romanov@nginx.com .req_headers_ack = nxt_port_rpc_handler, 331888Smax.romanov@nginx.com }; 331988Smax.romanov@nginx.com 332088Smax.romanov@nginx.com 332188Smax.romanov@nginx.com static void 332253Sigor@sysoev.ru nxt_router_thread_start(void *data) 332353Sigor@sysoev.ru { 3324141Smax.romanov@nginx.com nxt_int_t ret; 3325141Smax.romanov@nginx.com nxt_port_t *port; 332688Smax.romanov@nginx.com nxt_task_t *task; 33271545Smax.romanov@nginx.com nxt_work_t *work; 332853Sigor@sysoev.ru nxt_thread_t *thread; 332953Sigor@sysoev.ru nxt_thread_link_t *link; 333053Sigor@sysoev.ru nxt_event_engine_t *engine; 333153Sigor@sysoev.ru 333253Sigor@sysoev.ru link = data; 333353Sigor@sysoev.ru engine = link->engine; 333488Smax.romanov@nginx.com task = &engine->task; 333553Sigor@sysoev.ru 333653Sigor@sysoev.ru thread = nxt_thread(); 333753Sigor@sysoev.ru 3338165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 3339165Smax.romanov@nginx.com 334053Sigor@sysoev.ru /* STUB */ 334153Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 334253Sigor@sysoev.ru 334353Sigor@sysoev.ru engine->task.thread = thread; 334453Sigor@sysoev.ru engine->task.log = thread->log; 334553Sigor@sysoev.ru thread->engine = engine; 334663Sigor@sysoev.ru thread->task = &engine->task; 3347326Svbart@nginx.com #if 0 334853Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 3349326Svbart@nginx.com #endif 335053Sigor@sysoev.ru 335163Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 3352337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 3353337Sigor@sysoev.ru return; 3354337Sigor@sysoev.ru } 335553Sigor@sysoev.ru 3356197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 3357197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 3358141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3359141Smax.romanov@nginx.com return; 3360141Smax.romanov@nginx.com } 3361141Smax.romanov@nginx.com 3362141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 3363141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3364343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3365141Smax.romanov@nginx.com return; 3366141Smax.romanov@nginx.com } 3367141Smax.romanov@nginx.com 33681555Smax.romanov@nginx.com ret = nxt_router_port_queue_init(task, port); 33691555Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 33701555Smax.romanov@nginx.com nxt_port_use(task, port, -1); 33711555Smax.romanov@nginx.com return; 33721555Smax.romanov@nginx.com } 33731555Smax.romanov@nginx.com 3374141Smax.romanov@nginx.com engine->port = port; 3375141Smax.romanov@nginx.com 3376320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 3377141Smax.romanov@nginx.com 33781545Smax.romanov@nginx.com work = nxt_zalloc(sizeof(nxt_work_t)); 33791545Smax.romanov@nginx.com if (nxt_slow_path(work == NULL)) { 33801545Smax.romanov@nginx.com return; 33811545Smax.romanov@nginx.com } 33821545Smax.romanov@nginx.com 33831545Smax.romanov@nginx.com work->handler = nxt_router_rt_add_port; 33841545Smax.romanov@nginx.com work->task = link->work.task; 33851545Smax.romanov@nginx.com work->obj = work; 33861545Smax.romanov@nginx.com work->data = port; 33871545Smax.romanov@nginx.com 33881545Smax.romanov@nginx.com nxt_event_engine_post(link->work.task->thread->engine, work); 33891545Smax.romanov@nginx.com 339053Sigor@sysoev.ru nxt_event_engine_start(engine); 339153Sigor@sysoev.ru } 339253Sigor@sysoev.ru 339353Sigor@sysoev.ru 339453Sigor@sysoev.ru static void 33951545Smax.romanov@nginx.com nxt_router_rt_add_port(nxt_task_t *task, void *obj, void *data) 33961545Smax.romanov@nginx.com { 33971545Smax.romanov@nginx.com nxt_int_t res; 33981545Smax.romanov@nginx.com nxt_port_t *port; 33991545Smax.romanov@nginx.com nxt_runtime_t *rt; 34001545Smax.romanov@nginx.com 34011545Smax.romanov@nginx.com rt = task->thread->runtime; 34021545Smax.romanov@nginx.com port = data; 34031545Smax.romanov@nginx.com 34041545Smax.romanov@nginx.com nxt_free(obj); 34051545Smax.romanov@nginx.com 34061545Smax.romanov@nginx.com res = nxt_port_hash_add(&rt->ports, port); 34071545Smax.romanov@nginx.com 34081545Smax.romanov@nginx.com if (nxt_fast_path(res == NXT_OK)) { 34091545Smax.romanov@nginx.com nxt_port_use(task, port, 1); 34101545Smax.romanov@nginx.com } 34111545Smax.romanov@nginx.com } 34121545Smax.romanov@nginx.com 34131545Smax.romanov@nginx.com 34141545Smax.romanov@nginx.com static void 341553Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 341653Sigor@sysoev.ru { 3417153Sigor@sysoev.ru nxt_joint_job_t *job; 3418359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 3419359Sigor@sysoev.ru nxt_listen_event_t *lev; 342053Sigor@sysoev.ru nxt_listen_socket_t *ls; 3421359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 342253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 342353Sigor@sysoev.ru 3424153Sigor@sysoev.ru job = obj; 342553Sigor@sysoev.ru joint = data; 342653Sigor@sysoev.ru 3427159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 3428159Sigor@sysoev.ru 3429359Sigor@sysoev.ru skcf = joint->socket_conf; 3430359Sigor@sysoev.ru ls = skcf->listen; 3431359Sigor@sysoev.ru 3432359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 3433359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 3434359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 343553Sigor@sysoev.ru return; 343653Sigor@sysoev.ru } 343753Sigor@sysoev.ru 3438359Sigor@sysoev.ru lev->socket.data = joint; 3439359Sigor@sysoev.ru 3440359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 3441359Sigor@sysoev.ru 3442359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 3443359Sigor@sysoev.ru ls->count++; 3444359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 3445139Sigor@sysoev.ru 3446153Sigor@sysoev.ru job->work.next = NULL; 3447153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 3448153Sigor@sysoev.ru 3449153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 345053Sigor@sysoev.ru } 345153Sigor@sysoev.ru 345253Sigor@sysoev.ru 345353Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 345453Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 345553Sigor@sysoev.ru nxt_socket_conf_t *skcf) 345653Sigor@sysoev.ru { 3457115Sigor@sysoev.ru nxt_socket_t fd; 3458115Sigor@sysoev.ru nxt_queue_link_t *qlk; 3459359Sigor@sysoev.ru nxt_listen_event_t *lev; 3460359Sigor@sysoev.ru 3461359Sigor@sysoev.ru fd = skcf->listen->socket; 346253Sigor@sysoev.ru 3463115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 3464115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 3465115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 346653Sigor@sysoev.ru { 3467359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 3468359Sigor@sysoev.ru 3469359Sigor@sysoev.ru if (fd == lev->socket.fd) { 3470359Sigor@sysoev.ru return lev; 347153Sigor@sysoev.ru } 347253Sigor@sysoev.ru } 347353Sigor@sysoev.ru 347453Sigor@sysoev.ru return NULL; 347553Sigor@sysoev.ru } 347653Sigor@sysoev.ru 347753Sigor@sysoev.ru 347853Sigor@sysoev.ru static void 347953Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 348053Sigor@sysoev.ru { 3481153Sigor@sysoev.ru nxt_joint_job_t *job; 348253Sigor@sysoev.ru nxt_event_engine_t *engine; 3483359Sigor@sysoev.ru nxt_listen_event_t *lev; 348453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 348553Sigor@sysoev.ru 3486153Sigor@sysoev.ru job = obj; 348753Sigor@sysoev.ru joint = data; 348853Sigor@sysoev.ru 3489139Sigor@sysoev.ru engine = task->thread->engine; 3490139Sigor@sysoev.ru 3491159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 3492159Sigor@sysoev.ru 3493359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 3494359Sigor@sysoev.ru joint->socket_conf); 3495359Sigor@sysoev.ru 3496359Sigor@sysoev.ru old = lev->socket.data; 3497359Sigor@sysoev.ru lev->socket.data = joint; 3498359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 349953Sigor@sysoev.ru 3500153Sigor@sysoev.ru job->work.next = NULL; 3501153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 3502153Sigor@sysoev.ru 3503153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 3504139Sigor@sysoev.ru 3505181Smax.romanov@nginx.com /* 3506181Smax.romanov@nginx.com * The task is allocated from configuration temporary 3507181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 3508181Smax.romanov@nginx.com */ 3509181Smax.romanov@nginx.com 3510181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 351153Sigor@sysoev.ru } 351253Sigor@sysoev.ru 351353Sigor@sysoev.ru 351453Sigor@sysoev.ru static void 351553Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 351653Sigor@sysoev.ru { 35171867Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 35181867Smax.romanov@nginx.com nxt_listen_event_t *lev; 35191867Smax.romanov@nginx.com nxt_event_engine_t *engine; 35201867Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 35211867Smax.romanov@nginx.com 352253Sigor@sysoev.ru skcf = data; 352353Sigor@sysoev.ru 3524139Sigor@sysoev.ru engine = task->thread->engine; 3525139Sigor@sysoev.ru 3526359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 3527359Sigor@sysoev.ru 3528359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 352953Sigor@sysoev.ru 3530163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 3531359Sigor@sysoev.ru lev->socket.fd); 3532359Sigor@sysoev.ru 35331867Smax.romanov@nginx.com joint = lev->socket.data; 35341867Smax.romanov@nginx.com joint->close_job = obj; 35351867Smax.romanov@nginx.com 3536359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 3537359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 3538359Sigor@sysoev.ru 3539359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 354053Sigor@sysoev.ru } 354153Sigor@sysoev.ru 354253Sigor@sysoev.ru 354353Sigor@sysoev.ru static void 3544313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 3545313Sigor@sysoev.ru { 3546313Sigor@sysoev.ru nxt_event_engine_t *engine; 3547313Sigor@sysoev.ru 3548313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 3549313Sigor@sysoev.ru 3550313Sigor@sysoev.ru engine = task->thread->engine; 3551313Sigor@sysoev.ru 3552313Sigor@sysoev.ru engine->shutdown = 1; 3553313Sigor@sysoev.ru 3554313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 3555313Sigor@sysoev.ru nxt_thread_exit(task->thread); 3556313Sigor@sysoev.ru } 3557313Sigor@sysoev.ru } 3558313Sigor@sysoev.ru 3559313Sigor@sysoev.ru 3560313Sigor@sysoev.ru static void 356153Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 356253Sigor@sysoev.ru { 356353Sigor@sysoev.ru nxt_timer_t *timer; 35641867Smax.romanov@nginx.com nxt_joint_job_t *job; 3565359Sigor@sysoev.ru nxt_listen_event_t *lev; 356653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 356753Sigor@sysoev.ru 356853Sigor@sysoev.ru timer = obj; 3569359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 357053Sigor@sysoev.ru 3571163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 3572359Sigor@sysoev.ru lev->socket.fd); 3573359Sigor@sysoev.ru 3574359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 3575359Sigor@sysoev.ru 3576683Sigor@sysoev.ru joint = lev->socket.data; 3577683Sigor@sysoev.ru lev->socket.data = NULL; 3578683Sigor@sysoev.ru 35791881Smax.romanov@nginx.com /* 'task' refers to lev->task and we cannot use after nxt_free() */ 35801881Smax.romanov@nginx.com task = &task->thread->engine->task; 35811881Smax.romanov@nginx.com 35821881Smax.romanov@nginx.com nxt_router_listen_socket_release(task, joint->socket_conf); 35831881Smax.romanov@nginx.com 35841867Smax.romanov@nginx.com job = joint->close_job; 35851867Smax.romanov@nginx.com job->work.next = NULL; 35861867Smax.romanov@nginx.com job->work.handler = nxt_router_conf_wait; 35871867Smax.romanov@nginx.com 35881867Smax.romanov@nginx.com nxt_event_engine_post(job->tmcf->engine, &job->work); 35891867Smax.romanov@nginx.com 3590683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 359153Sigor@sysoev.ru } 359253Sigor@sysoev.ru 359353Sigor@sysoev.ru 359453Sigor@sysoev.ru static void 3595359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 359653Sigor@sysoev.ru { 3597359Sigor@sysoev.ru nxt_listen_socket_t *ls; 359853Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 359953Sigor@sysoev.ru 3600359Sigor@sysoev.ru ls = skcf->listen; 3601118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 360253Sigor@sysoev.ru 360353Sigor@sysoev.ru nxt_thread_spin_lock(lock); 360453Sigor@sysoev.ru 3605359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 3606359Sigor@sysoev.ru task->thread->engine, ls->count); 3607359Sigor@sysoev.ru 3608359Sigor@sysoev.ru if (--ls->count != 0) { 3609359Sigor@sysoev.ru ls = NULL; 361053Sigor@sysoev.ru } 361153Sigor@sysoev.ru 361253Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 361353Sigor@sysoev.ru 3614359Sigor@sysoev.ru if (ls != NULL) { 3615359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 3616359Sigor@sysoev.ru nxt_free(ls); 361753Sigor@sysoev.ru } 361853Sigor@sysoev.ru } 361953Sigor@sysoev.ru 362053Sigor@sysoev.ru 3621683Sigor@sysoev.ru void 3622683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 3623683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 3624683Sigor@sysoev.ru { 3625683Sigor@sysoev.ru nxt_event_engine_t *engine; 3626683Sigor@sysoev.ru 3627683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 3628683Sigor@sysoev.ru 36291541Smax.romanov@nginx.com engine = task->thread->engine; 36301541Smax.romanov@nginx.com 3631683Sigor@sysoev.ru if (--lev->count == 0) { 36321535Smax.romanov@nginx.com if (lev->next != NULL) { 36331541Smax.romanov@nginx.com nxt_sockaddr_cache_free(engine, lev->next); 36341541Smax.romanov@nginx.com 36351535Smax.romanov@nginx.com nxt_conn_free(task, lev->next); 36361535Smax.romanov@nginx.com } 36371535Smax.romanov@nginx.com 3638683Sigor@sysoev.ru nxt_free(lev); 3639683Sigor@sysoev.ru } 3640683Sigor@sysoev.ru 3641683Sigor@sysoev.ru if (joint != NULL) { 3642683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 3643683Sigor@sysoev.ru } 3644683Sigor@sysoev.ru 3645683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 3646683Sigor@sysoev.ru nxt_thread_exit(task->thread); 3647683Sigor@sysoev.ru } 3648683Sigor@sysoev.ru } 3649683Sigor@sysoev.ru 3650683Sigor@sysoev.ru 3651683Sigor@sysoev.ru void 365253Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 365353Sigor@sysoev.ru { 365453Sigor@sysoev.ru nxt_socket_conf_t *skcf; 365553Sigor@sysoev.ru nxt_router_conf_t *rtcf; 365653Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 365753Sigor@sysoev.ru 3658163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 365953Sigor@sysoev.ru 366053Sigor@sysoev.ru if (--joint->count != 0) { 366153Sigor@sysoev.ru return; 366253Sigor@sysoev.ru } 366353Sigor@sysoev.ru 366453Sigor@sysoev.ru nxt_queue_remove(&joint->link); 366553Sigor@sysoev.ru 3666530Sigor@sysoev.ru /* 3667530Sigor@sysoev.ru * The joint content can not be safely used after the critical 3668530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 3669530Sigor@sysoev.ru * be already destroyed by another thread. 3670530Sigor@sysoev.ru */ 367153Sigor@sysoev.ru skcf = joint->socket_conf; 367253Sigor@sysoev.ru rtcf = skcf->router_conf; 367353Sigor@sysoev.ru lock = &rtcf->router->lock; 367453Sigor@sysoev.ru 367553Sigor@sysoev.ru nxt_thread_spin_lock(lock); 367653Sigor@sysoev.ru 3677163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 3678163Smax.romanov@nginx.com rtcf, rtcf->count); 3679163Smax.romanov@nginx.com 368053Sigor@sysoev.ru if (--skcf->count != 0) { 3681952Sigor@sysoev.ru skcf = NULL; 368253Sigor@sysoev.ru rtcf = NULL; 368353Sigor@sysoev.ru 368453Sigor@sysoev.ru } else { 368553Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 368653Sigor@sysoev.ru 368753Sigor@sysoev.ru if (--rtcf->count != 0) { 368853Sigor@sysoev.ru rtcf = NULL; 368953Sigor@sysoev.ru } 369053Sigor@sysoev.ru } 369153Sigor@sysoev.ru 369253Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 369353Sigor@sysoev.ru 3694952Sigor@sysoev.ru #if (NXT_TLS) 36951563Svbart@nginx.com if (skcf != NULL && skcf->tls != NULL) { 36961563Svbart@nginx.com task->thread->runtime->tls->server_free(task, skcf->tls); 36971563Svbart@nginx.com } 3698952Sigor@sysoev.ru #endif 3699952Sigor@sysoev.ru 3700141Smax.romanov@nginx.com /* TODO remove engine->port */ 3701141Smax.romanov@nginx.com 370253Sigor@sysoev.ru if (rtcf != NULL) { 3703115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 3704131Smax.romanov@nginx.com 37051563Svbart@nginx.com nxt_router_apps_hash_use(task, rtcf, -1); 3706964Sigor@sysoev.ru 3707630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 3708630Svbart@nginx.com 3709131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 3710131Smax.romanov@nginx.com 371165Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 371253Sigor@sysoev.ru } 371353Sigor@sysoev.ru } 371453Sigor@sysoev.ru 371553Sigor@sysoev.ru 371653Sigor@sysoev.ru static void 3717630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 3718630Svbart@nginx.com nxt_router_access_log_t *access_log) 3719630Svbart@nginx.com { 3720630Svbart@nginx.com size_t size; 3721630Svbart@nginx.com u_char *buf, *p; 3722630Svbart@nginx.com nxt_off_t bytes; 3723630Svbart@nginx.com 3724630Svbart@nginx.com static nxt_time_string_t date_cache = { 3725630Svbart@nginx.com (nxt_atomic_uint_t) -1, 3726630Svbart@nginx.com nxt_router_access_log_date, 3727630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 3728703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 3729630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 3730630Svbart@nginx.com NXT_THREAD_TIME_SEC, 3731630Svbart@nginx.com }; 3732630Svbart@nginx.com 3733630Svbart@nginx.com size = r->remote->address_length 3734630Svbart@nginx.com + 6 /* ' - - [' */ 3735630Svbart@nginx.com + date_cache.size 3736630Svbart@nginx.com + 3 /* '] "' */ 3737630Svbart@nginx.com + r->method->length 3738630Svbart@nginx.com + 1 /* space */ 3739630Svbart@nginx.com + r->target.length 3740630Svbart@nginx.com + 1 /* space */ 3741630Svbart@nginx.com + r->version.length 3742630Svbart@nginx.com + 2 /* '" ' */ 3743630Svbart@nginx.com + 3 /* status */ 3744630Svbart@nginx.com + 1 /* space */ 3745630Svbart@nginx.com + NXT_OFF_T_LEN 3746630Svbart@nginx.com + 2 /* ' "' */ 3747630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3748630Svbart@nginx.com + 3 /* '" "' */ 3749630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3750630Svbart@nginx.com + 2 /* '"\n' */ 3751630Svbart@nginx.com ; 3752630Svbart@nginx.com 3753630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3754630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3755630Svbart@nginx.com return; 3756630Svbart@nginx.com } 3757630Svbart@nginx.com 3758630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3759630Svbart@nginx.com r->remote->address_length); 3760630Svbart@nginx.com 3761630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3762630Svbart@nginx.com 3763630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3764630Svbart@nginx.com 3765630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3766630Svbart@nginx.com 3767630Svbart@nginx.com if (r->method->length != 0) { 3768630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3769630Svbart@nginx.com 3770630Svbart@nginx.com if (r->target.length != 0) { 3771630Svbart@nginx.com *p++ = ' '; 3772630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3773630Svbart@nginx.com 3774630Svbart@nginx.com if (r->version.length != 0) { 3775630Svbart@nginx.com *p++ = ' '; 3776630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3777630Svbart@nginx.com } 3778630Svbart@nginx.com } 3779630Svbart@nginx.com 3780630Svbart@nginx.com } else { 3781630Svbart@nginx.com *p++ = '-'; 3782630Svbart@nginx.com } 3783630Svbart@nginx.com 3784630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3785630Svbart@nginx.com 3786630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3787630Svbart@nginx.com 3788630Svbart@nginx.com *p++ = ' '; 3789630Svbart@nginx.com 37901112Sigor@sysoev.ru bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); 3791630Svbart@nginx.com 3792630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3793630Svbart@nginx.com 3794630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3795630Svbart@nginx.com 3796630Svbart@nginx.com if (r->referer != NULL) { 3797630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3798630Svbart@nginx.com 3799630Svbart@nginx.com } else { 3800630Svbart@nginx.com *p++ = '-'; 3801630Svbart@nginx.com } 3802630Svbart@nginx.com 3803630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3804630Svbart@nginx.com 3805630Svbart@nginx.com if (r->user_agent != NULL) { 3806630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3807630Svbart@nginx.com 3808630Svbart@nginx.com } else { 3809630Svbart@nginx.com *p++ = '-'; 3810630Svbart@nginx.com } 3811630Svbart@nginx.com 3812630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3813630Svbart@nginx.com 3814630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3815630Svbart@nginx.com } 3816630Svbart@nginx.com 3817630Svbart@nginx.com 3818630Svbart@nginx.com static u_char * 3819630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3820630Svbart@nginx.com size_t size, const char *format) 3821630Svbart@nginx.com { 3822630Svbart@nginx.com u_char sign; 3823630Svbart@nginx.com time_t gmtoff; 3824630Svbart@nginx.com 3825630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3826630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3827630Svbart@nginx.com 3828630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3829630Svbart@nginx.com 3830630Svbart@nginx.com if (gmtoff < 0) { 3831630Svbart@nginx.com gmtoff = -gmtoff; 3832630Svbart@nginx.com sign = '-'; 3833630Svbart@nginx.com 3834630Svbart@nginx.com } else { 3835630Svbart@nginx.com sign = '+'; 3836630Svbart@nginx.com } 3837630Svbart@nginx.com 3838630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3839630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3840630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3841630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3842630Svbart@nginx.com } 3843630Svbart@nginx.com 3844630Svbart@nginx.com 3845630Svbart@nginx.com static void 3846630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3847630Svbart@nginx.com { 3848630Svbart@nginx.com uint32_t stream; 3849648Svbart@nginx.com nxt_int_t ret; 3850630Svbart@nginx.com nxt_buf_t *b; 3851630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3852630Svbart@nginx.com nxt_runtime_t *rt; 3853630Svbart@nginx.com nxt_router_access_log_t *access_log; 3854630Svbart@nginx.com 3855630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3856630Svbart@nginx.com 3857630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3858630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3859630Svbart@nginx.com goto fail; 3860630Svbart@nginx.com } 3861630Svbart@nginx.com 38621940Sz.hong@f5.com b->completion_handler = nxt_buf_dummy_completion; 38631566Smax.romanov@nginx.com 3864630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3865630Svbart@nginx.com *b->mem.free++ = '\0'; 3866630Svbart@nginx.com 3867630Svbart@nginx.com rt = task->thread->runtime; 3868630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3869630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3870630Svbart@nginx.com 3871630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3872630Svbart@nginx.com nxt_router_access_log_ready, 3873630Svbart@nginx.com nxt_router_access_log_error, 3874630Svbart@nginx.com -1, tmcf); 3875630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3876630Svbart@nginx.com goto fail; 3877630Svbart@nginx.com } 3878630Svbart@nginx.com 3879648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3880648Svbart@nginx.com stream, router_port->id, b); 3881648Svbart@nginx.com 3882648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3883648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3884648Svbart@nginx.com goto fail; 3885648Svbart@nginx.com } 3886630Svbart@nginx.com 3887630Svbart@nginx.com return; 3888630Svbart@nginx.com 3889630Svbart@nginx.com fail: 3890630Svbart@nginx.com 3891630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3892630Svbart@nginx.com } 3893630Svbart@nginx.com 3894630Svbart@nginx.com 3895630Svbart@nginx.com static void 3896630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3897630Svbart@nginx.com void *data) 3898630Svbart@nginx.com { 3899630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3900630Svbart@nginx.com nxt_router_access_log_t *access_log; 3901630Svbart@nginx.com 3902630Svbart@nginx.com tmcf = data; 3903630Svbart@nginx.com 3904630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3905630Svbart@nginx.com 39061558Smax.romanov@nginx.com access_log->fd = msg->fd[0]; 3907630Svbart@nginx.com 3908630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3909630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3910630Svbart@nginx.com } 3911630Svbart@nginx.com 3912630Svbart@nginx.com 3913630Svbart@nginx.com static void 3914630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3915630Svbart@nginx.com void *data) 3916630Svbart@nginx.com { 3917630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3918630Svbart@nginx.com 3919630Svbart@nginx.com tmcf = data; 3920630Svbart@nginx.com 3921630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3922630Svbart@nginx.com } 3923630Svbart@nginx.com 3924630Svbart@nginx.com 3925630Svbart@nginx.com static void 3926630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3927630Svbart@nginx.com nxt_router_access_log_t *access_log) 3928630Svbart@nginx.com { 3929630Svbart@nginx.com if (access_log == NULL) { 3930630Svbart@nginx.com return; 3931630Svbart@nginx.com } 3932630Svbart@nginx.com 3933630Svbart@nginx.com nxt_thread_spin_lock(lock); 3934630Svbart@nginx.com 3935630Svbart@nginx.com if (--access_log->count != 0) { 3936630Svbart@nginx.com access_log = NULL; 3937630Svbart@nginx.com } 3938630Svbart@nginx.com 3939630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3940630Svbart@nginx.com 3941630Svbart@nginx.com if (access_log != NULL) { 3942630Svbart@nginx.com 3943630Svbart@nginx.com if (access_log->fd != -1) { 3944630Svbart@nginx.com nxt_fd_close(access_log->fd); 3945630Svbart@nginx.com } 3946630Svbart@nginx.com 3947630Svbart@nginx.com nxt_free(access_log); 3948630Svbart@nginx.com } 3949630Svbart@nginx.com } 3950630Svbart@nginx.com 3951630Svbart@nginx.com 3952631Svbart@nginx.com typedef struct { 3953631Svbart@nginx.com nxt_mp_t *mem_pool; 3954631Svbart@nginx.com nxt_router_access_log_t *access_log; 3955631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3956631Svbart@nginx.com 3957631Svbart@nginx.com 39581552Smax.romanov@nginx.com static void 3959631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3960631Svbart@nginx.com { 3961631Svbart@nginx.com nxt_mp_t *mp; 3962631Svbart@nginx.com uint32_t stream; 3963631Svbart@nginx.com nxt_int_t ret; 3964631Svbart@nginx.com nxt_buf_t *b; 3965631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3966631Svbart@nginx.com nxt_runtime_t *rt; 3967631Svbart@nginx.com nxt_router_access_log_t *access_log; 3968631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3969631Svbart@nginx.com 3970631Svbart@nginx.com access_log = nxt_router->access_log; 3971631Svbart@nginx.com 3972631Svbart@nginx.com if (access_log == NULL) { 3973631Svbart@nginx.com return; 3974631Svbart@nginx.com } 3975631Svbart@nginx.com 3976631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3977631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3978631Svbart@nginx.com return; 3979631Svbart@nginx.com } 3980631Svbart@nginx.com 3981631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3982631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3983631Svbart@nginx.com goto fail; 3984631Svbart@nginx.com } 3985631Svbart@nginx.com 3986631Svbart@nginx.com reopen->mem_pool = mp; 3987631Svbart@nginx.com reopen->access_log = access_log; 3988631Svbart@nginx.com 3989631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3990631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3991631Svbart@nginx.com goto fail; 3992631Svbart@nginx.com } 3993631Svbart@nginx.com 3994651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3995651Svbart@nginx.com 3996631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3997631Svbart@nginx.com *b->mem.free++ = '\0'; 3998631Svbart@nginx.com 3999631Svbart@nginx.com rt = task->thread->runtime; 4000631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 4001631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 4002631Svbart@nginx.com 4003631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 4004631Svbart@nginx.com nxt_router_access_log_reopen_ready, 4005631Svbart@nginx.com nxt_router_access_log_reopen_error, 4006631Svbart@nginx.com -1, reopen); 4007631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 4008631Svbart@nginx.com goto fail; 4009631Svbart@nginx.com } 4010631Svbart@nginx.com 4011631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 4012631Svbart@nginx.com stream, router_port->id, b); 4013631Svbart@nginx.com 4014631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 4015631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 4016631Svbart@nginx.com goto fail; 4017631Svbart@nginx.com } 4018631Svbart@nginx.com 4019651Svbart@nginx.com nxt_mp_retain(mp); 4020651Svbart@nginx.com 4021631Svbart@nginx.com return; 4022631Svbart@nginx.com 4023631Svbart@nginx.com fail: 4024631Svbart@nginx.com 4025631Svbart@nginx.com nxt_mp_destroy(mp); 4026631Svbart@nginx.com } 4027631Svbart@nginx.com 4028631Svbart@nginx.com 4029631Svbart@nginx.com static void 4030651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 4031651Svbart@nginx.com { 4032651Svbart@nginx.com nxt_mp_t *mp; 4033651Svbart@nginx.com nxt_buf_t *b; 4034651Svbart@nginx.com 4035651Svbart@nginx.com b = obj; 4036651Svbart@nginx.com mp = b->data; 4037651Svbart@nginx.com 4038651Svbart@nginx.com nxt_mp_release(mp); 4039651Svbart@nginx.com } 4040651Svbart@nginx.com 4041651Svbart@nginx.com 4042651Svbart@nginx.com static void 4043631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4044631Svbart@nginx.com void *data) 4045631Svbart@nginx.com { 4046631Svbart@nginx.com nxt_router_access_log_t *access_log; 4047631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 4048631Svbart@nginx.com 4049631Svbart@nginx.com reopen = data; 4050631Svbart@nginx.com 4051631Svbart@nginx.com access_log = reopen->access_log; 4052631Svbart@nginx.com 4053631Svbart@nginx.com if (access_log == nxt_router->access_log) { 4054631Svbart@nginx.com 40551558Smax.romanov@nginx.com if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) { 4056631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 40571558Smax.romanov@nginx.com msg->fd[0], access_log->fd, nxt_errno); 4058631Svbart@nginx.com } 4059631Svbart@nginx.com } 4060631Svbart@nginx.com 40611558Smax.romanov@nginx.com nxt_fd_close(msg->fd[0]); 4062651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 4063631Svbart@nginx.com } 4064631Svbart@nginx.com 4065631Svbart@nginx.com 4066631Svbart@nginx.com static void 4067631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4068631Svbart@nginx.com void *data) 4069631Svbart@nginx.com { 4070631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 4071631Svbart@nginx.com 4072631Svbart@nginx.com reopen = data; 4073631Svbart@nginx.com 4074651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 4075631Svbart@nginx.com } 4076631Svbart@nginx.com 4077631Svbart@nginx.com 4078630Svbart@nginx.com static void 407953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 408053Sigor@sysoev.ru { 4081141Smax.romanov@nginx.com nxt_port_t *port; 408253Sigor@sysoev.ru nxt_thread_link_t *link; 408353Sigor@sysoev.ru nxt_event_engine_t *engine; 408453Sigor@sysoev.ru nxt_thread_handle_t handle; 408553Sigor@sysoev.ru 40861810Smax.romanov@nginx.com handle = (nxt_thread_handle_t) (uintptr_t) obj; 408753Sigor@sysoev.ru link = data; 408853Sigor@sysoev.ru 408953Sigor@sysoev.ru nxt_thread_wait(handle); 409053Sigor@sysoev.ru 409153Sigor@sysoev.ru engine = link->engine; 409253Sigor@sysoev.ru 409353Sigor@sysoev.ru nxt_queue_remove(&engine->link); 409453Sigor@sysoev.ru 4095141Smax.romanov@nginx.com port = engine->port; 4096141Smax.romanov@nginx.com 4097141Smax.romanov@nginx.com // TODO notify all apps 4098141Smax.romanov@nginx.com 4099343Smax.romanov@nginx.com port->engine = task->thread->engine; 4100163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 4101343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4102163Smax.romanov@nginx.com 4103163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 410463Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 410553Sigor@sysoev.ru 410653Sigor@sysoev.ru nxt_event_engine_free(engine); 410753Sigor@sysoev.ru 410853Sigor@sysoev.ru nxt_free(link); 410953Sigor@sysoev.ru } 411053Sigor@sysoev.ru 411153Sigor@sysoev.ru 411253Sigor@sysoev.ru static void 4113318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4114318Smax.romanov@nginx.com void *data) 411588Smax.romanov@nginx.com { 41161661Smax.romanov@nginx.com size_t b_size, count; 41171123Smax.romanov@nginx.com nxt_int_t ret; 41181547Smax.romanov@nginx.com nxt_app_t *app; 41191269Sigor@sysoev.ru nxt_buf_t *b, *next; 41201131Smax.romanov@nginx.com nxt_port_t *app_port; 41211123Smax.romanov@nginx.com nxt_unit_field_t *f; 41221123Smax.romanov@nginx.com nxt_http_field_t *field; 41231123Smax.romanov@nginx.com nxt_http_request_t *r; 41241123Smax.romanov@nginx.com nxt_unit_response_t *resp; 41251123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 412688Smax.romanov@nginx.com 41271123Smax.romanov@nginx.com req_rpc_data = data; 412888Smax.romanov@nginx.com 41291123Smax.romanov@nginx.com r = req_rpc_data->request; 41301007Salexander.borisov@nginx.com if (nxt_slow_path(r == NULL)) { 4131570Smax.romanov@nginx.com return; 4132570Smax.romanov@nginx.com } 4133425Smax.romanov@nginx.com 41341007Salexander.borisov@nginx.com if (r->error) { 41351123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 4136608Sigor@sysoev.ru return; 4137608Sigor@sysoev.ru } 4138608Sigor@sysoev.ru 41391547Smax.romanov@nginx.com app = req_rpc_data->app; 41401547Smax.romanov@nginx.com nxt_assert(app != NULL); 41411547Smax.romanov@nginx.com 41421547Smax.romanov@nginx.com if (msg->port_msg.type == _NXT_PORT_MSG_REQ_HEADERS_ACK) { 41431547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(task, msg, req_rpc_data); 41441547Smax.romanov@nginx.com 41451547Smax.romanov@nginx.com return; 41461547Smax.romanov@nginx.com } 41471547Smax.romanov@nginx.com 41481547Smax.romanov@nginx.com b = (msg->size == 0) ? NULL : msg->buf; 41491547Smax.romanov@nginx.com 415088Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 415188Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 415288Smax.romanov@nginx.com 41531007Salexander.borisov@nginx.com nxt_buf_chain_add(&b, nxt_http_buf_last(r)); 4154167Smax.romanov@nginx.com 41551547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 41561780Smax.romanov@nginx.com 41571780Smax.romanov@nginx.com if (req_rpc_data->apr_action == NXT_APR_REQUEST_FAILED) { 41581780Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_GOT_RESPONSE; 41591780Smax.romanov@nginx.com } 41601547Smax.romanov@nginx.com 41611123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 4162425Smax.romanov@nginx.com 4163425Smax.romanov@nginx.com } else { 41641547Smax.romanov@nginx.com if (app->timeout != 0) { 41651007Salexander.borisov@nginx.com r->timer.handler = nxt_router_app_timeout; 41661123Smax.romanov@nginx.com r->timer_data = req_rpc_data; 41671547Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, app->timeout); 4168425Smax.romanov@nginx.com } 416988Smax.romanov@nginx.com } 417088Smax.romanov@nginx.com 417188Smax.romanov@nginx.com if (b == NULL) { 417288Smax.romanov@nginx.com return; 417388Smax.romanov@nginx.com } 417488Smax.romanov@nginx.com 4175206Smax.romanov@nginx.com if (msg->buf == b) { 4176206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 4177206Smax.romanov@nginx.com msg->buf = NULL; 4178206Smax.romanov@nginx.com } 4179194Smax.romanov@nginx.com 4180431Sigor@sysoev.ru if (r->header_sent) { 4181431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 4182431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 4183277Sigor@sysoev.ru 418488Smax.romanov@nginx.com } else { 41851661Smax.romanov@nginx.com b_size = nxt_buf_is_mem(b) ? nxt_buf_mem_used_size(&b->mem) : 0; 41861661Smax.romanov@nginx.com 41871661Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(nxt_unit_response_t))) { 41881661Smax.romanov@nginx.com nxt_alert(task, "response buffer too small: %z", b_size); 4189743Smax.romanov@nginx.com goto fail; 4190743Smax.romanov@nginx.com } 4191743Smax.romanov@nginx.com 4192743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 41931661Smax.romanov@nginx.com count = (b_size - sizeof(nxt_unit_response_t)) 41941661Smax.romanov@nginx.com / sizeof(nxt_unit_field_t); 41951661Smax.romanov@nginx.com 41961661Smax.romanov@nginx.com if (nxt_slow_path(count < resp->fields_count)) { 41971661Smax.romanov@nginx.com nxt_alert(task, "response buffer too small for fields count: %D", 41981661Smax.romanov@nginx.com resp->fields_count); 4199743Smax.romanov@nginx.com goto fail; 4200743Smax.romanov@nginx.com } 4201743Smax.romanov@nginx.com 42021126Smax.romanov@nginx.com field = NULL; 42031126Smax.romanov@nginx.com 4204743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 42051126Smax.romanov@nginx.com if (f->skip) { 42061126Smax.romanov@nginx.com continue; 42071126Smax.romanov@nginx.com } 42081126Smax.romanov@nginx.com 42091007Salexander.borisov@nginx.com field = nxt_list_add(r->resp.fields); 4210743Smax.romanov@nginx.com 4211743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 4212743Smax.romanov@nginx.com goto fail; 4213743Smax.romanov@nginx.com } 4214743Smax.romanov@nginx.com 4215743Smax.romanov@nginx.com field->hash = f->hash; 42161126Smax.romanov@nginx.com field->skip = 0; 42171270Sigor@sysoev.ru field->hopbyhop = 0; 4218743Smax.romanov@nginx.com 4219743Smax.romanov@nginx.com field->name_length = f->name_length; 4220743Smax.romanov@nginx.com field->value_length = f->value_length; 4221743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 4222743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 4223743Smax.romanov@nginx.com 42241126Smax.romanov@nginx.com ret = nxt_http_field_process(field, &nxt_response_fields_hash, r); 42251126Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 42261126Smax.romanov@nginx.com goto fail; 42271126Smax.romanov@nginx.com } 42281126Smax.romanov@nginx.com 42291126Smax.romanov@nginx.com nxt_debug(task, "header%s: %*s: %*s", 42301126Smax.romanov@nginx.com (field->skip ? " skipped" : ""), 4231743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 4232743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 42331126Smax.romanov@nginx.com 42341126Smax.romanov@nginx.com if (field->skip) { 42351126Smax.romanov@nginx.com r->resp.fields->last->nelts--; 42361126Smax.romanov@nginx.com } 4237743Smax.romanov@nginx.com } 42381007Salexander.borisov@nginx.com 4239743Smax.romanov@nginx.com r->status = resp->status; 4240743Smax.romanov@nginx.com 4241743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 4242743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 4243743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 4244743Smax.romanov@nginx.com 4245743Smax.romanov@nginx.com } else { 4246743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 4247743Smax.romanov@nginx.com } 4248743Smax.romanov@nginx.com 4249435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 42501269Sigor@sysoev.ru next = b->next; 42511269Sigor@sysoev.ru b->next = NULL; 42521269Sigor@sysoev.ru 4253435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4254435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 4255507Smax.romanov@nginx.com 42561269Sigor@sysoev.ru b = next; 4257520Smax.romanov@nginx.com } 4258520Smax.romanov@nginx.com 4259520Smax.romanov@nginx.com if (b != NULL) { 4260431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 4261431Sigor@sysoev.ru } 4262431Sigor@sysoev.ru 42631270Sigor@sysoev.ru nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL); 42641127Smax.romanov@nginx.com 42651131Smax.romanov@nginx.com if (r->websocket_handshake 42661131Smax.romanov@nginx.com && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) 42671131Smax.romanov@nginx.com { 42681547Smax.romanov@nginx.com app_port = req_rpc_data->app_port; 42691131Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 42701131Smax.romanov@nginx.com goto fail; 42711131Smax.romanov@nginx.com } 42721131Smax.romanov@nginx.com 42731547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 42741547Smax.romanov@nginx.com 42751547Smax.romanov@nginx.com app_port->main_app_port->active_websockets++; 42761547Smax.romanov@nginx.com 42771547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 42781131Smax.romanov@nginx.com 42791978Smax.romanov@nginx.com nxt_router_app_port_release(task, app, app_port, NXT_APR_UPGRADE); 42801547Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_CLOSE; 42811547Smax.romanov@nginx.com 42821547Smax.romanov@nginx.com nxt_debug(task, "stream #%uD upgrade", req_rpc_data->stream); 42831131Smax.romanov@nginx.com 42841131Smax.romanov@nginx.com r->state = &nxt_http_websocket; 42851131Smax.romanov@nginx.com 42861131Smax.romanov@nginx.com } else { 42871131Smax.romanov@nginx.com r->state = &nxt_http_request_send_state; 42881131Smax.romanov@nginx.com } 4289431Sigor@sysoev.ru } 4290431Sigor@sysoev.ru 4291431Sigor@sysoev.ru return; 4292431Sigor@sysoev.ru 4293431Sigor@sysoev.ru fail: 4294431Sigor@sysoev.ru 4295615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 4296615Smax.romanov@nginx.com 42971123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 4298431Sigor@sysoev.ru } 4299431Sigor@sysoev.ru 4300431Sigor@sysoev.ru 43011547Smax.romanov@nginx.com static void 43021547Smax.romanov@nginx.com nxt_router_req_headers_ack_handler(nxt_task_t *task, 43031547Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, nxt_request_rpc_data_t *req_rpc_data) 43041547Smax.romanov@nginx.com { 43051555Smax.romanov@nginx.com int res; 43061547Smax.romanov@nginx.com nxt_app_t *app; 43071698Smax.romanov@nginx.com nxt_buf_t *b; 43081561Smax.romanov@nginx.com nxt_bool_t start_process, unlinked; 43091547Smax.romanov@nginx.com nxt_port_t *app_port, *main_app_port, *idle_port; 43101547Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 43111547Smax.romanov@nginx.com nxt_http_request_t *r; 43121547Smax.romanov@nginx.com 43131547Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: got ack from %PI:%d", 43141547Smax.romanov@nginx.com req_rpc_data->stream, 43151547Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 43161547Smax.romanov@nginx.com 43171547Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, msg->port, req_rpc_data, 43181547Smax.romanov@nginx.com msg->port_msg.pid); 43191547Smax.romanov@nginx.com 43201547Smax.romanov@nginx.com app = req_rpc_data->app; 43211561Smax.romanov@nginx.com r = req_rpc_data->request; 43221547Smax.romanov@nginx.com 43231547Smax.romanov@nginx.com start_process = 0; 43241561Smax.romanov@nginx.com unlinked = 0; 43251547Smax.romanov@nginx.com 43261547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 43271547Smax.romanov@nginx.com 43281561Smax.romanov@nginx.com if (r->app_link.next != NULL) { 43291561Smax.romanov@nginx.com nxt_queue_remove(&r->app_link); 43301561Smax.romanov@nginx.com r->app_link.next = NULL; 43311561Smax.romanov@nginx.com 43321561Smax.romanov@nginx.com unlinked = 1; 43331561Smax.romanov@nginx.com } 43341561Smax.romanov@nginx.com 43351547Smax.romanov@nginx.com app_port = nxt_port_hash_find(&app->port_hash, msg->port_msg.pid, 43361547Smax.romanov@nginx.com msg->port_msg.reply_port); 43371547Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 43381547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 43391547Smax.romanov@nginx.com 43401547Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 43411547Smax.romanov@nginx.com 43421561Smax.romanov@nginx.com if (unlinked) { 43431561Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 43441561Smax.romanov@nginx.com } 43451561Smax.romanov@nginx.com 43461547Smax.romanov@nginx.com return; 43471547Smax.romanov@nginx.com } 43481547Smax.romanov@nginx.com 43491547Smax.romanov@nginx.com main_app_port = app_port->main_app_port; 43501547Smax.romanov@nginx.com 43511547Smax.romanov@nginx.com if (nxt_queue_chk_remove(&main_app_port->idle_link)) { 43521547Smax.romanov@nginx.com app->idle_processes--; 43531547Smax.romanov@nginx.com 43541549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s (ack)", 43551549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id, 43561549Smax.romanov@nginx.com (main_app_port->idle_start ? "idle_ports" : "spare_ports")); 43571549Smax.romanov@nginx.com 43581547Smax.romanov@nginx.com /* Check port was in 'spare_ports' using idle_start field. */ 43591547Smax.romanov@nginx.com if (main_app_port->idle_start == 0 43601547Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 43611547Smax.romanov@nginx.com { 43621547Smax.romanov@nginx.com /* 43631547Smax.romanov@nginx.com * If there is a vacant space in spare ports, 43641547Smax.romanov@nginx.com * move the last idle to spare_ports. 43651547Smax.romanov@nginx.com */ 43661547Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 43671547Smax.romanov@nginx.com 43681547Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 43691547Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 43701547Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 43711547Smax.romanov@nginx.com 43721547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 43731547Smax.romanov@nginx.com 43741547Smax.romanov@nginx.com idle_port->idle_start = 0; 43751549Smax.romanov@nginx.com 43761549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " 43771549Smax.romanov@nginx.com "to spare_ports", 43781549Smax.romanov@nginx.com &app->name, idle_port->pid, idle_port->id); 43791547Smax.romanov@nginx.com } 43801547Smax.romanov@nginx.com 43811547Smax.romanov@nginx.com if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { 43821547Smax.romanov@nginx.com app->pending_processes++; 43831547Smax.romanov@nginx.com start_process = 1; 43841547Smax.romanov@nginx.com } 43851547Smax.romanov@nginx.com } 43861547Smax.romanov@nginx.com 43871547Smax.romanov@nginx.com main_app_port->active_requests++; 43881547Smax.romanov@nginx.com 43891547Smax.romanov@nginx.com nxt_port_inc_use(app_port); 43901547Smax.romanov@nginx.com 43911547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 43921547Smax.romanov@nginx.com 43931561Smax.romanov@nginx.com if (unlinked) { 43941561Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 43951561Smax.romanov@nginx.com } 43961561Smax.romanov@nginx.com 43971547Smax.romanov@nginx.com if (start_process) { 43981547Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 43991547Smax.romanov@nginx.com } 44001547Smax.romanov@nginx.com 44011547Smax.romanov@nginx.com nxt_port_use(task, req_rpc_data->app_port, -1); 44021547Smax.romanov@nginx.com 44031547Smax.romanov@nginx.com req_rpc_data->app_port = app_port; 44041547Smax.romanov@nginx.com 44051698Smax.romanov@nginx.com b = req_rpc_data->msg_info.buf; 44061698Smax.romanov@nginx.com 44071698Smax.romanov@nginx.com if (b != NULL) { 44081698Smax.romanov@nginx.com /* First buffer is already sent. Start from second. */ 44091698Smax.romanov@nginx.com b = b->next; 44101829Smax.romanov@nginx.com 44111829Smax.romanov@nginx.com req_rpc_data->msg_info.buf->next = NULL; 44121698Smax.romanov@nginx.com } 44131698Smax.romanov@nginx.com 44141698Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) { 44151555Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: send body fd %d", req_rpc_data->stream, 44161555Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd); 44171555Smax.romanov@nginx.com 44181698Smax.romanov@nginx.com if (req_rpc_data->msg_info.body_fd != -1) { 44191698Smax.romanov@nginx.com lseek(req_rpc_data->msg_info.body_fd, 0, SEEK_SET); 44201698Smax.romanov@nginx.com } 44211555Smax.romanov@nginx.com 44221555Smax.romanov@nginx.com res = nxt_port_socket_write(task, app_port, NXT_PORT_MSG_REQ_BODY, 44231555Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd, 44241555Smax.romanov@nginx.com req_rpc_data->stream, 44251698Smax.romanov@nginx.com task->thread->engine->port->id, b); 44261555Smax.romanov@nginx.com 44271555Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 44281555Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 44291555Smax.romanov@nginx.com } 44301555Smax.romanov@nginx.com } 44311555Smax.romanov@nginx.com 44321547Smax.romanov@nginx.com if (app->timeout != 0) { 44331547Smax.romanov@nginx.com r->timer.handler = nxt_router_app_timeout; 44341547Smax.romanov@nginx.com r->timer_data = req_rpc_data; 44351547Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, app->timeout); 44361547Smax.romanov@nginx.com } 44371547Smax.romanov@nginx.com } 44381547Smax.romanov@nginx.com 44391547Smax.romanov@nginx.com 4440431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 4441431Sigor@sysoev.ru nxt_aligned(64) = 4442431Sigor@sysoev.ru { 4443943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 4444431Sigor@sysoev.ru }; 4445431Sigor@sysoev.ru 4446431Sigor@sysoev.ru 4447431Sigor@sysoev.ru static void 4448431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 4449431Sigor@sysoev.ru { 4450431Sigor@sysoev.ru nxt_buf_t *out; 4451431Sigor@sysoev.ru nxt_http_request_t *r; 4452431Sigor@sysoev.ru 4453431Sigor@sysoev.ru r = obj; 4454431Sigor@sysoev.ru 4455431Sigor@sysoev.ru out = r->out; 4456431Sigor@sysoev.ru 4457431Sigor@sysoev.ru if (out != NULL) { 4458431Sigor@sysoev.ru r->out = NULL; 4459431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 446088Smax.romanov@nginx.com } 446188Smax.romanov@nginx.com } 446288Smax.romanov@nginx.com 4463277Sigor@sysoev.ru 4464318Smax.romanov@nginx.com static void 4465318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4466318Smax.romanov@nginx.com void *data) 4467318Smax.romanov@nginx.com { 44681123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 44691123Smax.romanov@nginx.com 44701123Smax.romanov@nginx.com req_rpc_data = data; 44711123Smax.romanov@nginx.com 44721547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 0; 44731547Smax.romanov@nginx.com 44741547Smax.romanov@nginx.com /* TODO cancel message and return if cancelled. */ 44751547Smax.romanov@nginx.com // nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream); 4476425Smax.romanov@nginx.com 44771123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 44781123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 4479616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 4480616Smax.romanov@nginx.com } 4481318Smax.romanov@nginx.com 44821123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 4483318Smax.romanov@nginx.com } 4484318Smax.romanov@nginx.com 4485318Smax.romanov@nginx.com 4486141Smax.romanov@nginx.com static void 4487343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4488343Smax.romanov@nginx.com void *data) 4489192Smax.romanov@nginx.com { 4490*1998St.nateldemoura@f5.com uint32_t n; 44911926Smax.romanov@nginx.com nxt_app_t *app; 4492*1998St.nateldemoura@f5.com nxt_bool_t start_process, restarted; 44931926Smax.romanov@nginx.com nxt_port_t *port; 44941926Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 44951926Smax.romanov@nginx.com nxt_app_joint_rpc_t *app_joint_rpc; 44961926Smax.romanov@nginx.com 44971926Smax.romanov@nginx.com nxt_assert(data != NULL); 44981926Smax.romanov@nginx.com 44991926Smax.romanov@nginx.com app_joint_rpc = data; 45001926Smax.romanov@nginx.com app_joint = app_joint_rpc->app_joint; 4501347Smax.romanov@nginx.com port = msg->u.new_port; 4502343Smax.romanov@nginx.com 4503753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 4504343Smax.romanov@nginx.com nxt_assert(port != NULL); 45051547Smax.romanov@nginx.com nxt_assert(port->id == 0); 4506343Smax.romanov@nginx.com 4507753Smax.romanov@nginx.com app = app_joint->app; 4508753Smax.romanov@nginx.com 4509753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4510753Smax.romanov@nginx.com 4511753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 4512753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 4513753Smax.romanov@nginx.com 4514753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4515753Smax.romanov@nginx.com 4516753Smax.romanov@nginx.com return; 4517753Smax.romanov@nginx.com } 4518753Smax.romanov@nginx.com 4519343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4520343Smax.romanov@nginx.com 4521*1998St.nateldemoura@f5.com restarted = (app->generation != app_joint_rpc->generation); 4522*1998St.nateldemoura@f5.com 4523*1998St.nateldemoura@f5.com if (app_joint_rpc->proto) { 4524*1998St.nateldemoura@f5.com nxt_assert(app->proto_port == NULL); 4525*1998St.nateldemoura@f5.com nxt_assert(port->type == NXT_PROCESS_PROTOTYPE); 4526*1998St.nateldemoura@f5.com 4527*1998St.nateldemoura@f5.com n = app->proto_port_requests; 4528*1998St.nateldemoura@f5.com app->proto_port_requests = 0; 4529*1998St.nateldemoura@f5.com 4530*1998St.nateldemoura@f5.com if (nxt_slow_path(restarted)) { 4531*1998St.nateldemoura@f5.com nxt_thread_mutex_unlock(&app->mutex); 4532*1998St.nateldemoura@f5.com 4533*1998St.nateldemoura@f5.com nxt_debug(task, "proto port ready for restarted app, send QUIT"); 4534*1998St.nateldemoura@f5.com 4535*1998St.nateldemoura@f5.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, 4536*1998St.nateldemoura@f5.com NULL); 4537*1998St.nateldemoura@f5.com 4538*1998St.nateldemoura@f5.com } else { 4539*1998St.nateldemoura@f5.com port->app = app; 4540*1998St.nateldemoura@f5.com app->proto_port = port; 4541*1998St.nateldemoura@f5.com 4542*1998St.nateldemoura@f5.com nxt_thread_mutex_unlock(&app->mutex); 4543*1998St.nateldemoura@f5.com 4544*1998St.nateldemoura@f5.com nxt_port_use(task, port, 1); 4545*1998St.nateldemoura@f5.com } 4546*1998St.nateldemoura@f5.com 4547*1998St.nateldemoura@f5.com port = task->thread->runtime->port_by_type[NXT_PROCESS_ROUTER]; 4548*1998St.nateldemoura@f5.com 4549*1998St.nateldemoura@f5.com while (n > 0) { 4550*1998St.nateldemoura@f5.com nxt_router_app_use(task, app, 1); 4551*1998St.nateldemoura@f5.com 4552*1998St.nateldemoura@f5.com nxt_router_start_app_process_handler(task, port, app); 4553*1998St.nateldemoura@f5.com 4554*1998St.nateldemoura@f5.com n--; 4555*1998St.nateldemoura@f5.com } 4556*1998St.nateldemoura@f5.com 4557*1998St.nateldemoura@f5.com return; 4558*1998St.nateldemoura@f5.com } 4559*1998St.nateldemoura@f5.com 4560*1998St.nateldemoura@f5.com nxt_assert(port->type == NXT_PROCESS_APP); 4561507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 4562507Smax.romanov@nginx.com 4563507Smax.romanov@nginx.com app->pending_processes--; 45641926Smax.romanov@nginx.com 4565*1998St.nateldemoura@f5.com if (nxt_slow_path(restarted)) { 45661926Smax.romanov@nginx.com nxt_debug(task, "new port ready for restarted app, send QUIT"); 45671926Smax.romanov@nginx.com 45681926Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 45691926Smax.romanov@nginx.com && nxt_router_app_can_start(app) 45701926Smax.romanov@nginx.com && nxt_router_app_need_start(app); 45711926Smax.romanov@nginx.com 45721926Smax.romanov@nginx.com if (start_process) { 45731926Smax.romanov@nginx.com app->pending_processes++; 45741926Smax.romanov@nginx.com } 45751926Smax.romanov@nginx.com 45761926Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 45771926Smax.romanov@nginx.com 45781926Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 45791926Smax.romanov@nginx.com 45801926Smax.romanov@nginx.com if (start_process) { 45811926Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 45821926Smax.romanov@nginx.com } 45831926Smax.romanov@nginx.com 45841926Smax.romanov@nginx.com return; 45851926Smax.romanov@nginx.com } 45861926Smax.romanov@nginx.com 45871926Smax.romanov@nginx.com port->app = app; 45881926Smax.romanov@nginx.com port->main_app_port = port; 45891926Smax.romanov@nginx.com 4590507Smax.romanov@nginx.com app->processes++; 45911547Smax.romanov@nginx.com nxt_port_hash_add(&app->port_hash, port); 45921547Smax.romanov@nginx.com app->port_hash_count++; 4593343Smax.romanov@nginx.com 4594343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4595343Smax.romanov@nginx.com 4596507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 4597507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 4598343Smax.romanov@nginx.com 45991547Smax.romanov@nginx.com nxt_router_app_shared_port_send(task, port); 46001547Smax.romanov@nginx.com 46011978Smax.romanov@nginx.com nxt_router_app_port_release(task, app, port, NXT_APR_NEW_PORT); 4602192Smax.romanov@nginx.com } 4603192Smax.romanov@nginx.com 4604192Smax.romanov@nginx.com 46051547Smax.romanov@nginx.com static nxt_int_t 46061547Smax.romanov@nginx.com nxt_router_app_shared_port_send(nxt_task_t *task, nxt_port_t *app_port) 46071547Smax.romanov@nginx.com { 46081547Smax.romanov@nginx.com nxt_buf_t *b; 46091547Smax.romanov@nginx.com nxt_port_t *port; 46101547Smax.romanov@nginx.com nxt_port_msg_new_port_t *msg; 46111547Smax.romanov@nginx.com 46121547Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 46131547Smax.romanov@nginx.com sizeof(nxt_port_data_t)); 46141547Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 46151547Smax.romanov@nginx.com return NXT_ERROR; 46161547Smax.romanov@nginx.com } 46171547Smax.romanov@nginx.com 46181547Smax.romanov@nginx.com port = app_port->app->shared_port; 46191547Smax.romanov@nginx.com 46201547Smax.romanov@nginx.com nxt_debug(task, "send port %FD to process %PI", 46211547Smax.romanov@nginx.com port->pair[0], app_port->pid); 46221547Smax.romanov@nginx.com 46231547Smax.romanov@nginx.com b->mem.free += sizeof(nxt_port_msg_new_port_t); 46241547Smax.romanov@nginx.com msg = (nxt_port_msg_new_port_t *) b->mem.pos; 46251547Smax.romanov@nginx.com 46261547Smax.romanov@nginx.com msg->id = port->id; 46271547Smax.romanov@nginx.com msg->pid = port->pid; 46281547Smax.romanov@nginx.com msg->max_size = port->max_size; 46291547Smax.romanov@nginx.com msg->max_share = port->max_share; 46301547Smax.romanov@nginx.com msg->type = port->type; 46311547Smax.romanov@nginx.com 46321555Smax.romanov@nginx.com return nxt_port_socket_write2(task, app_port, 46331547Smax.romanov@nginx.com NXT_PORT_MSG_NEW_PORT, 46341555Smax.romanov@nginx.com port->pair[0], port->queue_fd, 46351555Smax.romanov@nginx.com 0, 0, b); 46361547Smax.romanov@nginx.com } 46371547Smax.romanov@nginx.com 46381547Smax.romanov@nginx.com 4639192Smax.romanov@nginx.com static void 4640343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 4641343Smax.romanov@nginx.com void *data) 4642192Smax.romanov@nginx.com { 46431926Smax.romanov@nginx.com nxt_app_t *app; 46441926Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 46451926Smax.romanov@nginx.com nxt_queue_link_t *link; 46461926Smax.romanov@nginx.com nxt_http_request_t *r; 46471926Smax.romanov@nginx.com nxt_app_joint_rpc_t *app_joint_rpc; 46481926Smax.romanov@nginx.com 46491926Smax.romanov@nginx.com nxt_assert(data != NULL); 46501926Smax.romanov@nginx.com 46511926Smax.romanov@nginx.com app_joint_rpc = data; 46521926Smax.romanov@nginx.com app_joint = app_joint_rpc->app_joint; 4653753Smax.romanov@nginx.com 4654753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 4655753Smax.romanov@nginx.com 4656753Smax.romanov@nginx.com app = app_joint->app; 4657753Smax.romanov@nginx.com 4658753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4659753Smax.romanov@nginx.com 4660753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 4661753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 4662753Smax.romanov@nginx.com 4663753Smax.romanov@nginx.com return; 4664753Smax.romanov@nginx.com } 4665343Smax.romanov@nginx.com 4666343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 4667343Smax.romanov@nginx.com 46681561Smax.romanov@nginx.com link = NULL; 46691561Smax.romanov@nginx.com 4670343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4671343Smax.romanov@nginx.com 4672507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 4673507Smax.romanov@nginx.com 4674507Smax.romanov@nginx.com app->pending_processes--; 4675318Smax.romanov@nginx.com 46761561Smax.romanov@nginx.com if (app->processes == 0 && !nxt_queue_is_empty(&app->ack_waiting_req)) { 46771561Smax.romanov@nginx.com link = nxt_queue_first(&app->ack_waiting_req); 46781561Smax.romanov@nginx.com 46791561Smax.romanov@nginx.com nxt_queue_remove(link); 46801561Smax.romanov@nginx.com link->next = NULL; 46811561Smax.romanov@nginx.com } 46821561Smax.romanov@nginx.com 4683343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4684343Smax.romanov@nginx.com 46851561Smax.romanov@nginx.com while (link != NULL) { 46861561Smax.romanov@nginx.com r = nxt_container_of(link, nxt_http_request_t, app_link); 46871561Smax.romanov@nginx.com 46881561Smax.romanov@nginx.com nxt_event_engine_post(r->engine, &r->err_work); 46891561Smax.romanov@nginx.com 46901561Smax.romanov@nginx.com link = NULL; 46911561Smax.romanov@nginx.com 46921561Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 46931561Smax.romanov@nginx.com 46941561Smax.romanov@nginx.com if (app->processes == 0 && app->pending_processes == 0 46951561Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->ack_waiting_req)) 46961561Smax.romanov@nginx.com { 46971561Smax.romanov@nginx.com link = nxt_queue_first(&app->ack_waiting_req); 46981561Smax.romanov@nginx.com 46991561Smax.romanov@nginx.com nxt_queue_remove(link); 47001561Smax.romanov@nginx.com link->next = NULL; 47011561Smax.romanov@nginx.com } 47021561Smax.romanov@nginx.com 47031561Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 47041561Smax.romanov@nginx.com } 4705192Smax.romanov@nginx.com } 4706192Smax.romanov@nginx.com 4707192Smax.romanov@nginx.com 4708507Smax.romanov@nginx.com nxt_inline nxt_port_t * 47091549Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app) 4710141Smax.romanov@nginx.com { 4711343Smax.romanov@nginx.com nxt_port_t *port; 4712141Smax.romanov@nginx.com 4713141Smax.romanov@nginx.com port = NULL; 4714141Smax.romanov@nginx.com 4715141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4716141Smax.romanov@nginx.com 4717343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 4718343Smax.romanov@nginx.com 4719507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 4720507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4721507Smax.romanov@nginx.com 4722507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4723507Smax.romanov@nginx.com app->idle_processes--; 47241549Smax.romanov@nginx.com 47251549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s for quit", 47261549Smax.romanov@nginx.com &app->name, port->pid, port->id, 47271549Smax.romanov@nginx.com (port->idle_start ? "idle_ports" : "spare_ports")); 4728507Smax.romanov@nginx.com } 4729507Smax.romanov@nginx.com 47301547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 47311547Smax.romanov@nginx.com app->port_hash_count--; 47321547Smax.romanov@nginx.com 4733507Smax.romanov@nginx.com port->app = NULL; 4734507Smax.romanov@nginx.com app->processes--; 4735343Smax.romanov@nginx.com 4736343Smax.romanov@nginx.com break; 4737343Smax.romanov@nginx.com 4738343Smax.romanov@nginx.com } nxt_queue_loop; 4739141Smax.romanov@nginx.com 4740141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4741141Smax.romanov@nginx.com 4742141Smax.romanov@nginx.com return port; 4743141Smax.romanov@nginx.com } 4744141Smax.romanov@nginx.com 4745141Smax.romanov@nginx.com 4746141Smax.romanov@nginx.com static void 47471563Svbart@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 47481563Svbart@nginx.com { 47491563Svbart@nginx.com int c; 47501563Svbart@nginx.com 47511563Svbart@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 47521563Svbart@nginx.com 47531563Svbart@nginx.com if (i < 0 && c == -i) { 47541563Svbart@nginx.com 47551563Svbart@nginx.com if (task->thread->engine != app->engine) { 47561563Svbart@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 47571563Svbart@nginx.com 47581563Svbart@nginx.com } else { 47591563Svbart@nginx.com nxt_router_free_app(task, app->joint, NULL); 47601563Svbart@nginx.com } 47611563Svbart@nginx.com } 47621563Svbart@nginx.com } 47631563Svbart@nginx.com 47641563Svbart@nginx.com 47651563Svbart@nginx.com static void 4766753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 4767507Smax.romanov@nginx.com { 4768753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 4769507Smax.romanov@nginx.com 4770507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 4771507Smax.romanov@nginx.com 4772753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4773507Smax.romanov@nginx.com } 4774507Smax.romanov@nginx.com 4775507Smax.romanov@nginx.com 4776507Smax.romanov@nginx.com static void 47771978Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_app_t *app, nxt_port_t *port, 47781123Smax.romanov@nginx.com nxt_apr_action_t action) 4779343Smax.romanov@nginx.com { 47801547Smax.romanov@nginx.com int inc_use; 47811547Smax.romanov@nginx.com uint32_t got_response, dec_requests; 47821980Smax.romanov@nginx.com nxt_bool_t adjust_idle_timer; 47831547Smax.romanov@nginx.com nxt_port_t *main_app_port; 4784343Smax.romanov@nginx.com 4785343Smax.romanov@nginx.com nxt_assert(port != NULL); 4786343Smax.romanov@nginx.com 47871123Smax.romanov@nginx.com inc_use = 0; 47881123Smax.romanov@nginx.com got_response = 0; 47891547Smax.romanov@nginx.com dec_requests = 0; 47901123Smax.romanov@nginx.com 47911123Smax.romanov@nginx.com switch (action) { 47921123Smax.romanov@nginx.com case NXT_APR_NEW_PORT: 47931123Smax.romanov@nginx.com break; 47941123Smax.romanov@nginx.com case NXT_APR_REQUEST_FAILED: 47951547Smax.romanov@nginx.com dec_requests = 1; 47961123Smax.romanov@nginx.com inc_use = -1; 47971123Smax.romanov@nginx.com break; 47981123Smax.romanov@nginx.com case NXT_APR_GOT_RESPONSE: 47991123Smax.romanov@nginx.com got_response = 1; 48001123Smax.romanov@nginx.com inc_use = -1; 48011123Smax.romanov@nginx.com break; 48021131Smax.romanov@nginx.com case NXT_APR_UPGRADE: 48031131Smax.romanov@nginx.com got_response = 1; 48041131Smax.romanov@nginx.com break; 48051123Smax.romanov@nginx.com case NXT_APR_CLOSE: 48061123Smax.romanov@nginx.com inc_use = -1; 48071123Smax.romanov@nginx.com break; 48081123Smax.romanov@nginx.com } 48091123Smax.romanov@nginx.com 48101547Smax.romanov@nginx.com nxt_debug(task, "app '%V' release port %PI:%d: %d %d", &app->name, 48111547Smax.romanov@nginx.com port->pid, port->id, 48121547Smax.romanov@nginx.com (int) inc_use, (int) got_response); 48131547Smax.romanov@nginx.com 48141926Smax.romanov@nginx.com if (port->id == NXT_SHARED_PORT_ID) { 48151547Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 48161547Smax.romanov@nginx.com 48171547Smax.romanov@nginx.com app->active_requests -= got_response + dec_requests; 48181547Smax.romanov@nginx.com 48191547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 48201547Smax.romanov@nginx.com 48211547Smax.romanov@nginx.com goto adjust_use; 48221547Smax.romanov@nginx.com } 48231547Smax.romanov@nginx.com 48241547Smax.romanov@nginx.com main_app_port = port->main_app_port; 48251547Smax.romanov@nginx.com 4826343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4827343Smax.romanov@nginx.com 48281547Smax.romanov@nginx.com main_app_port->active_requests -= got_response + dec_requests; 48291547Smax.romanov@nginx.com app->active_requests -= got_response + dec_requests; 48301547Smax.romanov@nginx.com 48311980Smax.romanov@nginx.com if (main_app_port->pair[1] != -1 && main_app_port->app_link.next == NULL) { 48321980Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &main_app_port->app_link); 48331980Smax.romanov@nginx.com 48341980Smax.romanov@nginx.com nxt_port_inc_use(main_app_port); 4835507Smax.romanov@nginx.com } 4836507Smax.romanov@nginx.com 4837507Smax.romanov@nginx.com adjust_idle_timer = 0; 4838507Smax.romanov@nginx.com 48391980Smax.romanov@nginx.com if (main_app_port->pair[1] != -1 48401547Smax.romanov@nginx.com && main_app_port->active_requests == 0 48411547Smax.romanov@nginx.com && main_app_port->active_websockets == 0 48421547Smax.romanov@nginx.com && main_app_port->idle_link.next == NULL) 48431131Smax.romanov@nginx.com { 4844507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 4845507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 4846507Smax.romanov@nginx.com { 4847507Smax.romanov@nginx.com adjust_idle_timer = 1; 4848507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 4849507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 4850507Smax.romanov@nginx.com } 4851507Smax.romanov@nginx.com 4852507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 48531547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &main_app_port->idle_link); 4854507Smax.romanov@nginx.com 48551549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d to spare_ports", 48561549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id); 4857507Smax.romanov@nginx.com } else { 48581547Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &main_app_port->idle_link); 48591547Smax.romanov@nginx.com 48601547Smax.romanov@nginx.com main_app_port->idle_start = task->thread->engine->timers.now; 48611549Smax.romanov@nginx.com 48621549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d to idle_ports", 48631549Smax.romanov@nginx.com &app->name, main_app_port->pid, main_app_port->id); 4864507Smax.romanov@nginx.com } 4865507Smax.romanov@nginx.com 4866507Smax.romanov@nginx.com app->idle_processes++; 4867507Smax.romanov@nginx.com } 4868507Smax.romanov@nginx.com 4869343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4870343Smax.romanov@nginx.com 4871507Smax.romanov@nginx.com if (adjust_idle_timer) { 4872507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4873507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4874507Smax.romanov@nginx.com } 4875507Smax.romanov@nginx.com 4876343Smax.romanov@nginx.com /* ? */ 48771547Smax.romanov@nginx.com if (main_app_port->pair[1] == -1) { 4878343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 48791547Smax.romanov@nginx.com &app->name, app, main_app_port, main_app_port->pid); 4880343Smax.romanov@nginx.com 4881343Smax.romanov@nginx.com goto adjust_use; 4882163Smax.romanov@nginx.com } 4883163Smax.romanov@nginx.com 4884167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4885167Smax.romanov@nginx.com &app->name, app); 4886141Smax.romanov@nginx.com 4887343Smax.romanov@nginx.com adjust_use: 4888343Smax.romanov@nginx.com 48891123Smax.romanov@nginx.com nxt_port_use(task, port, inc_use); 4890141Smax.romanov@nginx.com } 4891141Smax.romanov@nginx.com 4892141Smax.romanov@nginx.com 4893343Smax.romanov@nginx.com void 4894343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4895141Smax.romanov@nginx.com { 4896507Smax.romanov@nginx.com nxt_app_t *app; 4897507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4898507Smax.romanov@nginx.com nxt_port_t *idle_port; 4899507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4900141Smax.romanov@nginx.com 4901141Smax.romanov@nginx.com app = port->app; 4902343Smax.romanov@nginx.com 4903343Smax.romanov@nginx.com nxt_assert(app != NULL); 4904141Smax.romanov@nginx.com 4905141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4906141Smax.romanov@nginx.com 4907*1998St.nateldemoura@f5.com if (port == app->proto_port) { 4908*1998St.nateldemoura@f5.com app->proto_port = NULL; 4909*1998St.nateldemoura@f5.com port->app = NULL; 4910*1998St.nateldemoura@f5.com 4911*1998St.nateldemoura@f5.com nxt_thread_mutex_unlock(&app->mutex); 4912*1998St.nateldemoura@f5.com 4913*1998St.nateldemoura@f5.com nxt_debug(task, "app '%V' prototype pid %PI closed", &app->name, 4914*1998St.nateldemoura@f5.com port->pid); 4915*1998St.nateldemoura@f5.com 4916*1998St.nateldemoura@f5.com nxt_port_use(task, port, -1); 4917*1998St.nateldemoura@f5.com 4918*1998St.nateldemoura@f5.com return; 4919*1998St.nateldemoura@f5.com } 4920*1998St.nateldemoura@f5.com 49211547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 49221547Smax.romanov@nginx.com app->port_hash_count--; 49231547Smax.romanov@nginx.com 49241547Smax.romanov@nginx.com if (port->id != 0) { 49251547Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 49261547Smax.romanov@nginx.com 49271547Smax.romanov@nginx.com nxt_debug(task, "app '%V' port (%PI, %d) closed", &app->name, 49281547Smax.romanov@nginx.com port->pid, port->id); 49291547Smax.romanov@nginx.com 49301547Smax.romanov@nginx.com return; 49311547Smax.romanov@nginx.com } 49321547Smax.romanov@nginx.com 4933507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4934507Smax.romanov@nginx.com 4935507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4936507Smax.romanov@nginx.com app->idle_processes--; 4937507Smax.romanov@nginx.com 49381549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of %s before close", 49391549Smax.romanov@nginx.com &app->name, port->pid, port->id, 49401549Smax.romanov@nginx.com (port->idle_start ? "idle_ports" : "spare_ports")); 49411549Smax.romanov@nginx.com 4942507Smax.romanov@nginx.com if (port->idle_start == 0 4943507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4944507Smax.romanov@nginx.com { 4945507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4946507Smax.romanov@nginx.com 4947507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4948507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4949507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4950507Smax.romanov@nginx.com 4951507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4952507Smax.romanov@nginx.com 4953507Smax.romanov@nginx.com idle_port->idle_start = 0; 49541549Smax.romanov@nginx.com 49551549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d from idle_ports " 49561549Smax.romanov@nginx.com "to spare_ports", 49571549Smax.romanov@nginx.com &app->name, idle_port->pid, idle_port->id); 4958507Smax.romanov@nginx.com } 4959343Smax.romanov@nginx.com } 4960343Smax.romanov@nginx.com 4961507Smax.romanov@nginx.com app->processes--; 4962507Smax.romanov@nginx.com 4963753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4964507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 49651547Smax.romanov@nginx.com && nxt_router_app_need_start(app); 4966507Smax.romanov@nginx.com 4967507Smax.romanov@nginx.com if (start_process) { 4968507Smax.romanov@nginx.com app->pending_processes++; 4969163Smax.romanov@nginx.com } 4970141Smax.romanov@nginx.com 4971141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4972163Smax.romanov@nginx.com 4973507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4974343Smax.romanov@nginx.com 4975343Smax.romanov@nginx.com if (unchain) { 4976343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4977163Smax.romanov@nginx.com } 4978163Smax.romanov@nginx.com 4979507Smax.romanov@nginx.com if (start_process) { 4980507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4981507Smax.romanov@nginx.com } 4982507Smax.romanov@nginx.com } 4983507Smax.romanov@nginx.com 4984507Smax.romanov@nginx.com 4985507Smax.romanov@nginx.com static void 4986507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4987507Smax.romanov@nginx.com { 4988507Smax.romanov@nginx.com nxt_app_t *app; 4989507Smax.romanov@nginx.com nxt_bool_t queued; 4990507Smax.romanov@nginx.com nxt_port_t *port; 4991507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4992507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4993507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4994507Smax.romanov@nginx.com 4995507Smax.romanov@nginx.com app = obj; 4996507Smax.romanov@nginx.com queued = (data == app); 4997507Smax.romanov@nginx.com 4998507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4999507Smax.romanov@nginx.com &app->name, queued); 5000507Smax.romanov@nginx.com 5001507Smax.romanov@nginx.com engine = task->thread->engine; 5002507Smax.romanov@nginx.com 5003507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 5004507Smax.romanov@nginx.com 5005811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 5006507Smax.romanov@nginx.com timeout = 0; 5007507Smax.romanov@nginx.com 5008507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 5009507Smax.romanov@nginx.com 5010507Smax.romanov@nginx.com if (queued) { 5011507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 5012343Smax.romanov@nginx.com } 5013507Smax.romanov@nginx.com 50141547Smax.romanov@nginx.com nxt_debug(task, "app '%V' idle_processes %d, spare_processes %d", 50151547Smax.romanov@nginx.com &app->name, 50161547Smax.romanov@nginx.com (int) app->idle_processes, (int) app->spare_processes); 50171547Smax.romanov@nginx.com 5018507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 5019507Smax.romanov@nginx.com 5020551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 5021507Smax.romanov@nginx.com 5022507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 5023507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 5024507Smax.romanov@nginx.com 5025507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 5026507Smax.romanov@nginx.com 50271547Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI, start %M, timeout %M, threshold %M", 50281547Smax.romanov@nginx.com &app->name, port->pid, 50291547Smax.romanov@nginx.com port->idle_start, timeout, threshold); 50301547Smax.romanov@nginx.com 5031507Smax.romanov@nginx.com if (timeout > threshold) { 5032507Smax.romanov@nginx.com break; 5033507Smax.romanov@nginx.com } 5034507Smax.romanov@nginx.com 5035507Smax.romanov@nginx.com nxt_queue_remove(lnk); 5036507Smax.romanov@nginx.com lnk->next = NULL; 5037507Smax.romanov@nginx.com 50381549Smax.romanov@nginx.com nxt_debug(task, "app '%V' move port %PI:%d out of idle_ports (timeout)", 50391549Smax.romanov@nginx.com &app->name, port->pid, port->id); 50401549Smax.romanov@nginx.com 5041507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 5042507Smax.romanov@nginx.com 50431547Smax.romanov@nginx.com nxt_port_hash_remove(&app->port_hash, port); 50441547Smax.romanov@nginx.com app->port_hash_count--; 50451547Smax.romanov@nginx.com 5046507Smax.romanov@nginx.com app->idle_processes--; 5047507Smax.romanov@nginx.com app->processes--; 5048507Smax.romanov@nginx.com port->app = NULL; 5049507Smax.romanov@nginx.com 5050507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 5051507Smax.romanov@nginx.com 5052507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 5053507Smax.romanov@nginx.com &app->name, port->pid); 5054507Smax.romanov@nginx.com 5055507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 5056507Smax.romanov@nginx.com 5057507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 5058507Smax.romanov@nginx.com 5059507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 5060507Smax.romanov@nginx.com } 5061507Smax.romanov@nginx.com 5062507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 5063507Smax.romanov@nginx.com 5064507Smax.romanov@nginx.com if (timeout > threshold) { 5065753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 5066507Smax.romanov@nginx.com 5067507Smax.romanov@nginx.com } else { 5068753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 5069507Smax.romanov@nginx.com } 5070507Smax.romanov@nginx.com 5071507Smax.romanov@nginx.com if (queued) { 5072507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 5073507Smax.romanov@nginx.com } 5074507Smax.romanov@nginx.com } 5075507Smax.romanov@nginx.com 5076507Smax.romanov@nginx.com 5077507Smax.romanov@nginx.com static void 5078507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 5079507Smax.romanov@nginx.com { 5080753Smax.romanov@nginx.com nxt_timer_t *timer; 5081753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 5082507Smax.romanov@nginx.com 5083507Smax.romanov@nginx.com timer = obj; 5084753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 5085753Smax.romanov@nginx.com 5086753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 5087753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 5088753Smax.romanov@nginx.com } 5089753Smax.romanov@nginx.com } 5090753Smax.romanov@nginx.com 5091753Smax.romanov@nginx.com 5092753Smax.romanov@nginx.com static void 5093753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 5094753Smax.romanov@nginx.com { 5095753Smax.romanov@nginx.com nxt_timer_t *timer; 5096753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 5097753Smax.romanov@nginx.com 5098753Smax.romanov@nginx.com timer = obj; 5099753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 5100753Smax.romanov@nginx.com 5101753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 5102507Smax.romanov@nginx.com } 5103507Smax.romanov@nginx.com 5104507Smax.romanov@nginx.com 5105507Smax.romanov@nginx.com static void 5106753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 5107507Smax.romanov@nginx.com { 5108753Smax.romanov@nginx.com nxt_app_t *app; 5109*1998St.nateldemoura@f5.com nxt_port_t *port, *proto_port; 5110753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 5111753Smax.romanov@nginx.com 5112753Smax.romanov@nginx.com app_joint = obj; 5113753Smax.romanov@nginx.com app = app_joint->app; 5114753Smax.romanov@nginx.com 5115753Smax.romanov@nginx.com for ( ;; ) { 51161549Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(task, app); 5117753Smax.romanov@nginx.com if (port == NULL) { 5118753Smax.romanov@nginx.com break; 5119753Smax.romanov@nginx.com } 5120753Smax.romanov@nginx.com 5121753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 5122753Smax.romanov@nginx.com } 5123753Smax.romanov@nginx.com 51241658Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 51251658Smax.romanov@nginx.com 51261658Smax.romanov@nginx.com for ( ;; ) { 51271658Smax.romanov@nginx.com port = nxt_port_hash_retrieve(&app->port_hash); 51281658Smax.romanov@nginx.com if (port == NULL) { 51291658Smax.romanov@nginx.com break; 51301658Smax.romanov@nginx.com } 51311658Smax.romanov@nginx.com 51321658Smax.romanov@nginx.com app->port_hash_count--; 51331658Smax.romanov@nginx.com 51341658Smax.romanov@nginx.com port->app = NULL; 51351658Smax.romanov@nginx.com 51361658Smax.romanov@nginx.com nxt_port_close(task, port); 51371658Smax.romanov@nginx.com 51381658Smax.romanov@nginx.com nxt_port_use(task, port, -1); 51391658Smax.romanov@nginx.com } 51401658Smax.romanov@nginx.com 5141*1998St.nateldemoura@f5.com proto_port = app->proto_port; 5142*1998St.nateldemoura@f5.com 5143*1998St.nateldemoura@f5.com if (proto_port != NULL) { 5144*1998St.nateldemoura@f5.com nxt_debug(task, "send QUIT to prototype '%V' pid %PI", &app->name, 5145*1998St.nateldemoura@f5.com proto_port->pid); 5146*1998St.nateldemoura@f5.com 5147*1998St.nateldemoura@f5.com app->proto_port = NULL; 5148*1998St.nateldemoura@f5.com proto_port->app = NULL; 5149*1998St.nateldemoura@f5.com } 5150*1998St.nateldemoura@f5.com 51511658Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 51521658Smax.romanov@nginx.com 5153*1998St.nateldemoura@f5.com if (proto_port != NULL) { 5154*1998St.nateldemoura@f5.com nxt_port_socket_write(task, proto_port, NXT_PORT_MSG_QUIT, 5155*1998St.nateldemoura@f5.com -1, 0, 0, NULL); 5156*1998St.nateldemoura@f5.com 5157*1998St.nateldemoura@f5.com nxt_port_close(task, proto_port); 5158*1998St.nateldemoura@f5.com 5159*1998St.nateldemoura@f5.com nxt_port_use(task, proto_port, -1); 5160*1998St.nateldemoura@f5.com } 5161*1998St.nateldemoura@f5.com 5162*1998St.nateldemoura@f5.com nxt_assert(app->proto_port == NULL); 5163753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 51641547Smax.romanov@nginx.com nxt_assert(app->active_requests == 0); 51651547Smax.romanov@nginx.com nxt_assert(app->port_hash_count == 0); 5166753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 5167753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 5168753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 5169753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 5170753Smax.romanov@nginx.com 51711547Smax.romanov@nginx.com nxt_port_mmaps_destroy(&app->outgoing, 1); 51721547Smax.romanov@nginx.com 51731547Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->outgoing.mutex); 51741547Smax.romanov@nginx.com 51751547Smax.romanov@nginx.com if (app->shared_port != NULL) { 51761547Smax.romanov@nginx.com app->shared_port->app = NULL; 51771547Smax.romanov@nginx.com nxt_port_close(task, app->shared_port); 51781547Smax.romanov@nginx.com nxt_port_use(task, app->shared_port, -1); 51791926Smax.romanov@nginx.com 51801926Smax.romanov@nginx.com app->shared_port = NULL; 51811547Smax.romanov@nginx.com } 51821547Smax.romanov@nginx.com 5183753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 51841473Svbart@nginx.com nxt_mp_destroy(app->mem_pool); 5185753Smax.romanov@nginx.com 5186753Smax.romanov@nginx.com app_joint->app = NULL; 5187753Smax.romanov@nginx.com 5188753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 5189753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 5190753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 5191753Smax.romanov@nginx.com 5192753Smax.romanov@nginx.com } else { 5193753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 5194753Smax.romanov@nginx.com } 5195141Smax.romanov@nginx.com } 5196141Smax.romanov@nginx.com 5197141Smax.romanov@nginx.com 5198427Smax.romanov@nginx.com static void 51991547Smax.romanov@nginx.com nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app, 52001547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 5201141Smax.romanov@nginx.com { 52021561Smax.romanov@nginx.com nxt_bool_t start_process; 52031561Smax.romanov@nginx.com nxt_port_t *port; 52041561Smax.romanov@nginx.com nxt_http_request_t *r; 52051547Smax.romanov@nginx.com 52061547Smax.romanov@nginx.com start_process = 0; 5207427Smax.romanov@nginx.com 5208427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 5209427Smax.romanov@nginx.com 52101547Smax.romanov@nginx.com port = app->shared_port; 52111547Smax.romanov@nginx.com nxt_port_inc_use(port); 52121547Smax.romanov@nginx.com 52131547Smax.romanov@nginx.com app->active_requests++; 52141547Smax.romanov@nginx.com 52151547Smax.romanov@nginx.com if (nxt_router_app_can_start(app) && nxt_router_app_need_start(app)) { 52161547Smax.romanov@nginx.com app->pending_processes++; 52171547Smax.romanov@nginx.com start_process = 1; 52181547Smax.romanov@nginx.com } 5219427Smax.romanov@nginx.com 52201561Smax.romanov@nginx.com r = req_rpc_data->request; 52211561Smax.romanov@nginx.com 52221561Smax.romanov@nginx.com /* 52231561Smax.romanov@nginx.com * Put request into application-wide list to be able to cancel request 52241561Smax.romanov@nginx.com * if something goes wrong with application processes. 52251561Smax.romanov@nginx.com */ 52261561Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ack_waiting_req, &r->app_link); 52271561Smax.romanov@nginx.com 5228427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 5229427Smax.romanov@nginx.com 52301561Smax.romanov@nginx.com /* 52311561Smax.romanov@nginx.com * Retain request memory pool while request is linked in ack_waiting_req 52321561Smax.romanov@nginx.com * to guarantee request structure memory is accessble. 52331561Smax.romanov@nginx.com */ 52341561Smax.romanov@nginx.com nxt_mp_retain(r->mem_pool); 52351561Smax.romanov@nginx.com 52361547Smax.romanov@nginx.com req_rpc_data->app_port = port; 52371547Smax.romanov@nginx.com req_rpc_data->apr_action = NXT_APR_REQUEST_FAILED; 52381547Smax.romanov@nginx.com 52391547Smax.romanov@nginx.com if (start_process) { 52401547Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 52411547Smax.romanov@nginx.com } 5242427Smax.romanov@nginx.com } 5243427Smax.romanov@nginx.com 5244427Smax.romanov@nginx.com 5245431Sigor@sysoev.ru void 52461007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, 52471925Sz.hong@f5.com nxt_http_action_t *action) 524853Sigor@sysoev.ru { 52491123Smax.romanov@nginx.com nxt_event_engine_t *engine; 52501925Sz.hong@f5.com nxt_http_app_conf_t *conf; 52511123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5252431Sigor@sysoev.ru 52531925Sz.hong@f5.com conf = action->u.conf; 525488Smax.romanov@nginx.com engine = task->thread->engine; 525588Smax.romanov@nginx.com 52561925Sz.hong@f5.com r->app_target = conf->target; 52571925Sz.hong@f5.com 52581123Smax.romanov@nginx.com req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port, 5259318Smax.romanov@nginx.com nxt_router_response_ready_handler, 5260318Smax.romanov@nginx.com nxt_router_response_error_handler, 52611123Smax.romanov@nginx.com sizeof(nxt_request_rpc_data_t)); 52621123Smax.romanov@nginx.com if (nxt_slow_path(req_rpc_data == NULL)) { 5263431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 5264141Smax.romanov@nginx.com return; 526588Smax.romanov@nginx.com } 526688Smax.romanov@nginx.com 52671402Smax.romanov@nginx.com /* 52681402Smax.romanov@nginx.com * At this point we have request req_rpc_data allocated and registered 52691402Smax.romanov@nginx.com * in port handlers. Need to fixup request memory pool. Counterpart 52701402Smax.romanov@nginx.com * release will be called via following call chain: 52711402Smax.romanov@nginx.com * nxt_request_rpc_data_unlink() -> 52721547Smax.romanov@nginx.com * nxt_router_http_request_release_post() -> 52731402Smax.romanov@nginx.com * nxt_router_http_request_release() 52741402Smax.romanov@nginx.com */ 52751402Smax.romanov@nginx.com nxt_mp_retain(r->mem_pool); 52761402Smax.romanov@nginx.com 52771402Smax.romanov@nginx.com r->timer.task = &engine->task; 52781402Smax.romanov@nginx.com r->timer.work_queue = &engine->fast_work_queue; 52791402Smax.romanov@nginx.com r->timer.log = engine->task.log; 52801402Smax.romanov@nginx.com r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 52811402Smax.romanov@nginx.com 52821561Smax.romanov@nginx.com r->engine = engine; 52831561Smax.romanov@nginx.com r->err_work.handler = nxt_router_http_request_error; 52841561Smax.romanov@nginx.com r->err_work.task = task; 52851561Smax.romanov@nginx.com r->err_work.obj = r; 52861561Smax.romanov@nginx.com 52871123Smax.romanov@nginx.com req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data); 52881925Sz.hong@f5.com req_rpc_data->app = conf->app; 52891547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 52901547Smax.romanov@nginx.com req_rpc_data->rpc_cancel = 1; 5291425Smax.romanov@nginx.com 52921925Sz.hong@f5.com nxt_router_app_use(task, conf->app, 1); 5293425Smax.romanov@nginx.com 52941123Smax.romanov@nginx.com req_rpc_data->request = r; 52951131Smax.romanov@nginx.com r->req_rpc_data = req_rpc_data; 52961123Smax.romanov@nginx.com 52971547Smax.romanov@nginx.com if (r->last != NULL) { 52981547Smax.romanov@nginx.com r->last->completion_handler = nxt_router_http_request_done; 52991547Smax.romanov@nginx.com } 53001547Smax.romanov@nginx.com 53011925Sz.hong@f5.com nxt_router_app_port_get(task, conf->app, req_rpc_data); 53021547Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_rpc_data); 53031547Smax.romanov@nginx.com } 53041547Smax.romanov@nginx.com 53051547Smax.romanov@nginx.com 53061547Smax.romanov@nginx.com static void 53071561Smax.romanov@nginx.com nxt_router_http_request_error(nxt_task_t *task, void *obj, void *data) 53081561Smax.romanov@nginx.com { 53091561Smax.romanov@nginx.com nxt_http_request_t *r; 53101561Smax.romanov@nginx.com 53111561Smax.romanov@nginx.com r = obj; 53121561Smax.romanov@nginx.com 53131561Smax.romanov@nginx.com nxt_debug(task, "router http request error (rpc_data %p)", r->req_rpc_data); 53141561Smax.romanov@nginx.com 53151561Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 53161561Smax.romanov@nginx.com 53171561Smax.romanov@nginx.com if (r->req_rpc_data != NULL) { 53181561Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, r->req_rpc_data); 53191561Smax.romanov@nginx.com } 53201561Smax.romanov@nginx.com 53211561Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 53221561Smax.romanov@nginx.com } 53231561Smax.romanov@nginx.com 53241561Smax.romanov@nginx.com 53251561Smax.romanov@nginx.com static void 53261547Smax.romanov@nginx.com nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data) 53271547Smax.romanov@nginx.com { 53281547Smax.romanov@nginx.com nxt_http_request_t *r; 53291547Smax.romanov@nginx.com 53301547Smax.romanov@nginx.com r = data; 53311547Smax.romanov@nginx.com 53321547Smax.romanov@nginx.com nxt_debug(task, "router http request done (rpc_data %p)", r->req_rpc_data); 53331547Smax.romanov@nginx.com 53341561Smax.romanov@nginx.com if (r->req_rpc_data != NULL) { 53351547Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, r->req_rpc_data); 53361547Smax.romanov@nginx.com } 53371547Smax.romanov@nginx.com 53381547Smax.romanov@nginx.com nxt_http_request_close_handler(task, r, r->proto.any); 5339167Smax.romanov@nginx.com } 5340167Smax.romanov@nginx.com 5341167Smax.romanov@nginx.com 5342167Smax.romanov@nginx.com static void 53431123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, 53441547Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 5345167Smax.romanov@nginx.com { 53461547Smax.romanov@nginx.com nxt_app_t *app; 53471547Smax.romanov@nginx.com nxt_buf_t *buf, *body; 53481123Smax.romanov@nginx.com nxt_int_t res; 53491545Smax.romanov@nginx.com nxt_port_t *port, *reply_port; 53501547Smax.romanov@nginx.com 53511555Smax.romanov@nginx.com int notify; 53521555Smax.romanov@nginx.com struct { 53531555Smax.romanov@nginx.com nxt_port_msg_t pm; 53541555Smax.romanov@nginx.com nxt_port_mmap_msg_t mm; 53551555Smax.romanov@nginx.com } msg; 53561555Smax.romanov@nginx.com 53571555Smax.romanov@nginx.com 53581547Smax.romanov@nginx.com app = req_rpc_data->app; 53591547Smax.romanov@nginx.com 53601547Smax.romanov@nginx.com nxt_assert(app != NULL); 53611547Smax.romanov@nginx.com 53621547Smax.romanov@nginx.com port = req_rpc_data->app_port; 53631547Smax.romanov@nginx.com 53641547Smax.romanov@nginx.com nxt_assert(port != NULL); 53651555Smax.romanov@nginx.com nxt_assert(port->queue != NULL); 53661547Smax.romanov@nginx.com 53671547Smax.romanov@nginx.com reply_port = task->thread->engine->port; 53681547Smax.romanov@nginx.com 53691547Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, req_rpc_data->request, app, 53701547Smax.romanov@nginx.com nxt_app_msg_prefix[app->type]); 5371743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 53721547Smax.romanov@nginx.com nxt_alert(task, "stream #%uD, app '%V': failed to prepare app message", 53731547Smax.romanov@nginx.com req_rpc_data->stream, &app->name); 53741547Smax.romanov@nginx.com 53751547Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 53761547Smax.romanov@nginx.com NXT_HTTP_INTERNAL_SERVER_ERROR); 53771547Smax.romanov@nginx.com 53781547Smax.romanov@nginx.com return; 5379122Smax.romanov@nginx.com } 538088Smax.romanov@nginx.com 5381507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 5382743Smax.romanov@nginx.com nxt_buf_used_size(buf), 5383743Smax.romanov@nginx.com port->socket.fd); 538488Smax.romanov@nginx.com 53851547Smax.romanov@nginx.com req_rpc_data->msg_info.buf = buf; 53861547Smax.romanov@nginx.com 53871547Smax.romanov@nginx.com body = req_rpc_data->request->body; 53881547Smax.romanov@nginx.com 53891547Smax.romanov@nginx.com if (body != NULL && nxt_buf_is_file(body)) { 53901547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = body->file->fd; 53911547Smax.romanov@nginx.com 53921547Smax.romanov@nginx.com body->file->fd = -1; 53931547Smax.romanov@nginx.com 53941547Smax.romanov@nginx.com } else { 53951547Smax.romanov@nginx.com req_rpc_data->msg_info.body_fd = -1; 53961547Smax.romanov@nginx.com } 53971547Smax.romanov@nginx.com 53981555Smax.romanov@nginx.com msg.pm.stream = req_rpc_data->stream; 53991555Smax.romanov@nginx.com msg.pm.pid = reply_port->pid; 54001555Smax.romanov@nginx.com msg.pm.reply_port = reply_port->id; 54011555Smax.romanov@nginx.com msg.pm.type = NXT_PORT_MSG_REQ_HEADERS; 54021555Smax.romanov@nginx.com msg.pm.last = 0; 54031555Smax.romanov@nginx.com msg.pm.mmap = 1; 54041555Smax.romanov@nginx.com msg.pm.nf = 0; 54051555Smax.romanov@nginx.com msg.pm.mf = 0; 54061555Smax.romanov@nginx.com msg.pm.tracking = 0; 54071555Smax.romanov@nginx.com 54081555Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler = buf->parent; 54091555Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr = mmap_handler->hdr; 54101555Smax.romanov@nginx.com 54111555Smax.romanov@nginx.com msg.mm.mmap_id = hdr->id; 54121555Smax.romanov@nginx.com msg.mm.chunk_id = nxt_port_mmap_chunk_id(hdr, buf->mem.pos); 54131555Smax.romanov@nginx.com msg.mm.size = nxt_buf_used_size(buf); 54141555Smax.romanov@nginx.com 54151555Smax.romanov@nginx.com res = nxt_app_queue_send(port->queue, &msg, sizeof(msg), 54161555Smax.romanov@nginx.com req_rpc_data->stream, ¬ify, 54171555Smax.romanov@nginx.com &req_rpc_data->msg_info.tracking_cookie); 54181555Smax.romanov@nginx.com if (nxt_fast_path(res == NXT_OK)) { 54191555Smax.romanov@nginx.com if (notify != 0) { 54201555Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, 54211555Smax.romanov@nginx.com NXT_PORT_MSG_READ_QUEUE, 54221555Smax.romanov@nginx.com -1, req_rpc_data->stream, 54231555Smax.romanov@nginx.com reply_port->id, NULL); 54241555Smax.romanov@nginx.com 54251555Smax.romanov@nginx.com } else { 54261555Smax.romanov@nginx.com nxt_debug(task, "queue is not empty"); 54271555Smax.romanov@nginx.com } 54281555Smax.romanov@nginx.com 54291615Smax.romanov@nginx.com buf->is_port_mmap_sent = 1; 54301615Smax.romanov@nginx.com buf->mem.pos = buf->mem.free; 54311615Smax.romanov@nginx.com 54321555Smax.romanov@nginx.com } else { 54331547Smax.romanov@nginx.com nxt_alert(task, "stream #%uD, app '%V': failed to send app message", 54341547Smax.romanov@nginx.com req_rpc_data->stream, &app->name); 54351547Smax.romanov@nginx.com 54361547Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 54371547Smax.romanov@nginx.com NXT_HTTP_INTERNAL_SERVER_ERROR); 54381547Smax.romanov@nginx.com } 543953Sigor@sysoev.ru } 544053Sigor@sysoev.ru 544153Sigor@sysoev.ru 5442743Smax.romanov@nginx.com struct nxt_fields_iter_s { 5443743Smax.romanov@nginx.com nxt_list_part_t *part; 5444743Smax.romanov@nginx.com nxt_http_field_t *field; 5445743Smax.romanov@nginx.com }; 5446743Smax.romanov@nginx.com 5447743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 5448743Smax.romanov@nginx.com 5449743Smax.romanov@nginx.com 5450743Smax.romanov@nginx.com static nxt_http_field_t * 5451743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 5452216Sigor@sysoev.ru { 5453743Smax.romanov@nginx.com if (part == NULL) { 5454743Smax.romanov@nginx.com return NULL; 5455216Sigor@sysoev.ru } 5456216Sigor@sysoev.ru 5457743Smax.romanov@nginx.com while (part->nelts == 0) { 5458743Smax.romanov@nginx.com part = part->next; 5459743Smax.romanov@nginx.com if (part == NULL) { 5460743Smax.romanov@nginx.com return NULL; 5461743Smax.romanov@nginx.com } 5462216Sigor@sysoev.ru } 5463216Sigor@sysoev.ru 5464743Smax.romanov@nginx.com i->part = part; 5465743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 5466743Smax.romanov@nginx.com 5467743Smax.romanov@nginx.com return i->field; 5468743Smax.romanov@nginx.com } 5469743Smax.romanov@nginx.com 5470743Smax.romanov@nginx.com 5471743Smax.romanov@nginx.com static nxt_http_field_t * 5472743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 5473743Smax.romanov@nginx.com { 5474743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 5475743Smax.romanov@nginx.com } 5476743Smax.romanov@nginx.com 5477743Smax.romanov@nginx.com 5478743Smax.romanov@nginx.com static nxt_http_field_t * 5479743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 5480743Smax.romanov@nginx.com { 5481743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 5482743Smax.romanov@nginx.com 5483743Smax.romanov@nginx.com end += i->part->nelts; 5484743Smax.romanov@nginx.com i->field++; 5485743Smax.romanov@nginx.com 5486743Smax.romanov@nginx.com if (i->field < end) { 5487743Smax.romanov@nginx.com return i->field; 5488216Sigor@sysoev.ru } 5489216Sigor@sysoev.ru 5490743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 5491216Sigor@sysoev.ru } 5492216Sigor@sysoev.ru 5493216Sigor@sysoev.ru 5494743Smax.romanov@nginx.com static nxt_buf_t * 54951007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, 54961547Smax.romanov@nginx.com nxt_app_t *app, const nxt_str_t *prefix) 5497216Sigor@sysoev.ru { 54981007Salexander.borisov@nginx.com void *target_pos, *query_pos; 54991007Salexander.borisov@nginx.com u_char *pos, *end, *p, c; 55001007Salexander.borisov@nginx.com size_t fields_count, req_size, size, free_size; 55011007Salexander.borisov@nginx.com size_t copy_size; 55021007Salexander.borisov@nginx.com nxt_off_t content_length; 55031007Salexander.borisov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 55041007Salexander.borisov@nginx.com nxt_http_field_t *field, *dup; 55051007Salexander.borisov@nginx.com nxt_unit_field_t *dst_field; 55061007Salexander.borisov@nginx.com nxt_fields_iter_t iter, dup_iter; 55071007Salexander.borisov@nginx.com nxt_unit_request_t *req; 5508216Sigor@sysoev.ru 5509743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 55101007Salexander.borisov@nginx.com + r->method->length + 1 55111007Salexander.borisov@nginx.com + r->version.length + 1 55121007Salexander.borisov@nginx.com + r->remote->length + 1 55131007Salexander.borisov@nginx.com + r->local->length + 1 55141007Salexander.borisov@nginx.com + r->server_name.length + 1 55151007Salexander.borisov@nginx.com + r->target.length + 1 55161007Salexander.borisov@nginx.com + (r->path->start != r->target.start ? r->path->length + 1 : 0); 55171007Salexander.borisov@nginx.com 55181007Salexander.borisov@nginx.com content_length = r->content_length_n < 0 ? 0 : r->content_length_n; 5519743Smax.romanov@nginx.com fields_count = 0; 5520743Smax.romanov@nginx.com 55211007Salexander.borisov@nginx.com nxt_list_each(field, r->fields) { 5522743Smax.romanov@nginx.com fields_count++; 5523743Smax.romanov@nginx.com 5524743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 5525743Smax.romanov@nginx.com + field->value_length + 1; 5526743Smax.romanov@nginx.com } nxt_list_loop; 5527743Smax.romanov@nginx.com 5528743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 5529743Smax.romanov@nginx.com 5530743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 5531743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 5532743Smax.romanov@nginx.com (int) req_size); 5533743Smax.romanov@nginx.com 5534743Smax.romanov@nginx.com return NULL; 5535743Smax.romanov@nginx.com } 5536743Smax.romanov@nginx.com 55371547Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, &app->outgoing, 55381007Salexander.borisov@nginx.com nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); 5539743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 5540743Smax.romanov@nginx.com return NULL; 5541743Smax.romanov@nginx.com } 5542743Smax.romanov@nginx.com 5543743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 5544743Smax.romanov@nginx.com out->mem.free += req_size; 5545743Smax.romanov@nginx.com 55461473Svbart@nginx.com req->app_target = r->app_target; 55471473Svbart@nginx.com 55481007Salexander.borisov@nginx.com req->content_length = content_length; 5549743Smax.romanov@nginx.com 5550743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 5551743Smax.romanov@nginx.com 5552743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 5553743Smax.romanov@nginx.com 55541007Salexander.borisov@nginx.com req->method_length = r->method->length; 5555743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 55561007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 5557743Smax.romanov@nginx.com *p++ = '\0'; 5558743Smax.romanov@nginx.com 55591007Salexander.borisov@nginx.com req->version_length = r->version.length; 5560743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 55611007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 5562743Smax.romanov@nginx.com *p++ = '\0'; 5563743Smax.romanov@nginx.com 55641007Salexander.borisov@nginx.com req->remote_length = r->remote->address_length; 5565743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 55661007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), 55671007Salexander.borisov@nginx.com r->remote->address_length); 5568743Smax.romanov@nginx.com *p++ = '\0'; 5569743Smax.romanov@nginx.com 55701007Salexander.borisov@nginx.com req->local_length = r->local->address_length; 5571743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 55721007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); 5573743Smax.romanov@nginx.com *p++ = '\0'; 5574743Smax.romanov@nginx.com 55751011Smax.romanov@nginx.com req->tls = (r->tls != NULL); 55761131Smax.romanov@nginx.com req->websocket_handshake = r->websocket_handshake; 55771011Smax.romanov@nginx.com 55781007Salexander.borisov@nginx.com req->server_name_length = r->server_name.length; 5579967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 55801007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->server_name.start, r->server_name.length); 5581967Svbart@nginx.com *p++ = '\0'; 5582967Svbart@nginx.com 5583743Smax.romanov@nginx.com target_pos = p; 55841007Salexander.borisov@nginx.com req->target_length = (uint32_t) r->target.length; 5585743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 55861007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 5587743Smax.romanov@nginx.com *p++ = '\0'; 5588743Smax.romanov@nginx.com 55891007Salexander.borisov@nginx.com req->path_length = (uint32_t) r->path->length; 55901007Salexander.borisov@nginx.com if (r->path->start == r->target.start) { 5591743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 5592277Sigor@sysoev.ru 5593216Sigor@sysoev.ru } else { 5594743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 55951007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 5596743Smax.romanov@nginx.com *p++ = '\0'; 5597305Smax.romanov@nginx.com } 5598216Sigor@sysoev.ru 55991990Sz.hong@f5.com req->query_length = (uint32_t) r->args->length; 56001990Sz.hong@f5.com if (r->args->start != NULL) { 5601743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 56021007Salexander.borisov@nginx.com r->args->start - r->target.start); 5603743Smax.romanov@nginx.com 5604743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 5605277Sigor@sysoev.ru 5606216Sigor@sysoev.ru } else { 5607743Smax.romanov@nginx.com req->query.offset = 0; 5608216Sigor@sysoev.ru } 5609216Sigor@sysoev.ru 5610743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 5611743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 5612743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 56131733Svbart@nginx.com req->authorization_field = NXT_UNIT_NONE_FIELD; 5614743Smax.romanov@nginx.com 5615743Smax.romanov@nginx.com dst_field = req->fields; 5616743Smax.romanov@nginx.com 56171007Salexander.borisov@nginx.com for (field = nxt_fields_first(r->fields, &iter); 5618743Smax.romanov@nginx.com field != NULL; 5619743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 5620743Smax.romanov@nginx.com { 5621743Smax.romanov@nginx.com if (field->skip) { 5622743Smax.romanov@nginx.com continue; 5623743Smax.romanov@nginx.com } 5624743Smax.romanov@nginx.com 5625743Smax.romanov@nginx.com dst_field->hash = field->hash; 5626743Smax.romanov@nginx.com dst_field->skip = 0; 5627743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 5628743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 5629743Smax.romanov@nginx.com 56301007Salexander.borisov@nginx.com if (field == r->content_length) { 5631743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 5632743Smax.romanov@nginx.com 56331007Salexander.borisov@nginx.com } else if (field == r->content_type) { 5634743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 5635743Smax.romanov@nginx.com 56361007Salexander.borisov@nginx.com } else if (field == r->cookie) { 5637743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 56381733Svbart@nginx.com 56391733Svbart@nginx.com } else if (field == r->authorization) { 56401733Svbart@nginx.com req->authorization_field = dst_field - req->fields; 5641743Smax.romanov@nginx.com } 5642743Smax.romanov@nginx.com 5643743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 5644743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 5645743Smax.romanov@nginx.com (int) field->name_length, field->name, 5646743Smax.romanov@nginx.com (int) field->value_length, field->value); 5647743Smax.romanov@nginx.com 5648743Smax.romanov@nginx.com if (prefix->length != 0) { 5649743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 5650743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 5651743Smax.romanov@nginx.com 5652743Smax.romanov@nginx.com end = field->name + field->name_length; 5653743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 5654743Smax.romanov@nginx.com c = *pos; 5655743Smax.romanov@nginx.com 5656743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 5657743Smax.romanov@nginx.com *p++ = (c & ~0x20); 5658743Smax.romanov@nginx.com continue; 5659743Smax.romanov@nginx.com } 5660743Smax.romanov@nginx.com 5661743Smax.romanov@nginx.com if (c == '-') { 5662743Smax.romanov@nginx.com *p++ = '_'; 5663743Smax.romanov@nginx.com continue; 5664743Smax.romanov@nginx.com } 5665743Smax.romanov@nginx.com 5666743Smax.romanov@nginx.com *p++ = c; 5667743Smax.romanov@nginx.com } 5668743Smax.romanov@nginx.com 5669743Smax.romanov@nginx.com } else { 5670743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 5671743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 5672743Smax.romanov@nginx.com } 5673743Smax.romanov@nginx.com 5674743Smax.romanov@nginx.com *p++ = '\0'; 5675743Smax.romanov@nginx.com 5676743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 5677743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 5678743Smax.romanov@nginx.com 5679743Smax.romanov@nginx.com if (prefix->length != 0) { 5680743Smax.romanov@nginx.com dup_iter = iter; 5681743Smax.romanov@nginx.com 5682743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 5683743Smax.romanov@nginx.com dup != NULL; 5684743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 5685743Smax.romanov@nginx.com { 5686743Smax.romanov@nginx.com if (dup->name_length != field->name_length 5687743Smax.romanov@nginx.com || dup->skip 5688743Smax.romanov@nginx.com || dup->hash != field->hash 5689743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 5690743Smax.romanov@nginx.com { 5691743Smax.romanov@nginx.com continue; 5692743Smax.romanov@nginx.com } 5693743Smax.romanov@nginx.com 5694743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 5695743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 5696743Smax.romanov@nginx.com 5697743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 5698743Smax.romanov@nginx.com 5699743Smax.romanov@nginx.com dup->skip = 1; 5700743Smax.romanov@nginx.com } 5701743Smax.romanov@nginx.com } 5702743Smax.romanov@nginx.com 5703743Smax.romanov@nginx.com *p++ = '\0'; 5704743Smax.romanov@nginx.com 5705743Smax.romanov@nginx.com dst_field++; 5706743Smax.romanov@nginx.com } 5707743Smax.romanov@nginx.com 57081007Salexander.borisov@nginx.com req->fields_count = (uint32_t) (dst_field - req->fields); 5709743Smax.romanov@nginx.com 5710743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 5711743Smax.romanov@nginx.com 5712743Smax.romanov@nginx.com buf = out; 5713743Smax.romanov@nginx.com tail = &buf->next; 5714216Sigor@sysoev.ru 57151007Salexander.borisov@nginx.com for (b = r->body; b != NULL; b = b->next) { 5716743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 5717743Smax.romanov@nginx.com pos = b->mem.pos; 5718743Smax.romanov@nginx.com 5719743Smax.romanov@nginx.com while (size > 0) { 5720743Smax.romanov@nginx.com if (buf == NULL) { 5721743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 5722743Smax.romanov@nginx.com 57231547Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, &app->outgoing, free_size); 5724743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 5725743Smax.romanov@nginx.com while (out != NULL) { 5726743Smax.romanov@nginx.com buf = out->next; 57271269Sigor@sysoev.ru out->next = NULL; 5728743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 5729743Smax.romanov@nginx.com out = buf; 5730743Smax.romanov@nginx.com } 5731743Smax.romanov@nginx.com return NULL; 5732743Smax.romanov@nginx.com } 5733743Smax.romanov@nginx.com 5734743Smax.romanov@nginx.com *tail = buf; 5735743Smax.romanov@nginx.com tail = &buf->next; 5736743Smax.romanov@nginx.com 5737743Smax.romanov@nginx.com } else { 5738743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5739743Smax.romanov@nginx.com if (free_size < size 5740743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 5741743Smax.romanov@nginx.com == NXT_OK) 5742743Smax.romanov@nginx.com { 5743743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5744743Smax.romanov@nginx.com } 5745743Smax.romanov@nginx.com } 5746743Smax.romanov@nginx.com 5747743Smax.romanov@nginx.com if (free_size > 0) { 5748743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 5749743Smax.romanov@nginx.com 5750743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 5751743Smax.romanov@nginx.com 5752743Smax.romanov@nginx.com size -= copy_size; 5753743Smax.romanov@nginx.com pos += copy_size; 5754743Smax.romanov@nginx.com 5755743Smax.romanov@nginx.com if (size == 0) { 5756743Smax.romanov@nginx.com break; 5757743Smax.romanov@nginx.com } 5758743Smax.romanov@nginx.com } 5759743Smax.romanov@nginx.com 5760743Smax.romanov@nginx.com buf = NULL; 5761743Smax.romanov@nginx.com } 5762216Sigor@sysoev.ru } 5763216Sigor@sysoev.ru 5764743Smax.romanov@nginx.com return out; 5765584Salexander.borisov@nginx.com } 5766584Salexander.borisov@nginx.com 5767584Salexander.borisov@nginx.com 576853Sigor@sysoev.ru static void 5769318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 5770318Smax.romanov@nginx.com { 5771615Smax.romanov@nginx.com nxt_timer_t *timer; 57721007Salexander.borisov@nginx.com nxt_http_request_t *r; 57731123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5774318Smax.romanov@nginx.com 5775318Smax.romanov@nginx.com timer = obj; 5776318Smax.romanov@nginx.com 5777318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 5778318Smax.romanov@nginx.com 57791007Salexander.borisov@nginx.com r = nxt_timer_data(timer, nxt_http_request_t, timer); 57801123Smax.romanov@nginx.com req_rpc_data = r->timer_data; 5781615Smax.romanov@nginx.com 57821007Salexander.borisov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 5783615Smax.romanov@nginx.com 57841123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 5785318Smax.romanov@nginx.com } 57861007Salexander.borisov@nginx.com 57871007Salexander.borisov@nginx.com 57881547Smax.romanov@nginx.com static void 57891547Smax.romanov@nginx.com nxt_router_http_request_release_post(nxt_task_t *task, nxt_http_request_t *r) 57901007Salexander.borisov@nginx.com { 57911007Salexander.borisov@nginx.com r->timer.handler = nxt_router_http_request_release; 57921007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 0); 57931007Salexander.borisov@nginx.com } 57941007Salexander.borisov@nginx.com 57951007Salexander.borisov@nginx.com 57961007Salexander.borisov@nginx.com static void 57971007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) 57981007Salexander.borisov@nginx.com { 57991007Salexander.borisov@nginx.com nxt_http_request_t *r; 58001007Salexander.borisov@nginx.com 58011547Smax.romanov@nginx.com nxt_debug(task, "http request pool release"); 58021007Salexander.borisov@nginx.com 58031007Salexander.borisov@nginx.com r = nxt_timer_data(obj, nxt_http_request_t, timer); 58041007Salexander.borisov@nginx.com 58051007Salexander.borisov@nginx.com nxt_mp_release(r->mem_pool); 58061007Salexander.borisov@nginx.com } 58071321Smax.romanov@nginx.com 58081321Smax.romanov@nginx.com 58091321Smax.romanov@nginx.com static void 58101321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 58111321Smax.romanov@nginx.com { 58121321Smax.romanov@nginx.com size_t mi; 58131321Smax.romanov@nginx.com uint32_t i; 58141321Smax.romanov@nginx.com nxt_bool_t ack; 58151321Smax.romanov@nginx.com nxt_process_t *process; 58161321Smax.romanov@nginx.com nxt_free_map_t *m; 58171754Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 58181321Smax.romanov@nginx.com 58191321Smax.romanov@nginx.com nxt_debug(task, "oosm in %PI", msg->port_msg.pid); 58201321Smax.romanov@nginx.com 58211321Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, 58221321Smax.romanov@nginx.com msg->port_msg.pid); 58231321Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 58241321Smax.romanov@nginx.com return; 58251321Smax.romanov@nginx.com } 58261321Smax.romanov@nginx.com 58271321Smax.romanov@nginx.com ack = 0; 58281321Smax.romanov@nginx.com 58291321Smax.romanov@nginx.com /* 58301321Smax.romanov@nginx.com * To mitigate possible racing condition (when OOSM message received 58311321Smax.romanov@nginx.com * after some of the memory was already freed), need to try to find 58321321Smax.romanov@nginx.com * first free segment in shared memory and send ACK if found. 58331321Smax.romanov@nginx.com */ 58341321Smax.romanov@nginx.com 58351321Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 58361321Smax.romanov@nginx.com 58371321Smax.romanov@nginx.com for (i = 0; i < process->incoming.size; i++) { 58381754Smax.romanov@nginx.com mmap_handler = process->incoming.elts[i].mmap_handler; 58391754Smax.romanov@nginx.com 58401754Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 58411754Smax.romanov@nginx.com continue; 58421754Smax.romanov@nginx.com } 58431754Smax.romanov@nginx.com 58441754Smax.romanov@nginx.com m = mmap_handler->hdr->free_map; 58451321Smax.romanov@nginx.com 58461321Smax.romanov@nginx.com for (mi = 0; mi < MAX_FREE_IDX; mi++) { 58471321Smax.romanov@nginx.com if (m[mi] != 0) { 58481321Smax.romanov@nginx.com ack = 1; 58491321Smax.romanov@nginx.com 58501321Smax.romanov@nginx.com nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA", 58511321Smax.romanov@nginx.com i, mi, m[mi]); 58521321Smax.romanov@nginx.com 58531321Smax.romanov@nginx.com break; 58541321Smax.romanov@nginx.com } 58551321Smax.romanov@nginx.com } 58561321Smax.romanov@nginx.com } 58571321Smax.romanov@nginx.com 58581321Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 58591321Smax.romanov@nginx.com 58601321Smax.romanov@nginx.com if (ack) { 58611662Smax.romanov@nginx.com nxt_process_broadcast_shm_ack(task, process); 58621321Smax.romanov@nginx.com } 58631321Smax.romanov@nginx.com } 58641545Smax.romanov@nginx.com 58651545Smax.romanov@nginx.com 58661545Smax.romanov@nginx.com static void 58671546Smax.romanov@nginx.com nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 58681546Smax.romanov@nginx.com { 58691546Smax.romanov@nginx.com nxt_fd_t fd; 58701546Smax.romanov@nginx.com nxt_port_t *port; 58711546Smax.romanov@nginx.com nxt_runtime_t *rt; 58721546Smax.romanov@nginx.com nxt_port_mmaps_t *mmaps; 58731546Smax.romanov@nginx.com nxt_port_msg_get_mmap_t *get_mmap_msg; 58741546Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 58751546Smax.romanov@nginx.com 58761546Smax.romanov@nginx.com rt = task->thread->runtime; 58771546Smax.romanov@nginx.com 58781546Smax.romanov@nginx.com port = nxt_runtime_port_find(rt, msg->port_msg.pid, 58791546Smax.romanov@nginx.com msg->port_msg.reply_port); 58801546Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 58811546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: reply_port %PI:%d not found", 58821546Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 58831546Smax.romanov@nginx.com 58841546Smax.romanov@nginx.com return; 58851546Smax.romanov@nginx.com } 58861546Smax.romanov@nginx.com 58871546Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_used_size(msg->buf) 58881546Smax.romanov@nginx.com < (int) sizeof(nxt_port_msg_get_mmap_t))) 58891546Smax.romanov@nginx.com { 58901546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: message buffer too small (%d)", 58911546Smax.romanov@nginx.com (int) nxt_buf_used_size(msg->buf)); 58921546Smax.romanov@nginx.com 58931546Smax.romanov@nginx.com return; 58941546Smax.romanov@nginx.com } 58951546Smax.romanov@nginx.com 58961546Smax.romanov@nginx.com get_mmap_msg = (nxt_port_msg_get_mmap_t *) msg->buf->mem.pos; 58971546Smax.romanov@nginx.com 58981546Smax.romanov@nginx.com nxt_assert(port->type == NXT_PROCESS_APP); 58991546Smax.romanov@nginx.com 59001547Smax.romanov@nginx.com if (nxt_slow_path(port->app == NULL)) { 59011547Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d", 59021547Smax.romanov@nginx.com port->pid, port->id); 59031547Smax.romanov@nginx.com 59041547Smax.romanov@nginx.com // FIXME 59051547Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 59061547Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 59071547Smax.romanov@nginx.com 59081547Smax.romanov@nginx.com return; 59091547Smax.romanov@nginx.com } 59101547Smax.romanov@nginx.com 59111547Smax.romanov@nginx.com mmaps = &port->app->outgoing; 59121546Smax.romanov@nginx.com nxt_thread_mutex_lock(&mmaps->mutex); 59131546Smax.romanov@nginx.com 59141546Smax.romanov@nginx.com if (nxt_slow_path(get_mmap_msg->id >= mmaps->size)) { 59151546Smax.romanov@nginx.com nxt_thread_mutex_unlock(&mmaps->mutex); 59161546Smax.romanov@nginx.com 59171546Smax.romanov@nginx.com nxt_alert(task, "get_mmap_handler: mmap id is too big (%d)", 59181546Smax.romanov@nginx.com (int) get_mmap_msg->id); 59191546Smax.romanov@nginx.com 59201547Smax.romanov@nginx.com // FIXME 59211547Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, 59221547Smax.romanov@nginx.com -1, msg->port_msg.stream, 0, NULL); 59231546Smax.romanov@nginx.com return; 59241546Smax.romanov@nginx.com } 59251546Smax.romanov@nginx.com 59261546Smax.romanov@nginx.com mmap_handler = mmaps->elts[get_mmap_msg->id].mmap_handler; 59271546Smax.romanov@nginx.com 59281546Smax.romanov@nginx.com fd = mmap_handler->fd; 59291546Smax.romanov@nginx.com 59301546Smax.romanov@nginx.com nxt_thread_mutex_unlock(&mmaps->mutex); 59311546Smax.romanov@nginx.com 59321546Smax.romanov@nginx.com nxt_debug(task, "get mmap %PI:%d found", 59331546Smax.romanov@nginx.com msg->port_msg.pid, (int) get_mmap_msg->id); 59341546Smax.romanov@nginx.com 59351546Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL); 59361546Smax.romanov@nginx.com } 59371546Smax.romanov@nginx.com 59381546Smax.romanov@nginx.com 59391546Smax.romanov@nginx.com static void 59401545Smax.romanov@nginx.com nxt_router_get_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 59411545Smax.romanov@nginx.com { 59421545Smax.romanov@nginx.com nxt_port_t *port, *reply_port; 59431545Smax.romanov@nginx.com nxt_runtime_t *rt; 59441545Smax.romanov@nginx.com nxt_port_msg_get_port_t *get_port_msg; 59451545Smax.romanov@nginx.com 59461545Smax.romanov@nginx.com rt = task->thread->runtime; 59471545Smax.romanov@nginx.com 59481545Smax.romanov@nginx.com reply_port = nxt_runtime_port_find(rt, msg->port_msg.pid, 59491545Smax.romanov@nginx.com msg->port_msg.reply_port); 59501545Smax.romanov@nginx.com if (nxt_slow_path(reply_port == NULL)) { 59511545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: reply_port %PI:%d not found", 59521545Smax.romanov@nginx.com msg->port_msg.pid, msg->port_msg.reply_port); 59531545Smax.romanov@nginx.com 59541545Smax.romanov@nginx.com return; 59551545Smax.romanov@nginx.com } 59561545Smax.romanov@nginx.com 59571545Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_used_size(msg->buf) 59581545Smax.romanov@nginx.com < (int) sizeof(nxt_port_msg_get_port_t))) 59591545Smax.romanov@nginx.com { 59601545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: message buffer too small (%d)", 59611545Smax.romanov@nginx.com (int) nxt_buf_used_size(msg->buf)); 59621545Smax.romanov@nginx.com 59631545Smax.romanov@nginx.com return; 59641545Smax.romanov@nginx.com } 59651545Smax.romanov@nginx.com 59661545Smax.romanov@nginx.com get_port_msg = (nxt_port_msg_get_port_t *) msg->buf->mem.pos; 59671545Smax.romanov@nginx.com 59681545Smax.romanov@nginx.com port = nxt_runtime_port_find(rt, get_port_msg->pid, get_port_msg->id); 59691545Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 59701545Smax.romanov@nginx.com nxt_alert(task, "get_port_handler: port %PI:%d not found", 59711545Smax.romanov@nginx.com get_port_msg->pid, get_port_msg->id); 59721545Smax.romanov@nginx.com 59731545Smax.romanov@nginx.com return; 59741545Smax.romanov@nginx.com } 59751545Smax.romanov@nginx.com 59761545Smax.romanov@nginx.com nxt_debug(task, "get port %PI:%d found", get_port_msg->pid, 59771545Smax.romanov@nginx.com get_port_msg->id); 59781545Smax.romanov@nginx.com 59791545Smax.romanov@nginx.com (void) nxt_port_send_port(task, reply_port, port, msg->port_msg.stream); 59801545Smax.romanov@nginx.com } 5981