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> 1820Sigor@sysoev.ru 19115Sigor@sysoev.ru typedef struct { 20318Smax.romanov@nginx.com nxt_str_t type; 21507Smax.romanov@nginx.com uint32_t processes; 22507Smax.romanov@nginx.com uint32_t max_processes; 23507Smax.romanov@nginx.com uint32_t spare_processes; 24318Smax.romanov@nginx.com nxt_msec_t timeout; 25427Smax.romanov@nginx.com nxt_msec_t res_timeout; 26507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 27318Smax.romanov@nginx.com uint32_t requests; 28318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 29507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 301473Svbart@nginx.com nxt_conf_value_t *targets_value; 31133Sigor@sysoev.ru } nxt_router_app_conf_t; 32133Sigor@sysoev.ru 33133Sigor@sysoev.ru 34133Sigor@sysoev.ru typedef struct { 35964Sigor@sysoev.ru nxt_str_t pass; 36964Sigor@sysoev.ru nxt_str_t application; 37115Sigor@sysoev.ru } nxt_router_listener_conf_t; 38115Sigor@sysoev.ru 39115Sigor@sysoev.ru 40774Svbart@nginx.com #if (NXT_TLS) 41774Svbart@nginx.com 42774Svbart@nginx.com typedef struct { 43774Svbart@nginx.com nxt_str_t name; 44774Svbart@nginx.com nxt_socket_conf_t *conf; 45774Svbart@nginx.com 46774Svbart@nginx.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 47774Svbart@nginx.com } nxt_router_tlssock_t; 48774Svbart@nginx.com 49774Svbart@nginx.com #endif 50774Svbart@nginx.com 51774Svbart@nginx.com 52198Sigor@sysoev.ru typedef struct { 53198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 54198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 55198Sigor@sysoev.ru } nxt_socket_rpc_t; 56198Sigor@sysoev.ru 57198Sigor@sysoev.ru 58507Smax.romanov@nginx.com typedef struct { 59507Smax.romanov@nginx.com nxt_app_t *app; 60507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 61507Smax.romanov@nginx.com } nxt_app_rpc_t; 62507Smax.romanov@nginx.com 63507Smax.romanov@nginx.com 64427Smax.romanov@nginx.com struct nxt_port_select_state_s { 651123Smax.romanov@nginx.com nxt_app_t *app; 661123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 671123Smax.romanov@nginx.com 681123Smax.romanov@nginx.com nxt_port_t *failed_port; 691123Smax.romanov@nginx.com int failed_port_use_delta; 701123Smax.romanov@nginx.com 711123Smax.romanov@nginx.com uint8_t start_process; /* 1 bit */ 721123Smax.romanov@nginx.com nxt_request_app_link_t *shared_ra; 731123Smax.romanov@nginx.com nxt_port_t *port; 74427Smax.romanov@nginx.com }; 75427Smax.romanov@nginx.com 76427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t; 77427Smax.romanov@nginx.com 78*1488St.nateldemoura@f5.com static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, 79*1488St.nateldemoura@f5.com nxt_mp_t *mp); 80*1488St.nateldemoura@f5.com static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data); 81662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 82662Smax.romanov@nginx.com nxt_port_t *controller_port); 83662Smax.romanov@nginx.com 84427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task, 85427Smax.romanov@nginx.com nxt_port_select_state_t *state); 86427Smax.romanov@nginx.com 87427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task, 88427Smax.romanov@nginx.com nxt_port_select_state_t *state); 89427Smax.romanov@nginx.com 90507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 911123Smax.romanov@nginx.com static void nxt_request_app_link_update_peer(nxt_task_t *task, 921123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 931123Smax.romanov@nginx.com 94343Smax.romanov@nginx.com 95425Smax.romanov@nginx.com nxt_inline void 961123Smax.romanov@nginx.com nxt_request_app_link_inc_use(nxt_request_app_link_t *req_app_link) 97425Smax.romanov@nginx.com { 981123Smax.romanov@nginx.com nxt_atomic_fetch_add(&req_app_link->use_count, 1); 99425Smax.romanov@nginx.com } 100425Smax.romanov@nginx.com 101425Smax.romanov@nginx.com nxt_inline void 1021294Smax.romanov@nginx.com nxt_request_app_link_chk_use(nxt_request_app_link_t *req_app_link, int i) 103425Smax.romanov@nginx.com { 104538Svbart@nginx.com #if (NXT_DEBUG) 105425Smax.romanov@nginx.com int c; 106425Smax.romanov@nginx.com 1071294Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&req_app_link->use_count, i); 1081294Smax.romanov@nginx.com 1091294Smax.romanov@nginx.com nxt_assert((c + i) > 0); 110538Svbart@nginx.com #else 1111294Smax.romanov@nginx.com (void) nxt_atomic_fetch_add(&req_app_link->use_count, i); 112538Svbart@nginx.com #endif 113425Smax.romanov@nginx.com } 114425Smax.romanov@nginx.com 1151123Smax.romanov@nginx.com static void nxt_request_app_link_use(nxt_task_t *task, 1161123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, int i); 117425Smax.romanov@nginx.com 118139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 119198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 120198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 121139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 122139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 123139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 124139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 125193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 12653Sigor@sysoev.ru 127115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 128115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 1291183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 1301183Svbart@nginx.com nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); 131133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 132198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 133198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 134198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 135198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 136198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 137198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 138774Svbart@nginx.com #if (NXT_TLS) 139774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task, 140774Svbart@nginx.com nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls); 141774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task, 142774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 143774Svbart@nginx.com #endif 144507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 145507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 146507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 147507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 148507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 149507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 150359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 151359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 152359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 153359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 15453Sigor@sysoev.ru 15553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 15653Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 15753Sigor@sysoev.ru const nxt_event_interface_t *interface); 158115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 159115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 160115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 161115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 162115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 163115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 164154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 165154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 166154Sigor@sysoev.ru nxt_work_handler_t handler); 167313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 168313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 169139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 170139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 17153Sigor@sysoev.ru 17253Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 17353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17453Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 17553Sigor@sysoev.ru nxt_event_engine_t *engine); 176343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 177133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17853Sigor@sysoev.ru 179315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 180315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 181315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 182315Sigor@sysoev.ru nxt_work_t *jobs); 18353Sigor@sysoev.ru 18453Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 18553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 18653Sigor@sysoev.ru void *data); 18753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 18853Sigor@sysoev.ru void *data); 18953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 19053Sigor@sysoev.ru void *data); 191313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 192313Sigor@sysoev.ru void *data); 19353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 19453Sigor@sysoev.ru void *data); 19553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 19653Sigor@sysoev.ru void *data); 197359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 198359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 19953Sigor@sysoev.ru 200630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 201630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 202630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 203630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 204630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 205630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 206630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 207630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 208630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 209630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 210630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 211630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 212651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 213651Svbart@nginx.com void *data); 214631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 215631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 216631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 217631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 218630Svbart@nginx.com 219343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 220343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 221343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 222343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 223343Smax.romanov@nginx.com 224753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 2251123Smax.romanov@nginx.com 226343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2271123Smax.romanov@nginx.com nxt_apr_action_t action); 228427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 2291123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 230141Smax.romanov@nginx.com 231425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 2321123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 2331007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 2341007Salexander.borisov@nginx.com nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix); 235510Salexander.borisov@nginx.com 236318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 237507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 238507Smax.romanov@nginx.com void *data); 239507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 240507Smax.romanov@nginx.com void *data); 241753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 242507Smax.romanov@nginx.com void *data); 243753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 244431Sigor@sysoev.ru 245431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 246431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 247141Smax.romanov@nginx.com 248753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 249753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 250753Smax.romanov@nginx.com 2511007Salexander.borisov@nginx.com static nxt_int_t nxt_router_http_request_done(nxt_task_t *task, 2521007Salexander.borisov@nginx.com nxt_http_request_t *r); 2531007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 2541007Salexander.borisov@nginx.com void *data); 2551321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 2561007Salexander.borisov@nginx.com 2571149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2581131Smax.romanov@nginx.com 259119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 26020Sigor@sysoev.ru 261743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 262743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 263743Smax.romanov@nginx.com 264743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 265804Svbart@nginx.com &empty_prefix, 266743Smax.romanov@nginx.com &http_prefix, 267743Smax.romanov@nginx.com &http_prefix, 268743Smax.romanov@nginx.com &http_prefix, 269743Smax.romanov@nginx.com &http_prefix, 270977Smax.romanov@gmail.com &empty_prefix, 271216Sigor@sysoev.ru }; 272216Sigor@sysoev.ru 273216Sigor@sysoev.ru 274*1488St.nateldemoura@f5.com static const nxt_port_handlers_t nxt_router_process_port_handlers = { 275*1488St.nateldemoura@f5.com .quit = nxt_signal_quit_handler, 276662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 277662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 278662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 279662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 280662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 281662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 282662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 283662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2841321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 285662Smax.romanov@nginx.com }; 286662Smax.romanov@nginx.com 287662Smax.romanov@nginx.com 288*1488St.nateldemoura@f5.com const nxt_process_init_t nxt_router_process = { 289*1488St.nateldemoura@f5.com .name = "router", 290*1488St.nateldemoura@f5.com .type = NXT_PROCESS_ROUTER, 291*1488St.nateldemoura@f5.com .prefork = nxt_router_prefork, 292*1488St.nateldemoura@f5.com .restart = 1, 293*1488St.nateldemoura@f5.com .setup = nxt_process_core_setup, 294*1488St.nateldemoura@f5.com .start = nxt_router_start, 295*1488St.nateldemoura@f5.com .port_handlers = &nxt_router_process_port_handlers, 296*1488St.nateldemoura@f5.com .signals = nxt_process_signals, 297*1488St.nateldemoura@f5.com }; 298*1488St.nateldemoura@f5.com 299*1488St.nateldemoura@f5.com 300*1488St.nateldemoura@f5.com static nxt_int_t 301*1488St.nateldemoura@f5.com nxt_router_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp) 302*1488St.nateldemoura@f5.com { 303*1488St.nateldemoura@f5.com nxt_runtime_stop_app_processes(task, task->thread->runtime); 304*1488St.nateldemoura@f5.com 305*1488St.nateldemoura@f5.com return NXT_OK; 306*1488St.nateldemoura@f5.com } 307*1488St.nateldemoura@f5.com 308*1488St.nateldemoura@f5.com 309*1488St.nateldemoura@f5.com static nxt_int_t 310*1488St.nateldemoura@f5.com nxt_router_start(nxt_task_t *task, nxt_process_data_t *data) 31120Sigor@sysoev.ru { 312141Smax.romanov@nginx.com nxt_int_t ret; 313662Smax.romanov@nginx.com nxt_port_t *controller_port; 314141Smax.romanov@nginx.com nxt_router_t *router; 315141Smax.romanov@nginx.com nxt_runtime_t *rt; 316141Smax.romanov@nginx.com 317141Smax.romanov@nginx.com rt = task->thread->runtime; 31853Sigor@sysoev.ru 319*1488St.nateldemoura@f5.com nxt_log(task, NXT_LOG_INFO, "router started"); 320*1488St.nateldemoura@f5.com 321771Sigor@sysoev.ru #if (NXT_TLS) 322771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 323771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 324771Sigor@sysoev.ru return NXT_ERROR; 325771Sigor@sysoev.ru } 326771Sigor@sysoev.ru 327771Sigor@sysoev.ru ret = rt->tls->library_init(task); 328771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 329771Sigor@sysoev.ru return ret; 330771Sigor@sysoev.ru } 331771Sigor@sysoev.ru #endif 332771Sigor@sysoev.ru 3331459Smax.romanov@nginx.com ret = nxt_http_init(task); 33488Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 33588Smax.romanov@nginx.com return ret; 33688Smax.romanov@nginx.com } 33788Smax.romanov@nginx.com 33853Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 33953Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 34053Sigor@sysoev.ru return NXT_ERROR; 34153Sigor@sysoev.ru } 34253Sigor@sysoev.ru 34353Sigor@sysoev.ru nxt_queue_init(&router->engines); 34453Sigor@sysoev.ru nxt_queue_init(&router->sockets); 345133Sigor@sysoev.ru nxt_queue_init(&router->apps); 34653Sigor@sysoev.ru 347119Smax.romanov@nginx.com nxt_router = router; 348119Smax.romanov@nginx.com 349662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 350662Smax.romanov@nginx.com if (controller_port != NULL) { 351662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 352662Smax.romanov@nginx.com } 353662Smax.romanov@nginx.com 354115Sigor@sysoev.ru return NXT_OK; 355115Sigor@sysoev.ru } 356115Sigor@sysoev.ru 357115Sigor@sysoev.ru 358343Smax.romanov@nginx.com static void 359662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 360662Smax.romanov@nginx.com { 361662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 362662Smax.romanov@nginx.com -1, 0, 0, NULL); 363662Smax.romanov@nginx.com } 364662Smax.romanov@nginx.com 365662Smax.romanov@nginx.com 366662Smax.romanov@nginx.com static void 367507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 368507Smax.romanov@nginx.com void *data) 369167Smax.romanov@nginx.com { 370343Smax.romanov@nginx.com size_t size; 371343Smax.romanov@nginx.com uint32_t stream; 372430Sigor@sysoev.ru nxt_mp_t *mp; 373648Svbart@nginx.com nxt_int_t ret; 374343Smax.romanov@nginx.com nxt_app_t *app; 375343Smax.romanov@nginx.com nxt_buf_t *b; 376343Smax.romanov@nginx.com nxt_port_t *main_port; 377343Smax.romanov@nginx.com nxt_runtime_t *rt; 378343Smax.romanov@nginx.com 379343Smax.romanov@nginx.com app = data; 380167Smax.romanov@nginx.com 381167Smax.romanov@nginx.com rt = task->thread->runtime; 382240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 383167Smax.romanov@nginx.com 384507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 385343Smax.romanov@nginx.com 386343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 387343Smax.romanov@nginx.com 388343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 389343Smax.romanov@nginx.com 390343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 391343Smax.romanov@nginx.com goto failed; 392167Smax.romanov@nginx.com } 393167Smax.romanov@nginx.com 394343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 395343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 396343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 397343Smax.romanov@nginx.com 398753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 399753Smax.romanov@nginx.com 400343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 401343Smax.romanov@nginx.com nxt_router_app_port_ready, 402343Smax.romanov@nginx.com nxt_router_app_port_error, 403753Smax.romanov@nginx.com -1, app->joint); 404343Smax.romanov@nginx.com 405343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 406753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 407753Smax.romanov@nginx.com 408343Smax.romanov@nginx.com goto failed; 409343Smax.romanov@nginx.com } 410343Smax.romanov@nginx.com 411*1488St.nateldemoura@f5.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS, 412*1488St.nateldemoura@f5.com -1, stream, port->id, b); 413648Svbart@nginx.com 414648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 415648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 416753Smax.romanov@nginx.com 417753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 418753Smax.romanov@nginx.com 419648Svbart@nginx.com goto failed; 420648Svbart@nginx.com } 421343Smax.romanov@nginx.com 422753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 423753Smax.romanov@nginx.com 424343Smax.romanov@nginx.com return; 425343Smax.romanov@nginx.com 426343Smax.romanov@nginx.com failed: 427343Smax.romanov@nginx.com 428648Svbart@nginx.com if (b != NULL) { 429648Svbart@nginx.com mp = b->data; 430648Svbart@nginx.com nxt_mp_free(mp, b); 431648Svbart@nginx.com nxt_mp_release(mp); 432648Svbart@nginx.com } 433648Svbart@nginx.com 434343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 435343Smax.romanov@nginx.com 436507Smax.romanov@nginx.com app->pending_processes--; 437343Smax.romanov@nginx.com 438343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 439343Smax.romanov@nginx.com 440343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 441167Smax.romanov@nginx.com } 442167Smax.romanov@nginx.com 443167Smax.romanov@nginx.com 444753Smax.romanov@nginx.com static void 445753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 446753Smax.romanov@nginx.com { 447753Smax.romanov@nginx.com app_joint->use_count += i; 448753Smax.romanov@nginx.com 449753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 450753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 451753Smax.romanov@nginx.com 452753Smax.romanov@nginx.com nxt_free(app_joint); 453753Smax.romanov@nginx.com } 454753Smax.romanov@nginx.com } 455753Smax.romanov@nginx.com 456753Smax.romanov@nginx.com 457343Smax.romanov@nginx.com static nxt_int_t 458507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 459141Smax.romanov@nginx.com { 460343Smax.romanov@nginx.com nxt_int_t res; 461343Smax.romanov@nginx.com nxt_port_t *router_port; 462343Smax.romanov@nginx.com nxt_runtime_t *rt; 463343Smax.romanov@nginx.com 464343Smax.romanov@nginx.com rt = task->thread->runtime; 465343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 466343Smax.romanov@nginx.com 467343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 468343Smax.romanov@nginx.com 469507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 470343Smax.romanov@nginx.com app); 471343Smax.romanov@nginx.com 472343Smax.romanov@nginx.com if (res == NXT_OK) { 473343Smax.romanov@nginx.com return res; 474318Smax.romanov@nginx.com } 475318Smax.romanov@nginx.com 476343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 477343Smax.romanov@nginx.com 478507Smax.romanov@nginx.com app->pending_processes--; 479343Smax.romanov@nginx.com 480343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 481343Smax.romanov@nginx.com 482343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 483343Smax.romanov@nginx.com 484343Smax.romanov@nginx.com return NXT_ERROR; 485318Smax.romanov@nginx.com } 486318Smax.romanov@nginx.com 487318Smax.romanov@nginx.com 488351Smax.romanov@nginx.com nxt_inline void 4891123Smax.romanov@nginx.com nxt_request_app_link_init(nxt_task_t *task, 4901123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, nxt_request_rpc_data_t *req_rpc_data) 491167Smax.romanov@nginx.com { 4921414Smax.romanov@nginx.com nxt_buf_t *body; 493318Smax.romanov@nginx.com nxt_event_engine_t *engine; 494351Smax.romanov@nginx.com 495318Smax.romanov@nginx.com engine = task->thread->engine; 496167Smax.romanov@nginx.com 4971123Smax.romanov@nginx.com nxt_memzero(req_app_link, sizeof(nxt_request_app_link_t)); 4981123Smax.romanov@nginx.com 4991123Smax.romanov@nginx.com req_app_link->stream = req_rpc_data->stream; 5001123Smax.romanov@nginx.com req_app_link->use_count = 1; 5011123Smax.romanov@nginx.com req_app_link->req_rpc_data = req_rpc_data; 5021123Smax.romanov@nginx.com req_rpc_data->req_app_link = req_app_link; 5031123Smax.romanov@nginx.com req_app_link->reply_port = engine->port; 5041123Smax.romanov@nginx.com req_app_link->request = req_rpc_data->request; 5051123Smax.romanov@nginx.com req_app_link->apr_action = NXT_APR_GOT_RESPONSE; 5061123Smax.romanov@nginx.com 5071123Smax.romanov@nginx.com req_app_link->work.handler = NULL; 5081123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 5091123Smax.romanov@nginx.com req_app_link->work.obj = req_app_link; 5101123Smax.romanov@nginx.com req_app_link->work.data = engine; 5111414Smax.romanov@nginx.com 5121414Smax.romanov@nginx.com body = req_rpc_data->request->body; 5131414Smax.romanov@nginx.com 5141414Smax.romanov@nginx.com if (body != NULL && nxt_buf_is_file(body)) { 5151414Smax.romanov@nginx.com req_app_link->body_fd = body->file->fd; 5161414Smax.romanov@nginx.com 5171414Smax.romanov@nginx.com body->file->fd = -1; 5181414Smax.romanov@nginx.com 5191414Smax.romanov@nginx.com } else { 5201414Smax.romanov@nginx.com req_app_link->body_fd = -1; 5211414Smax.romanov@nginx.com } 522351Smax.romanov@nginx.com } 523351Smax.romanov@nginx.com 524351Smax.romanov@nginx.com 5251123Smax.romanov@nginx.com nxt_inline nxt_request_app_link_t * 5261123Smax.romanov@nginx.com nxt_request_app_link_alloc(nxt_task_t *task, 5271123Smax.romanov@nginx.com nxt_request_app_link_t *ra_src, nxt_request_rpc_data_t *req_rpc_data) 528351Smax.romanov@nginx.com { 5291123Smax.romanov@nginx.com nxt_mp_t *mp; 5301123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 5311123Smax.romanov@nginx.com 5321123Smax.romanov@nginx.com if (ra_src != NULL && ra_src->mem_pool != NULL) { 533425Smax.romanov@nginx.com return ra_src; 534425Smax.romanov@nginx.com } 535425Smax.romanov@nginx.com 5361123Smax.romanov@nginx.com mp = req_rpc_data->request->mem_pool; 5371123Smax.romanov@nginx.com 5381123Smax.romanov@nginx.com req_app_link = nxt_mp_alloc(mp, sizeof(nxt_request_app_link_t)); 5391123Smax.romanov@nginx.com 5401123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 5411123Smax.romanov@nginx.com 5421123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 5431123Smax.romanov@nginx.com 5441123Smax.romanov@nginx.com if (ra_src != NULL) { 5451123Smax.romanov@nginx.com ra_src->req_rpc_data = NULL; 5461123Smax.romanov@nginx.com } 547351Smax.romanov@nginx.com 548351Smax.romanov@nginx.com return NULL; 549351Smax.romanov@nginx.com } 550351Smax.romanov@nginx.com 551430Sigor@sysoev.ru nxt_mp_retain(mp); 552430Sigor@sysoev.ru 5531123Smax.romanov@nginx.com nxt_request_app_link_init(task, req_app_link, req_rpc_data); 5541123Smax.romanov@nginx.com 5551414Smax.romanov@nginx.com if (ra_src != NULL) { 5561414Smax.romanov@nginx.com req_app_link->body_fd = ra_src->body_fd; 5571414Smax.romanov@nginx.com } 5581414Smax.romanov@nginx.com 5591123Smax.romanov@nginx.com req_app_link->mem_pool = mp; 5601123Smax.romanov@nginx.com 5611123Smax.romanov@nginx.com return req_app_link; 562167Smax.romanov@nginx.com } 563167Smax.romanov@nginx.com 564167Smax.romanov@nginx.com 565423Smax.romanov@nginx.com nxt_inline nxt_bool_t 566423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 567423Smax.romanov@nginx.com uint32_t stream) 568423Smax.romanov@nginx.com { 569423Smax.romanov@nginx.com nxt_buf_t *b, *next; 570423Smax.romanov@nginx.com nxt_bool_t cancelled; 571423Smax.romanov@nginx.com 572423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 573423Smax.romanov@nginx.com return 0; 574423Smax.romanov@nginx.com } 575423Smax.romanov@nginx.com 576423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 577423Smax.romanov@nginx.com stream); 578423Smax.romanov@nginx.com 579423Smax.romanov@nginx.com if (cancelled) { 580423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 581423Smax.romanov@nginx.com } 582423Smax.romanov@nginx.com 583423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 584423Smax.romanov@nginx.com next = b->next; 5851269Sigor@sysoev.ru b->next = NULL; 586423Smax.romanov@nginx.com 587423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 588423Smax.romanov@nginx.com 589423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 590423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 591423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 592423Smax.romanov@nginx.com } 593423Smax.romanov@nginx.com } 594423Smax.romanov@nginx.com 595423Smax.romanov@nginx.com msg_info->buf = NULL; 596423Smax.romanov@nginx.com 597423Smax.romanov@nginx.com return cancelled; 598423Smax.romanov@nginx.com } 599423Smax.romanov@nginx.com 600423Smax.romanov@nginx.com 601167Smax.romanov@nginx.com static void 6021123Smax.romanov@nginx.com nxt_request_app_link_update_peer_handler(nxt_task_t *task, void *obj, 6031123Smax.romanov@nginx.com void *data) 6041123Smax.romanov@nginx.com { 6051123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 6061123Smax.romanov@nginx.com 6071123Smax.romanov@nginx.com req_app_link = obj; 6081123Smax.romanov@nginx.com 6091123Smax.romanov@nginx.com nxt_request_app_link_update_peer(task, req_app_link); 6101123Smax.romanov@nginx.com 6111123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 6121123Smax.romanov@nginx.com } 613425Smax.romanov@nginx.com 614425Smax.romanov@nginx.com 615425Smax.romanov@nginx.com static void 6161123Smax.romanov@nginx.com nxt_request_app_link_update_peer(nxt_task_t *task, 6171123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 618167Smax.romanov@nginx.com { 6191123Smax.romanov@nginx.com nxt_event_engine_t *engine; 6201123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 6211123Smax.romanov@nginx.com 6221123Smax.romanov@nginx.com engine = req_app_link->work.data; 6231123Smax.romanov@nginx.com 6241123Smax.romanov@nginx.com if (task->thread->engine != engine) { 6251123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 6261123Smax.romanov@nginx.com 6271123Smax.romanov@nginx.com req_app_link->work.handler = nxt_request_app_link_update_peer_handler; 6281123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 6291123Smax.romanov@nginx.com req_app_link->work.next = NULL; 6301123Smax.romanov@nginx.com 6311123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD post update peer to %p", 6321123Smax.romanov@nginx.com req_app_link->stream, engine); 6331123Smax.romanov@nginx.com 6341123Smax.romanov@nginx.com nxt_event_engine_post(engine, &req_app_link->work); 6351123Smax.romanov@nginx.com 6361123Smax.romanov@nginx.com return; 6371123Smax.romanov@nginx.com } 6381123Smax.romanov@nginx.com 6391123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD update peer", 6401123Smax.romanov@nginx.com req_app_link->stream); 6411123Smax.romanov@nginx.com 6421123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 6431123Smax.romanov@nginx.com 6441123Smax.romanov@nginx.com if (req_rpc_data != NULL && req_app_link->app_port != NULL) { 6451123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, 6461123Smax.romanov@nginx.com req_app_link->app_port->pid); 6471123Smax.romanov@nginx.com } 648425Smax.romanov@nginx.com } 649425Smax.romanov@nginx.com 650425Smax.romanov@nginx.com 651425Smax.romanov@nginx.com static void 6521123Smax.romanov@nginx.com nxt_request_app_link_release(nxt_task_t *task, 6531123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 654425Smax.romanov@nginx.com { 655431Sigor@sysoev.ru nxt_mp_t *mp; 6561131Smax.romanov@nginx.com nxt_http_request_t *r; 6571123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 6581123Smax.romanov@nginx.com 6591123Smax.romanov@nginx.com nxt_assert(task->thread->engine == req_app_link->work.data); 6601123Smax.romanov@nginx.com nxt_assert(req_app_link->use_count == 0); 6611123Smax.romanov@nginx.com 6621123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD release", req_app_link->stream); 6631123Smax.romanov@nginx.com 6641123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 6651123Smax.romanov@nginx.com 6661123Smax.romanov@nginx.com if (req_rpc_data != NULL) { 6671123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link->err_code != 0)) { 6681123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 6691123Smax.romanov@nginx.com req_app_link->err_code); 670423Smax.romanov@nginx.com 671423Smax.romanov@nginx.com } else { 6721123Smax.romanov@nginx.com req_rpc_data->app_port = req_app_link->app_port; 6731123Smax.romanov@nginx.com req_rpc_data->apr_action = req_app_link->apr_action; 6741123Smax.romanov@nginx.com req_rpc_data->msg_info = req_app_link->msg_info; 6751123Smax.romanov@nginx.com 6761123Smax.romanov@nginx.com if (req_rpc_data->app->timeout != 0) { 6771131Smax.romanov@nginx.com r = req_rpc_data->request; 6781131Smax.romanov@nginx.com 6791131Smax.romanov@nginx.com r->timer.handler = nxt_router_app_timeout; 6801131Smax.romanov@nginx.com r->timer_data = req_rpc_data; 6811131Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 6821123Smax.romanov@nginx.com req_rpc_data->app->timeout); 683425Smax.romanov@nginx.com } 684425Smax.romanov@nginx.com 6851123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6861123Smax.romanov@nginx.com req_app_link->msg_info.buf = NULL; 687423Smax.romanov@nginx.com } 688343Smax.romanov@nginx.com 6891123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 6901123Smax.romanov@nginx.com req_app_link->req_rpc_data = NULL; 6911123Smax.romanov@nginx.com } 6921123Smax.romanov@nginx.com 6931123Smax.romanov@nginx.com if (req_app_link->app_port != NULL) { 6941123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_app_link->app_port, 6951123Smax.romanov@nginx.com req_app_link->apr_action); 6961123Smax.romanov@nginx.com 6971123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6981123Smax.romanov@nginx.com } 6991123Smax.romanov@nginx.com 7001414Smax.romanov@nginx.com if (req_app_link->body_fd != -1) { 7011414Smax.romanov@nginx.com nxt_fd_close(req_app_link->body_fd); 7021414Smax.romanov@nginx.com 7031414Smax.romanov@nginx.com req_app_link->body_fd = -1; 7041414Smax.romanov@nginx.com } 7051414Smax.romanov@nginx.com 7061123Smax.romanov@nginx.com nxt_router_msg_cancel(task, &req_app_link->msg_info, req_app_link->stream); 7071123Smax.romanov@nginx.com 7081123Smax.romanov@nginx.com mp = req_app_link->mem_pool; 709430Sigor@sysoev.ru 710430Sigor@sysoev.ru if (mp != NULL) { 7111123Smax.romanov@nginx.com nxt_mp_free(mp, req_app_link); 712430Sigor@sysoev.ru nxt_mp_release(mp); 713351Smax.romanov@nginx.com } 714167Smax.romanov@nginx.com } 715167Smax.romanov@nginx.com 716167Smax.romanov@nginx.com 717425Smax.romanov@nginx.com static void 7181123Smax.romanov@nginx.com nxt_request_app_link_release_handler(nxt_task_t *task, void *obj, void *data) 719425Smax.romanov@nginx.com { 7201123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 7211123Smax.romanov@nginx.com 7221123Smax.romanov@nginx.com req_app_link = obj; 7231123Smax.romanov@nginx.com 7241123Smax.romanov@nginx.com nxt_assert(req_app_link->work.data == data); 7251123Smax.romanov@nginx.com 7261123Smax.romanov@nginx.com nxt_atomic_fetch_add(&req_app_link->use_count, -1); 7271123Smax.romanov@nginx.com 7281123Smax.romanov@nginx.com nxt_request_app_link_release(task, req_app_link); 729425Smax.romanov@nginx.com } 730