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; 30133Sigor@sysoev.ru } nxt_router_app_conf_t; 31133Sigor@sysoev.ru 32133Sigor@sysoev.ru 33133Sigor@sysoev.ru typedef struct { 34964Sigor@sysoev.ru nxt_str_t pass; 35964Sigor@sysoev.ru nxt_str_t application; 36115Sigor@sysoev.ru } nxt_router_listener_conf_t; 37115Sigor@sysoev.ru 38115Sigor@sysoev.ru 39774Svbart@nginx.com #if (NXT_TLS) 40774Svbart@nginx.com 41774Svbart@nginx.com typedef struct { 42774Svbart@nginx.com nxt_str_t name; 43774Svbart@nginx.com nxt_socket_conf_t *conf; 44774Svbart@nginx.com 45774Svbart@nginx.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 46774Svbart@nginx.com } nxt_router_tlssock_t; 47774Svbart@nginx.com 48774Svbart@nginx.com #endif 49774Svbart@nginx.com 50774Svbart@nginx.com 51198Sigor@sysoev.ru typedef struct { 52198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 53198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 54198Sigor@sysoev.ru } nxt_socket_rpc_t; 55198Sigor@sysoev.ru 56198Sigor@sysoev.ru 57507Smax.romanov@nginx.com typedef struct { 58507Smax.romanov@nginx.com nxt_app_t *app; 59507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 60507Smax.romanov@nginx.com } nxt_app_rpc_t; 61507Smax.romanov@nginx.com 62507Smax.romanov@nginx.com 63427Smax.romanov@nginx.com struct nxt_port_select_state_s { 641123Smax.romanov@nginx.com nxt_app_t *app; 651123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 661123Smax.romanov@nginx.com 671123Smax.romanov@nginx.com nxt_port_t *failed_port; 681123Smax.romanov@nginx.com int failed_port_use_delta; 691123Smax.romanov@nginx.com 701123Smax.romanov@nginx.com uint8_t start_process; /* 1 bit */ 711123Smax.romanov@nginx.com nxt_request_app_link_t *shared_ra; 721123Smax.romanov@nginx.com nxt_port_t *port; 73427Smax.romanov@nginx.com }; 74427Smax.romanov@nginx.com 75427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t; 76427Smax.romanov@nginx.com 77662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 78662Smax.romanov@nginx.com nxt_port_t *controller_port); 79662Smax.romanov@nginx.com 80427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task, 81427Smax.romanov@nginx.com nxt_port_select_state_t *state); 82427Smax.romanov@nginx.com 83427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task, 84427Smax.romanov@nginx.com nxt_port_select_state_t *state); 85427Smax.romanov@nginx.com 86507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 871123Smax.romanov@nginx.com static void nxt_request_app_link_update_peer(nxt_task_t *task, 881123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 891123Smax.romanov@nginx.com 90343Smax.romanov@nginx.com 91425Smax.romanov@nginx.com nxt_inline void 921123Smax.romanov@nginx.com nxt_request_app_link_inc_use(nxt_request_app_link_t *req_app_link) 93425Smax.romanov@nginx.com { 941123Smax.romanov@nginx.com nxt_atomic_fetch_add(&req_app_link->use_count, 1); 95425Smax.romanov@nginx.com } 96425Smax.romanov@nginx.com 97425Smax.romanov@nginx.com nxt_inline void 981123Smax.romanov@nginx.com nxt_request_app_link_dec_use(nxt_request_app_link_t *req_app_link) 99425Smax.romanov@nginx.com { 100538Svbart@nginx.com #if (NXT_DEBUG) 101425Smax.romanov@nginx.com int c; 102425Smax.romanov@nginx.com 1031123Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&req_app_link->use_count, -1); 104425Smax.romanov@nginx.com 105425Smax.romanov@nginx.com nxt_assert(c > 1); 106538Svbart@nginx.com #else 1071123Smax.romanov@nginx.com (void) nxt_atomic_fetch_add(&req_app_link->use_count, -1); 108538Svbart@nginx.com #endif 109425Smax.romanov@nginx.com } 110425Smax.romanov@nginx.com 1111123Smax.romanov@nginx.com static void nxt_request_app_link_use(nxt_task_t *task, 1121123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, int i); 113425Smax.romanov@nginx.com 114139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 115198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 116198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 117139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 118139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 119139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 120139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 121193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 12253Sigor@sysoev.ru 123115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 124115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 125*1183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 126*1183Svbart@nginx.com nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); 127133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 128198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 129198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 130198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 131198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 132198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 133198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 134774Svbart@nginx.com #if (NXT_TLS) 135774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task, 136774Svbart@nginx.com nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *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); 139774Svbart@nginx.com #endif 140507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 141507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 142507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 143507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 144507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 145507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 146359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 147359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 148359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 149359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 15053Sigor@sysoev.ru 15153Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 15253Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 15353Sigor@sysoev.ru const nxt_event_interface_t *interface); 154115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 155115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 156115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 157115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 158115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 159115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 160154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 161154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 162154Sigor@sysoev.ru nxt_work_handler_t handler); 163313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 164313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 165139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 166139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 16753Sigor@sysoev.ru 16853Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 16953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17053Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 17153Sigor@sysoev.ru nxt_event_engine_t *engine); 172343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 173133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17453Sigor@sysoev.ru 175315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 176315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 177315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 178315Sigor@sysoev.ru nxt_work_t *jobs); 17953Sigor@sysoev.ru 18053Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 18153Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 18253Sigor@sysoev.ru void *data); 18353Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 18453Sigor@sysoev.ru void *data); 18553Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 18653Sigor@sysoev.ru void *data); 187313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 188313Sigor@sysoev.ru void *data); 18953Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 19053Sigor@sysoev.ru void *data); 19153Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 19253Sigor@sysoev.ru void *data); 193359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 194359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 19553Sigor@sysoev.ru 196630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 197630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 198630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 199630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 200630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 201630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 202630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 203630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 204630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 205630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 206630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 207630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 208651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 209651Svbart@nginx.com void *data); 210631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 211631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 212631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 213631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 214630Svbart@nginx.com 215343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 216343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 217343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 218343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 219343Smax.romanov@nginx.com 220753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 2211123Smax.romanov@nginx.com 222343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2231123Smax.romanov@nginx.com nxt_apr_action_t action); 224427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 2251123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 226141Smax.romanov@nginx.com 227425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 2281123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link); 2291007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 2301007Salexander.borisov@nginx.com nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix); 231510Salexander.borisov@nginx.com 232318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 233507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 234507Smax.romanov@nginx.com void *data); 235507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 236507Smax.romanov@nginx.com void *data); 237753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 238507Smax.romanov@nginx.com void *data); 239753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 240431Sigor@sysoev.ru 241431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 242431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 243141Smax.romanov@nginx.com 244753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 245753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 246753Smax.romanov@nginx.com 2471007Salexander.borisov@nginx.com static nxt_int_t nxt_router_http_request_done(nxt_task_t *task, 2481007Salexander.borisov@nginx.com nxt_http_request_t *r); 2491007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 2501007Salexander.borisov@nginx.com void *data); 2511007Salexander.borisov@nginx.com 2521149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2531131Smax.romanov@nginx.com 254119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 25520Sigor@sysoev.ru 256743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 257743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 258743Smax.romanov@nginx.com 259743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 260804Svbart@nginx.com &empty_prefix, 261743Smax.romanov@nginx.com &http_prefix, 262743Smax.romanov@nginx.com &http_prefix, 263743Smax.romanov@nginx.com &http_prefix, 264743Smax.romanov@nginx.com &http_prefix, 265977Smax.romanov@gmail.com &empty_prefix, 266216Sigor@sysoev.ru }; 267216Sigor@sysoev.ru 268216Sigor@sysoev.ru 269662Smax.romanov@nginx.com nxt_port_handlers_t nxt_router_process_port_handlers = { 270662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 271662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 272662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 273662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 274662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 275662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 276662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 277662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 278662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 279662Smax.romanov@nginx.com }; 280662Smax.romanov@nginx.com 281662Smax.romanov@nginx.com 28220Sigor@sysoev.ru nxt_int_t 283141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 28420Sigor@sysoev.ru { 285141Smax.romanov@nginx.com nxt_int_t ret; 286662Smax.romanov@nginx.com nxt_port_t *controller_port; 287141Smax.romanov@nginx.com nxt_router_t *router; 288141Smax.romanov@nginx.com nxt_runtime_t *rt; 289141Smax.romanov@nginx.com 290141Smax.romanov@nginx.com rt = task->thread->runtime; 29153Sigor@sysoev.ru 292771Sigor@sysoev.ru #if (NXT_TLS) 293771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 294771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 295771Sigor@sysoev.ru return NXT_ERROR; 296771Sigor@sysoev.ru } 297771Sigor@sysoev.ru 298771Sigor@sysoev.ru ret = rt->tls->library_init(task); 299771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 300771Sigor@sysoev.ru return ret; 301771Sigor@sysoev.ru } 302771Sigor@sysoev.ru #endif 303771Sigor@sysoev.ru 304431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 30588Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 30688Smax.romanov@nginx.com return ret; 30788Smax.romanov@nginx.com } 30888Smax.romanov@nginx.com 30953Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 31053Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 31153Sigor@sysoev.ru return NXT_ERROR; 31253Sigor@sysoev.ru } 31353Sigor@sysoev.ru 31453Sigor@sysoev.ru nxt_queue_init(&router->engines); 31553Sigor@sysoev.ru nxt_queue_init(&router->sockets); 316133Sigor@sysoev.ru nxt_queue_init(&router->apps); 31753Sigor@sysoev.ru 318119Smax.romanov@nginx.com nxt_router = router; 319119Smax.romanov@nginx.com 320662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 321662Smax.romanov@nginx.com if (controller_port != NULL) { 322662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 323662Smax.romanov@nginx.com } 324662Smax.romanov@nginx.com 325115Sigor@sysoev.ru return NXT_OK; 326115Sigor@sysoev.ru } 327115Sigor@sysoev.ru 328115Sigor@sysoev.ru 329343Smax.romanov@nginx.com static void 330662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 331662Smax.romanov@nginx.com { 332662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 333662Smax.romanov@nginx.com -1, 0, 0, NULL); 334662Smax.romanov@nginx.com } 335662Smax.romanov@nginx.com 336662Smax.romanov@nginx.com 337662Smax.romanov@nginx.com static void 338507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 339507Smax.romanov@nginx.com void *data) 340167Smax.romanov@nginx.com { 341343Smax.romanov@nginx.com size_t size; 342343Smax.romanov@nginx.com uint32_t stream; 343430Sigor@sysoev.ru nxt_mp_t *mp; 344648Svbart@nginx.com nxt_int_t ret; 345343Smax.romanov@nginx.com nxt_app_t *app; 346343Smax.romanov@nginx.com nxt_buf_t *b; 347343Smax.romanov@nginx.com nxt_port_t *main_port; 348343Smax.romanov@nginx.com nxt_runtime_t *rt; 349343Smax.romanov@nginx.com 350343Smax.romanov@nginx.com app = data; 351167Smax.romanov@nginx.com 352167Smax.romanov@nginx.com rt = task->thread->runtime; 353240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 354167Smax.romanov@nginx.com 355507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 356343Smax.romanov@nginx.com 357343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 358343Smax.romanov@nginx.com 359343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 360343Smax.romanov@nginx.com 361343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 362343Smax.romanov@nginx.com goto failed; 363167Smax.romanov@nginx.com } 364167Smax.romanov@nginx.com 365343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 366343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 367343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 368343Smax.romanov@nginx.com 369753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 370753Smax.romanov@nginx.com 371343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 372343Smax.romanov@nginx.com nxt_router_app_port_ready, 373343Smax.romanov@nginx.com nxt_router_app_port_error, 374753Smax.romanov@nginx.com -1, app->joint); 375343Smax.romanov@nginx.com 376343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 377753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 378753Smax.romanov@nginx.com 379343Smax.romanov@nginx.com goto failed; 380343Smax.romanov@nginx.com } 381343Smax.romanov@nginx.com 382648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 383648Svbart@nginx.com stream, port->id, b); 384648Svbart@nginx.com 385648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 386648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 387753Smax.romanov@nginx.com 388753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 389753Smax.romanov@nginx.com 390648Svbart@nginx.com goto failed; 391648Svbart@nginx.com } 392343Smax.romanov@nginx.com 393753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 394753Smax.romanov@nginx.com 395343Smax.romanov@nginx.com return; 396343Smax.romanov@nginx.com 397343Smax.romanov@nginx.com failed: 398343Smax.romanov@nginx.com 399648Svbart@nginx.com if (b != NULL) { 400648Svbart@nginx.com mp = b->data; 401648Svbart@nginx.com nxt_mp_free(mp, b); 402648Svbart@nginx.com nxt_mp_release(mp); 403648Svbart@nginx.com } 404648Svbart@nginx.com 405343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 406343Smax.romanov@nginx.com 407507Smax.romanov@nginx.com app->pending_processes--; 408343Smax.romanov@nginx.com 409343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 410343Smax.romanov@nginx.com 411343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 412167Smax.romanov@nginx.com } 413167Smax.romanov@nginx.com 414167Smax.romanov@nginx.com 415753Smax.romanov@nginx.com static void 416753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 417753Smax.romanov@nginx.com { 418753Smax.romanov@nginx.com app_joint->use_count += i; 419753Smax.romanov@nginx.com 420753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 421753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 422753Smax.romanov@nginx.com 423753Smax.romanov@nginx.com nxt_free(app_joint); 424753Smax.romanov@nginx.com } 425753Smax.romanov@nginx.com } 426753Smax.romanov@nginx.com 427753Smax.romanov@nginx.com 428343Smax.romanov@nginx.com static nxt_int_t 429507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 430141Smax.romanov@nginx.com { 431343Smax.romanov@nginx.com nxt_int_t res; 432343Smax.romanov@nginx.com nxt_port_t *router_port; 433343Smax.romanov@nginx.com nxt_runtime_t *rt; 434343Smax.romanov@nginx.com 435343Smax.romanov@nginx.com rt = task->thread->runtime; 436343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 437343Smax.romanov@nginx.com 438343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 439343Smax.romanov@nginx.com 440507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 441343Smax.romanov@nginx.com app); 442343Smax.romanov@nginx.com 443343Smax.romanov@nginx.com if (res == NXT_OK) { 444343Smax.romanov@nginx.com return res; 445318Smax.romanov@nginx.com } 446318Smax.romanov@nginx.com 447343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 448343Smax.romanov@nginx.com 449507Smax.romanov@nginx.com app->pending_processes--; 450343Smax.romanov@nginx.com 451343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 452343Smax.romanov@nginx.com 453343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 454343Smax.romanov@nginx.com 455343Smax.romanov@nginx.com return NXT_ERROR; 456318Smax.romanov@nginx.com } 457318Smax.romanov@nginx.com 458318Smax.romanov@nginx.com 459351Smax.romanov@nginx.com nxt_inline void 4601123Smax.romanov@nginx.com nxt_request_app_link_init(nxt_task_t *task, 4611123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, nxt_request_rpc_data_t *req_rpc_data) 462167Smax.romanov@nginx.com { 463318Smax.romanov@nginx.com nxt_event_engine_t *engine; 464351Smax.romanov@nginx.com 465318Smax.romanov@nginx.com engine = task->thread->engine; 466167Smax.romanov@nginx.com 4671123Smax.romanov@nginx.com nxt_memzero(req_app_link, sizeof(nxt_request_app_link_t)); 4681123Smax.romanov@nginx.com 4691123Smax.romanov@nginx.com req_app_link->stream = req_rpc_data->stream; 4701123Smax.romanov@nginx.com req_app_link->use_count = 1; 4711123Smax.romanov@nginx.com req_app_link->req_rpc_data = req_rpc_data; 4721123Smax.romanov@nginx.com req_rpc_data->req_app_link = req_app_link; 4731123Smax.romanov@nginx.com req_app_link->reply_port = engine->port; 4741123Smax.romanov@nginx.com req_app_link->request = req_rpc_data->request; 4751123Smax.romanov@nginx.com req_app_link->apr_action = NXT_APR_GOT_RESPONSE; 4761123Smax.romanov@nginx.com 4771123Smax.romanov@nginx.com req_app_link->work.handler = NULL; 4781123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 4791123Smax.romanov@nginx.com req_app_link->work.obj = req_app_link; 4801123Smax.romanov@nginx.com req_app_link->work.data = engine; 481351Smax.romanov@nginx.com } 482351Smax.romanov@nginx.com 483351Smax.romanov@nginx.com 4841123Smax.romanov@nginx.com nxt_inline nxt_request_app_link_t * 4851123Smax.romanov@nginx.com nxt_request_app_link_alloc(nxt_task_t *task, 4861123Smax.romanov@nginx.com nxt_request_app_link_t *ra_src, nxt_request_rpc_data_t *req_rpc_data) 487351Smax.romanov@nginx.com { 4881123Smax.romanov@nginx.com nxt_mp_t *mp; 4891123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 4901123Smax.romanov@nginx.com 4911123Smax.romanov@nginx.com if (ra_src != NULL && ra_src->mem_pool != NULL) { 492425Smax.romanov@nginx.com return ra_src; 493425Smax.romanov@nginx.com } 494425Smax.romanov@nginx.com 4951123Smax.romanov@nginx.com mp = req_rpc_data->request->mem_pool; 4961123Smax.romanov@nginx.com 4971123Smax.romanov@nginx.com req_app_link = nxt_mp_alloc(mp, sizeof(nxt_request_app_link_t)); 4981123Smax.romanov@nginx.com 4991123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 5001123Smax.romanov@nginx.com 5011123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 5021123Smax.romanov@nginx.com 5031123Smax.romanov@nginx.com if (ra_src != NULL) { 5041123Smax.romanov@nginx.com ra_src->req_rpc_data = NULL; 5051123Smax.romanov@nginx.com } 506351Smax.romanov@nginx.com 507351Smax.romanov@nginx.com return NULL; 508351Smax.romanov@nginx.com } 509351Smax.romanov@nginx.com 510430Sigor@sysoev.ru nxt_mp_retain(mp); 511430Sigor@sysoev.ru 5121123Smax.romanov@nginx.com nxt_request_app_link_init(task, req_app_link, req_rpc_data); 5131123Smax.romanov@nginx.com 5141123Smax.romanov@nginx.com req_app_link->mem_pool = mp; 5151123Smax.romanov@nginx.com 5161123Smax.romanov@nginx.com return req_app_link; 517167Smax.romanov@nginx.com } 518167Smax.romanov@nginx.com 519167Smax.romanov@nginx.com 520423Smax.romanov@nginx.com nxt_inline nxt_bool_t 521423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 522423Smax.romanov@nginx.com uint32_t stream) 523423Smax.romanov@nginx.com { 524423Smax.romanov@nginx.com nxt_buf_t *b, *next; 525423Smax.romanov@nginx.com nxt_bool_t cancelled; 526423Smax.romanov@nginx.com 527423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 528423Smax.romanov@nginx.com return 0; 529423Smax.romanov@nginx.com } 530423Smax.romanov@nginx.com 531423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 532423Smax.romanov@nginx.com stream); 533423Smax.romanov@nginx.com 534423Smax.romanov@nginx.com if (cancelled) { 535423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 536423Smax.romanov@nginx.com } 537423Smax.romanov@nginx.com 538423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 539423Smax.romanov@nginx.com next = b->next; 540423Smax.romanov@nginx.com 541423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 542423Smax.romanov@nginx.com 543423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 544423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 545423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 546423Smax.romanov@nginx.com } 547423Smax.romanov@nginx.com } 548423Smax.romanov@nginx.com 549423Smax.romanov@nginx.com msg_info->buf = NULL; 550423Smax.romanov@nginx.com 551423Smax.romanov@nginx.com return cancelled; 552423Smax.romanov@nginx.com } 553423Smax.romanov@nginx.com 554423Smax.romanov@nginx.com 555167Smax.romanov@nginx.com static void 5561123Smax.romanov@nginx.com nxt_request_app_link_update_peer_handler(nxt_task_t *task, void *obj, 5571123Smax.romanov@nginx.com void *data) 5581123Smax.romanov@nginx.com { 5591123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 5601123Smax.romanov@nginx.com 5611123Smax.romanov@nginx.com req_app_link = obj; 5621123Smax.romanov@nginx.com 5631123Smax.romanov@nginx.com nxt_request_app_link_update_peer(task, req_app_link); 5641123Smax.romanov@nginx.com 5651123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 5661123Smax.romanov@nginx.com } 567425Smax.romanov@nginx.com 568425Smax.romanov@nginx.com 569425Smax.romanov@nginx.com static void 5701123Smax.romanov@nginx.com nxt_request_app_link_update_peer(nxt_task_t *task, 5711123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 572167Smax.romanov@nginx.com { 5731123Smax.romanov@nginx.com nxt_event_engine_t *engine; 5741123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5751123Smax.romanov@nginx.com 5761123Smax.romanov@nginx.com engine = req_app_link->work.data; 5771123Smax.romanov@nginx.com 5781123Smax.romanov@nginx.com if (task->thread->engine != engine) { 5791123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 5801123Smax.romanov@nginx.com 5811123Smax.romanov@nginx.com req_app_link->work.handler = nxt_request_app_link_update_peer_handler; 5821123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 5831123Smax.romanov@nginx.com req_app_link->work.next = NULL; 5841123Smax.romanov@nginx.com 5851123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD post update peer to %p", 5861123Smax.romanov@nginx.com req_app_link->stream, engine); 5871123Smax.romanov@nginx.com 5881123Smax.romanov@nginx.com nxt_event_engine_post(engine, &req_app_link->work); 5891123Smax.romanov@nginx.com 5901123Smax.romanov@nginx.com return; 5911123Smax.romanov@nginx.com } 5921123Smax.romanov@nginx.com 5931123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD update peer", 5941123Smax.romanov@nginx.com req_app_link->stream); 5951123Smax.romanov@nginx.com 5961123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 5971123Smax.romanov@nginx.com 5981123Smax.romanov@nginx.com if (req_rpc_data != NULL && req_app_link->app_port != NULL) { 5991123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, 6001123Smax.romanov@nginx.com req_app_link->app_port->pid); 6011123Smax.romanov@nginx.com } 6021123Smax.romanov@nginx.com 6031123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 604425Smax.romanov@nginx.com } 605425Smax.romanov@nginx.com 606425Smax.romanov@nginx.com 607425Smax.romanov@nginx.com static void 6081123Smax.romanov@nginx.com nxt_request_app_link_release(nxt_task_t *task, 6091123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 610425Smax.romanov@nginx.com { 611431Sigor@sysoev.ru nxt_mp_t *mp; 6121131Smax.romanov@nginx.com nxt_http_request_t *r; 6131123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 6141123Smax.romanov@nginx.com 6151123Smax.romanov@nginx.com nxt_assert(task->thread->engine == req_app_link->work.data); 6161123Smax.romanov@nginx.com nxt_assert(req_app_link->use_count == 0); 6171123Smax.romanov@nginx.com 6181123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD release", req_app_link->stream); 6191123Smax.romanov@nginx.com 6201123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 6211123Smax.romanov@nginx.com 6221123Smax.romanov@nginx.com if (req_rpc_data != NULL) { 6231123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link->err_code != 0)) { 6241123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 6251123Smax.romanov@nginx.com req_app_link->err_code); 626423Smax.romanov@nginx.com 627423Smax.romanov@nginx.com } else { 6281123Smax.romanov@nginx.com req_rpc_data->app_port = req_app_link->app_port; 6291123Smax.romanov@nginx.com req_rpc_data->apr_action = req_app_link->apr_action; 6301123Smax.romanov@nginx.com req_rpc_data->msg_info = req_app_link->msg_info; 6311123Smax.romanov@nginx.com 6321123Smax.romanov@nginx.com if (req_rpc_data->app->timeout != 0) { 6331131Smax.romanov@nginx.com r = req_rpc_data->request; 6341131Smax.romanov@nginx.com 6351131Smax.romanov@nginx.com r->timer.handler = nxt_router_app_timeout; 6361131Smax.romanov@nginx.com r->timer_data = req_rpc_data; 6371131Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 6381123Smax.romanov@nginx.com req_rpc_data->app->timeout); 639425Smax.romanov@nginx.com } 640425Smax.romanov@nginx.com 6411123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6421123Smax.romanov@nginx.com req_app_link->msg_info.buf = NULL; 643423Smax.romanov@nginx.com } 644343Smax.romanov@nginx.com 6451123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 6461123Smax.romanov@nginx.com req_app_link->req_rpc_data = NULL; 6471123Smax.romanov@nginx.com } 6481123Smax.romanov@nginx.com 6491123Smax.romanov@nginx.com if (req_app_link->app_port != NULL) { 6501123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_app_link->app_port, 6511123Smax.romanov@nginx.com req_app_link->apr_action); 6521123Smax.romanov@nginx.com 6531123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6541123Smax.romanov@nginx.com } 6551123Smax.romanov@nginx.com 6561123Smax.romanov@nginx.com nxt_router_msg_cancel(task, &req_app_link->msg_info, req_app_link->stream); 6571123Smax.romanov@nginx.com 6581123Smax.romanov@nginx.com mp = req_app_link->mem_pool; 659430Sigor@sysoev.ru 660430Sigor@sysoev.ru if (mp != NULL) { 6611123Smax.romanov@nginx.com nxt_mp_free(mp, req_app_link); 662430Sigor@sysoev.ru nxt_mp_release(mp); 663351Smax.romanov@nginx.com } 664167Smax.romanov@nginx.com } 665167Smax.romanov@nginx.com 666167Smax.romanov@nginx.com 667425Smax.romanov@nginx.com static void 6681123Smax.romanov@nginx.com nxt_request_app_link_release_handler(nxt_task_t *task, void *obj, void *data) 669425Smax.romanov@nginx.com { 6701123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 6711123Smax.romanov@nginx.com 6721123Smax.romanov@nginx.com req_app_link = obj; 6731123Smax.romanov@nginx.com 6741123Smax.romanov@nginx.com nxt_assert(req_app_link->work.data == data); 6751123Smax.romanov@nginx.com 6761123Smax.romanov@nginx.com nxt_atomic_fetch_add(&req_app_link->use_count, -1); 6771123Smax.romanov@nginx.com 6781123Smax.romanov@nginx.com nxt_request_app_link_release(task, req_app_link); 679425Smax.romanov@nginx.com } 680425Smax.romanov@nginx.com 681425Smax.romanov@nginx.com 682425Smax.romanov@nginx.com static void 6831123Smax.romanov@nginx.com nxt_request_app_link_use(nxt_task_t *task, nxt_request_app_link_t *req_app_link, 6841123Smax.romanov@nginx.com int i) 685425Smax.romanov@nginx.com { 686425Smax.romanov@nginx.com int c; 687425Smax.romanov@nginx.com nxt_event_engine_t *engine; 688425Smax.romanov@nginx.com 6891123Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&req_app_link->use_count, i); 690425Smax.romanov@nginx.com 691425Smax.romanov@nginx.com if (i < 0 && c == -i) { 6921123Smax.romanov@nginx.com engine = req_app_link->work.data; 693425Smax.romanov@nginx.com 694425Smax.romanov@nginx.com if (task->thread->engine == engine) { 6951123Smax.romanov@nginx.com nxt_request_app_link_release(task, req_app_link); 696425Smax.romanov@nginx.com 697425Smax.romanov@nginx.com return; 698425Smax.romanov@nginx.com } 699425Smax.romanov@nginx.com 7001123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 7011123Smax.romanov@nginx.com 7021123Smax.romanov@nginx.com req_app_link->work.handler = nxt_request_app_link_release_handler; 7031123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 7041123Smax.romanov@nginx.com req_app_link->work.next = NULL; 7051123Smax.romanov@nginx.com 7061123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD post release to %p", 7071123Smax.romanov@nginx.com req_app_link->stream, engine); 7081123Smax.romanov@nginx.com 7091123Smax.romanov@nginx.com nxt_event_engine_post(engine, &req_app_link->work); 710425Smax.romanov@nginx.com } 711425Smax.romanov@nginx.com } 712425Smax.romanov@nginx.com 713425Smax.romanov@nginx.com 714423Smax.romanov@nginx.com nxt_inline void 7151123Smax.romanov@nginx.com nxt_request_app_link_error(nxt_request_app_link_t *req_app_link, int code, 7161123Smax.romanov@nginx.com const char *str) 717345Smax.romanov@nginx.com { 7181123Smax.romanov@nginx.com req_app_link->app_port = NULL; 7191123Smax.romanov@nginx.com req_app_link->err_code = code; 7201123Smax.romanov@nginx.com req_app_link->err_str = str; 721345Smax.romanov@nginx.com } 722345Smax.romanov@nginx.com 723345Smax.romanov@nginx.com 724427Smax.romanov@nginx.com nxt_inline void 7251123Smax.romanov@nginx.com nxt_request_app_link_pending(nxt_task_t *task, nxt_app_t *app, 7261123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 727427Smax.romanov@nginx.com { 7281123Smax.romanov@nginx.com nxt_queue_insert_tail(&req_app_link->app_port->pending_requests, 7291123Smax.romanov@nginx.com &req_app_link->link_port_pending); 7301123Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &req_app_link->link_app_pending); 7311123Smax.romanov@nginx.com 7321123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 7331123Smax.romanov@nginx.com 7341123Smax.romanov@nginx.com req_app_link->res_time = nxt_thread_monotonic_time(task->thread) 7351123Smax.romanov@nginx.com + app->res_timeout; 7361123Smax.romanov@nginx.com 7371123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD enqueue to pending_requests", 7381123Smax.romanov@nginx.com req_app_link->stream); 739427Smax.romanov@nginx.com } 740427Smax.romanov@nginx.com 741427Smax.romanov@nginx.com 742425Smax.romanov@nginx.com nxt_inline nxt_bool_t 743425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 744425Smax.romanov@nginx.com { 745425Smax.romanov@nginx.com if (lnk->next != NULL) { 746425Smax.romanov@nginx.com nxt_queue_remove(lnk); 747425Smax.romanov@nginx.com 748425Smax.romanov@nginx.com lnk->next = NULL; 749425Smax.romanov@nginx.com 750425Smax.romanov@nginx.com return 1; 751425Smax.romanov@nginx.com } 752425Smax.romanov@nginx.com 753425Smax.romanov@nginx.com return 0; 754425Smax.romanov@nginx.com } 755425Smax.romanov@nginx.com 756425Smax.romanov@nginx.com 757343Smax.romanov@nginx.com nxt_inline void 7581123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task, 7591123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 760343Smax.romanov@nginx.com { 7611123Smax.romanov@nginx.com int ra_use_delta; 7621123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 7631123Smax.romanov@nginx.com 7641123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 7651123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_rpc_data->app_port, 7661123Smax.romanov@nginx.com req_rpc_data->apr_action); 7671123Smax.romanov@nginx.com 7681123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 7691123Smax.romanov@nginx.com } 7701123Smax.romanov@nginx.com 7711123Smax.romanov@nginx.com nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream); 7721123Smax.romanov@nginx.com 7731123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 7741123Smax.romanov@nginx.com if (req_app_link != NULL) { 7751123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 7761123Smax.romanov@nginx.com req_app_link->req_rpc_data = NULL; 777343Smax.romanov@nginx.com 778425Smax.romanov@nginx.com ra_use_delta = 0; 779425Smax.romanov@nginx.com 7801123Smax.romanov@nginx.com nxt_thread_mutex_lock(&req_rpc_data->app->mutex); 7811123Smax.romanov@nginx.com 7821123Smax.romanov@nginx.com if (req_app_link->link_app_requests.next == NULL 7831123Smax.romanov@nginx.com && req_app_link->link_port_pending.next == NULL 7841131Smax.romanov@nginx.com && req_app_link->link_app_pending.next == NULL 7851131Smax.romanov@nginx.com && req_app_link->link_port_websockets.next == NULL) 786425Smax.romanov@nginx.com { 7871123Smax.romanov@nginx.com req_app_link = NULL; 788343Smax.romanov@nginx.com 789343Smax.romanov@nginx.com } else { 7901123Smax.romanov@nginx.com ra_use_delta -= 7911123Smax.romanov@nginx.com nxt_queue_chk_remove(&req_app_link->link_app_requests) 7921131Smax.romanov@nginx.com + nxt_queue_chk_remove(&req_app_link->link_port_pending) 7931131Smax.romanov@nginx.com + nxt_queue_chk_remove(&req_app_link->link_port_websockets); 7941123Smax.romanov@nginx.com 7951123Smax.romanov@nginx.com nxt_queue_chk_remove(&req_app_link->link_app_pending); 796343Smax.romanov@nginx.com } 797343Smax.romanov@nginx.com 7981123Smax.romanov@nginx.com nxt_thread_mutex_unlock(&req_rpc_data->app->mutex); 7991123Smax.romanov@nginx.com 8001123Smax.romanov@nginx.com if (req_app_link != NULL) { 8011123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, ra_use_delta); 802425Smax.romanov@nginx.com } 803343Smax.romanov@nginx.com } 804343Smax.romanov@nginx.com 8051123Smax.romanov@nginx.com if (req_rpc_data->app != NULL) { 8061123Smax.romanov@nginx.com nxt_router_app_use(task, req_rpc_data->app, -1); 8071123Smax.romanov@nginx.com 8081123Smax.romanov@nginx.com req_rpc_data->app = NULL; 8091123Smax.romanov@nginx.com } 8101123Smax.romanov@nginx.com 8111123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 8121123Smax.romanov@nginx.com req_rpc_data->request->timer_data = NULL; 8131123Smax.romanov@nginx.com 8141123Smax.romanov@nginx.com nxt_router_http_request_done(task, req_rpc_data->request); 8151123Smax.romanov@nginx.com 8161131Smax.romanov@nginx.com req_rpc_data->request->req_rpc_data = NULL; 8171123Smax.romanov@nginx.com req_rpc_data->request = NULL; 818346Smax.romanov@nginx.com } 819343Smax.romanov@nginx.com } 820343Smax.romanov@nginx.com 821343Smax.romanov@nginx.com 822141Smax.romanov@nginx.com void 823141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 824141Smax.romanov@nginx.com { 825141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 826141Smax.romanov@nginx.com 827670Smax.romanov@nginx.com if (msg->u.new_port != NULL 828670Smax.romanov@nginx.com && msg->u.new_port->type == NXT_PROCESS_CONTROLLER) 829670Smax.romanov@nginx.com { 830662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 831662Smax.romanov@nginx.com } 832662Smax.romanov@nginx.com 833192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 834141Smax.romanov@nginx.com return; 835141Smax.romanov@nginx.com } 836141Smax.romanov@nginx.com 837426Smax.romanov@nginx.com if (msg->u.new_port == NULL 838426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 839347Smax.romanov@nginx.com { 840192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 841141Smax.romanov@nginx.com } 842192Smax.romanov@nginx.com 843192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 844141Smax.romanov@nginx.com } 845141Smax.romanov@nginx.com 846141Smax.romanov@nginx.com 847139Sigor@sysoev.ru void 848139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 849115Sigor@sysoev.ru { 850198Sigor@sysoev.ru nxt_int_t ret; 851139Sigor@sysoev.ru nxt_buf_t *b; 852139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 853139Sigor@sysoev.ru 854139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 855139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 856139Sigor@sysoev.ru return; 85753Sigor@sysoev.ru } 85853Sigor@sysoev.ru 859494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 860423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 861493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 862423Smax.romanov@nginx.com 863591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 864139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 865139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 866198Sigor@sysoev.ru msg->port_msg.pid, 867198Sigor@sysoev.ru msg->port_msg.reply_port); 868198Sigor@sysoev.ru 869779Smax.romanov@nginx.com if (nxt_slow_path(tmcf->port == NULL)) { 870779Smax.romanov@nginx.com nxt_alert(task, "reply port not found"); 871779Smax.romanov@nginx.com 872779Smax.romanov@nginx.com return; 873779Smax.romanov@nginx.com } 874779Smax.romanov@nginx.com 875779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 876779Smax.romanov@nginx.com 877591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 878591Sigor@sysoev.ru msg->buf, msg->size); 879551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 880551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 881551Smax.romanov@nginx.com 882551Smax.romanov@nginx.com return; 883551Smax.romanov@nginx.com } 884551Smax.romanov@nginx.com 885198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 886198Sigor@sysoev.ru 887198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 888198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 889198Sigor@sysoev.ru 890198Sigor@sysoev.ru } else { 891198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 892139Sigor@sysoev.ru } 89353Sigor@sysoev.ru } 89453Sigor@sysoev.ru 89553Sigor@sysoev.ru 896347Smax.romanov@nginx.com static void 897507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 898507Smax.romanov@nginx.com void *data) 899347Smax.romanov@nginx.com { 900347Smax.romanov@nginx.com union { 901347Smax.romanov@nginx.com nxt_pid_t removed_pid; 902347Smax.romanov@nginx.com void *data; 903347Smax.romanov@nginx.com } u; 904347Smax.romanov@nginx.com 905347Smax.romanov@nginx.com u.data = data; 906347Smax.romanov@nginx.com 907347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 908347Smax.romanov@nginx.com } 909347Smax.romanov@nginx.com 910347Smax.romanov@nginx.com 911192Smax.romanov@nginx.com void 912192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 913192Smax.romanov@nginx.com { 914347Smax.romanov@nginx.com nxt_event_engine_t *engine; 915318Smax.romanov@nginx.com 916192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 917192Smax.romanov@nginx.com 918318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 919318Smax.romanov@nginx.com { 920507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 921347Smax.romanov@nginx.com msg->u.data); 922318Smax.romanov@nginx.com } 923318Smax.romanov@nginx.com nxt_queue_loop; 924318Smax.romanov@nginx.com 9251085Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 9261085Smax.romanov@nginx.com return; 9271085Smax.romanov@nginx.com } 9281085Smax.romanov@nginx.com 929192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 930192Smax.romanov@nginx.com 931192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 932192Smax.romanov@nginx.com } 933192Smax.romanov@nginx.com 934192Smax.romanov@nginx.com 93553Sigor@sysoev.ru static nxt_router_temp_conf_t * 936139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 93753Sigor@sysoev.ru { 93865Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 93953Sigor@sysoev.ru nxt_router_conf_t *rtcf; 94053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 94153Sigor@sysoev.ru 94265Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 94353Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 94453Sigor@sysoev.ru return NULL; 94553Sigor@sysoev.ru } 94653Sigor@sysoev.ru 94765Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 94853Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 94953Sigor@sysoev.ru goto fail; 95053Sigor@sysoev.ru } 95153Sigor@sysoev.ru 95253Sigor@sysoev.ru rtcf->mem_pool = mp; 95353Sigor@sysoev.ru 95465Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 95553Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 95653Sigor@sysoev.ru goto fail; 95753Sigor@sysoev.ru } 95853Sigor@sysoev.ru 95965Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 96053Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 96153Sigor@sysoev.ru goto temp_fail; 96253Sigor@sysoev.ru } 96353Sigor@sysoev.ru 96453Sigor@sysoev.ru tmcf->mem_pool = tmp; 965591Sigor@sysoev.ru tmcf->router_conf = rtcf; 966139Sigor@sysoev.ru tmcf->count = 1; 967139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 96853Sigor@sysoev.ru 96953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 97053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 97153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 97253Sigor@sysoev.ru goto temp_fail; 97353Sigor@sysoev.ru } 97453Sigor@sysoev.ru 97553Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 97653Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 97753Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 97853Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 97953Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 980416Smax.romanov@nginx.com 981774Svbart@nginx.com #if (NXT_TLS) 982774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 983774Svbart@nginx.com #endif 984774Svbart@nginx.com 985133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 986133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 98753Sigor@sysoev.ru 98853Sigor@sysoev.ru return tmcf; 98953Sigor@sysoev.ru 99053Sigor@sysoev.ru temp_fail: 99153Sigor@sysoev.ru 99265Sigor@sysoev.ru nxt_mp_destroy(tmp); 99353Sigor@sysoev.ru 99453Sigor@sysoev.ru fail: 99553Sigor@sysoev.ru 99665Sigor@sysoev.ru nxt_mp_destroy(mp); 99753Sigor@sysoev.ru 99853Sigor@sysoev.ru return NULL; 99953Sigor@sysoev.ru } 100053Sigor@sysoev.ru 100153Sigor@sysoev.ru 1002507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1003507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 1004507Smax.romanov@nginx.com { 1005507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 1006507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 1007507Smax.romanov@nginx.com } 1008507Smax.romanov@nginx.com 1009507Smax.romanov@nginx.com 1010507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1011507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 1012507Smax.romanov@nginx.com { 1013507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 1014507Smax.romanov@nginx.com < app->spare_processes; 1015507Smax.romanov@nginx.com } 1016507Smax.romanov@nginx.com 1017507Smax.romanov@nginx.com 1018198Sigor@sysoev.ru static void 1019198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 1020139Sigor@sysoev.ru { 1021139Sigor@sysoev.ru nxt_int_t ret; 1022507Smax.romanov@nginx.com nxt_app_t *app; 1023139Sigor@sysoev.ru nxt_router_t *router; 1024139Sigor@sysoev.ru nxt_runtime_t *rt; 1025198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1026198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1027630Svbart@nginx.com nxt_router_conf_t *rtcf; 1028198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1029139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1030774Svbart@nginx.com #if (NXT_TLS) 1031774Svbart@nginx.com nxt_router_tlssock_t *tls; 1032774Svbart@nginx.com #endif 1033139Sigor@sysoev.ru 1034198Sigor@sysoev.ru tmcf = obj; 1035198Sigor@sysoev.ru 1036198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 1037198Sigor@sysoev.ru 1038198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 1039198Sigor@sysoev.ru nxt_queue_remove(qlk); 1040198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 1041198Sigor@sysoev.ru 1042198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1043198Sigor@sysoev.ru 1044198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1045198Sigor@sysoev.ru 1046198Sigor@sysoev.ru return; 1047139Sigor@sysoev.ru } 1048139Sigor@sysoev.ru 1049774Svbart@nginx.com #if (NXT_TLS) 1050774Svbart@nginx.com qlk = nxt_queue_first(&tmcf->tls); 1051774Svbart@nginx.com 1052774Svbart@nginx.com if (qlk != nxt_queue_tail(&tmcf->tls)) { 1053774Svbart@nginx.com nxt_queue_remove(qlk); 1054774Svbart@nginx.com 1055774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 1056774Svbart@nginx.com 1057774Svbart@nginx.com nxt_router_tls_rpc_create(task, tmcf, tls); 1058774Svbart@nginx.com return; 1059774Svbart@nginx.com } 1060774Svbart@nginx.com #endif 1061774Svbart@nginx.com 1062507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1063507Smax.romanov@nginx.com 1064507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1065507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1066507Smax.romanov@nginx.com return; 1067507Smax.romanov@nginx.com } 1068507Smax.romanov@nginx.com 1069507Smax.romanov@nginx.com } nxt_queue_loop; 1070507Smax.romanov@nginx.com 1071630Svbart@nginx.com rtcf = tmcf->router_conf; 1072630Svbart@nginx.com 1073630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1074630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1075630Svbart@nginx.com return; 1076630Svbart@nginx.com } 1077630Svbart@nginx.com 1078139Sigor@sysoev.ru rt = task->thread->runtime; 1079139Sigor@sysoev.ru 1080139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1081139Sigor@sysoev.ru 1082630Svbart@nginx.com router = rtcf->router; 1083198Sigor@sysoev.ru 1084139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1085139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1086198Sigor@sysoev.ru goto fail; 1087139Sigor@sysoev.ru } 1088139Sigor@sysoev.ru 1089139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1090139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1091198Sigor@sysoev.ru goto fail; 1092139Sigor@sysoev.ru } 1093139Sigor@sysoev.ru 1094343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1095139Sigor@sysoev.ru 1096315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1097139Sigor@sysoev.ru 1098139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 1099139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 1100139Sigor@sysoev.ru 1101630Svbart@nginx.com router->access_log = rtcf->access_log; 1102630Svbart@nginx.com 1103198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1104198Sigor@sysoev.ru 1105198Sigor@sysoev.ru return; 1106198Sigor@sysoev.ru 1107198Sigor@sysoev.ru fail: 1108198Sigor@sysoev.ru 1109198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1110198Sigor@sysoev.ru 1111198Sigor@sysoev.ru return; 1112139Sigor@sysoev.ru } 1113139Sigor@sysoev.ru 1114139Sigor@sysoev.ru 1115139Sigor@sysoev.ru static void 1116139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1117139Sigor@sysoev.ru { 1118153Sigor@sysoev.ru nxt_joint_job_t *job; 1119153Sigor@sysoev.ru 1120153Sigor@sysoev.ru job = obj; 1121153Sigor@sysoev.ru 1122198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1123139Sigor@sysoev.ru } 1124139Sigor@sysoev.ru 1125139Sigor@sysoev.ru 1126139Sigor@sysoev.ru static void 1127198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1128139Sigor@sysoev.ru { 1129139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 1130139Sigor@sysoev.ru 1131139Sigor@sysoev.ru if (--tmcf->count == 0) { 1132193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 1133139Sigor@sysoev.ru } 1134139Sigor@sysoev.ru } 1135139Sigor@sysoev.ru 1136139Sigor@sysoev.ru 1137139Sigor@sysoev.ru static void 1138139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1139139Sigor@sysoev.ru { 1140507Smax.romanov@nginx.com nxt_app_t *app; 1141568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1142148Sigor@sysoev.ru nxt_socket_t s; 1143149Sigor@sysoev.ru nxt_router_t *router; 1144148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1145148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1146630Svbart@nginx.com nxt_router_conf_t *rtcf; 1147148Sigor@sysoev.ru 1148564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1149198Sigor@sysoev.ru 1150148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1151148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1152148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1153148Sigor@sysoev.ru { 1154148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1155359Sigor@sysoev.ru s = skcf->listen->socket; 1156148Sigor@sysoev.ru 1157148Sigor@sysoev.ru if (s != -1) { 1158148Sigor@sysoev.ru nxt_socket_close(task, s); 1159148Sigor@sysoev.ru } 1160148Sigor@sysoev.ru 1161359Sigor@sysoev.ru nxt_free(skcf->listen); 1162148Sigor@sysoev.ru } 1163148Sigor@sysoev.ru 1164568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1165568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1166568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1167568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1168568Smax.romanov@nginx.com 1169964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1170964Sigor@sysoev.ru 1171964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 1172964Sigor@sysoev.ru 1173568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1174568Smax.romanov@nginx.com 1175964Sigor@sysoev.ru if (skcf->pass != NULL) { 1176964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 1177568Smax.romanov@nginx.com } 1178568Smax.romanov@nginx.com 1179568Smax.romanov@nginx.com } nxt_queue_loop; 1180568Smax.romanov@nginx.com 1181507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1182507Smax.romanov@nginx.com 1183753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1184507Smax.romanov@nginx.com 1185507Smax.romanov@nginx.com } nxt_queue_loop; 1186507Smax.romanov@nginx.com 1187630Svbart@nginx.com router = rtcf->router; 1188149Sigor@sysoev.ru 1189149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1190149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1191149Sigor@sysoev.ru 1192416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1193416Smax.romanov@nginx.com 1194148Sigor@sysoev.ru // TODO: new engines and threads 1195148Sigor@sysoev.ru 1196630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1197630Svbart@nginx.com 1198630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1199139Sigor@sysoev.ru 1200193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1201139Sigor@sysoev.ru } 1202139Sigor@sysoev.ru 1203139Sigor@sysoev.ru 1204139Sigor@sysoev.ru static void 1205139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1206193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1207139Sigor@sysoev.ru { 1208193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1209779Smax.romanov@nginx.com 1210779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1211779Smax.romanov@nginx.com 1212779Smax.romanov@nginx.com tmcf->port = NULL; 1213139Sigor@sysoev.ru } 1214139Sigor@sysoev.ru 1215139Sigor@sysoev.ru 1216115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1217115Sigor@sysoev.ru { 1218133Sigor@sysoev.ru nxt_string("listeners_threads"), 1219115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1220115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1221115Sigor@sysoev.ru }, 1222115Sigor@sysoev.ru }; 1223115Sigor@sysoev.ru 1224115Sigor@sysoev.ru 1225133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1226115Sigor@sysoev.ru { 1227133Sigor@sysoev.ru nxt_string("type"), 1228115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1229133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1230115Sigor@sysoev.ru }, 1231115Sigor@sysoev.ru 1232115Sigor@sysoev.ru { 1233507Smax.romanov@nginx.com nxt_string("limits"), 1234507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1235507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1236133Sigor@sysoev.ru }, 1237318Smax.romanov@nginx.com 1238318Smax.romanov@nginx.com { 1239507Smax.romanov@nginx.com nxt_string("processes"), 1240507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1241507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1242507Smax.romanov@nginx.com }, 1243507Smax.romanov@nginx.com 1244507Smax.romanov@nginx.com { 1245507Smax.romanov@nginx.com nxt_string("processes"), 1246318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1247507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1248318Smax.romanov@nginx.com }, 1249318Smax.romanov@nginx.com }; 1250318Smax.romanov@nginx.com 1251318Smax.romanov@nginx.com 1252318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1253318Smax.romanov@nginx.com { 1254318Smax.romanov@nginx.com nxt_string("timeout"), 1255318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1256318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1257318Smax.romanov@nginx.com }, 1258318Smax.romanov@nginx.com 1259318Smax.romanov@nginx.com { 1260427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1261427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1262427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1263427Smax.romanov@nginx.com }, 1264427Smax.romanov@nginx.com 1265427Smax.romanov@nginx.com { 1266318Smax.romanov@nginx.com nxt_string("requests"), 1267318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1268318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1269318Smax.romanov@nginx.com }, 1270133Sigor@sysoev.ru }; 1271133Sigor@sysoev.ru 1272133Sigor@sysoev.ru 1273507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1274507Smax.romanov@nginx.com { 1275507Smax.romanov@nginx.com nxt_string("spare"), 1276507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1277507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1278507Smax.romanov@nginx.com }, 1279507Smax.romanov@nginx.com 1280507Smax.romanov@nginx.com { 1281507Smax.romanov@nginx.com nxt_string("max"), 1282507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1283507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1284507Smax.romanov@nginx.com }, 1285507Smax.romanov@nginx.com 1286507Smax.romanov@nginx.com { 1287507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1288507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1289507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1290507Smax.romanov@nginx.com }, 1291507Smax.romanov@nginx.com }; 1292507Smax.romanov@nginx.com 1293507Smax.romanov@nginx.com 1294133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1295133Sigor@sysoev.ru { 1296964Sigor@sysoev.ru nxt_string("pass"), 1297964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1298964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1299964Sigor@sysoev.ru }, 1300964Sigor@sysoev.ru 1301964Sigor@sysoev.ru { 1302133Sigor@sysoev.ru nxt_string("application"), 1303964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1304133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1305115Sigor@sysoev.ru }, 1306115Sigor@sysoev.ru }; 1307115Sigor@sysoev.ru 1308115Sigor@sysoev.ru 1309115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1310115Sigor@sysoev.ru { 1311115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1312115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1313115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1314115Sigor@sysoev.ru }, 1315115Sigor@sysoev.ru 1316115Sigor@sysoev.ru { 1317115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1318115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1319115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1320115Sigor@sysoev.ru }, 1321115Sigor@sysoev.ru 1322115Sigor@sysoev.ru { 1323206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1324206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1325206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1326206Smax.romanov@nginx.com }, 1327206Smax.romanov@nginx.com 1328206Smax.romanov@nginx.com { 1329206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1330206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1331206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1332206Smax.romanov@nginx.com }, 1333206Smax.romanov@nginx.com 1334206Smax.romanov@nginx.com { 1335206Smax.romanov@nginx.com nxt_string("max_body_size"), 1336206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1337206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1338206Smax.romanov@nginx.com }, 1339206Smax.romanov@nginx.com 1340206Smax.romanov@nginx.com { 1341431Sigor@sysoev.ru nxt_string("idle_timeout"), 1342431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1343431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1344431Sigor@sysoev.ru }, 1345431Sigor@sysoev.ru 1346431Sigor@sysoev.ru { 1347115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1348115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1349115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1350115Sigor@sysoev.ru }, 1351206Smax.romanov@nginx.com 1352206Smax.romanov@nginx.com { 1353206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1354206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1355206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1356206Smax.romanov@nginx.com }, 1357431Sigor@sysoev.ru 1358431Sigor@sysoev.ru { 1359431Sigor@sysoev.ru nxt_string("send_timeout"), 1360431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1361431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1362431Sigor@sysoev.ru }, 1363115Sigor@sysoev.ru }; 1364115Sigor@sysoev.ru 1365115Sigor@sysoev.ru 13661131Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_websocket_conf[] = { 13671131Smax.romanov@nginx.com { 13681131Smax.romanov@nginx.com nxt_string("max_frame_size"), 13691131Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 13701131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, max_frame_size), 13711131Smax.romanov@nginx.com }, 13721131Smax.romanov@nginx.com 13731131Smax.romanov@nginx.com { 13741131Smax.romanov@nginx.com nxt_string("read_timeout"), 13751131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 13761131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, read_timeout), 13771131Smax.romanov@nginx.com }, 13781131Smax.romanov@nginx.com 13791131Smax.romanov@nginx.com { 13801131Smax.romanov@nginx.com nxt_string("keepalive_interval"), 13811131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 13821131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, keepalive_interval), 13831131Smax.romanov@nginx.com }, 13841131Smax.romanov@nginx.com 13851131Smax.romanov@nginx.com }; 13861131Smax.romanov@nginx.com 13871131Smax.romanov@nginx.com 138853Sigor@sysoev.ru static nxt_int_t 1389115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1390115Sigor@sysoev.ru u_char *start, u_char *end) 139153Sigor@sysoev.ru { 1392133Sigor@sysoev.ru u_char *p; 1393133Sigor@sysoev.ru size_t size; 1394115Sigor@sysoev.ru nxt_mp_t *mp; 1395115Sigor@sysoev.ru uint32_t next; 1396115Sigor@sysoev.ru nxt_int_t ret; 1397630Svbart@nginx.com nxt_str_t name, path; 1398133Sigor@sysoev.ru nxt_app_t *app, *prev; 1399359Sigor@sysoev.ru nxt_router_t *router; 1400753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 14011131Smax.romanov@nginx.com nxt_conf_value_t *conf, *http, *value, *websocket; 1402133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1403133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1404*1183Svbart@nginx.com nxt_conf_value_t *routes_conf, *static_conf; 1405115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1406964Sigor@sysoev.ru nxt_http_routes_t *routes; 1407507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1408216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1409133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1410630Svbart@nginx.com nxt_router_access_log_t *access_log; 1411115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1412774Svbart@nginx.com #if (NXT_TLS) 1413774Svbart@nginx.com nxt_router_tlssock_t *tls; 1414774Svbart@nginx.com #endif 1415115Sigor@sysoev.ru 1416716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1417133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1418115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1419964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1420630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1421774Svbart@nginx.com #if (NXT_TLS) 1422774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1423774Svbart@nginx.com #endif 1424*1183Svbart@nginx.com static nxt_str_t static_path = nxt_string("/settings/http/static"); 14251131Smax.romanov@nginx.com static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); 1426115Sigor@sysoev.ru 1427208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1428115Sigor@sysoev.ru if (conf == NULL) { 1429564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1430115Sigor@sysoev.ru return NXT_ERROR; 1431115Sigor@sysoev.ru } 1432115Sigor@sysoev.ru 1433591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1434213Svbart@nginx.com 1435213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1436591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1437115Sigor@sysoev.ru if (ret != NXT_OK) { 1438564Svbart@nginx.com nxt_alert(task, "root map error"); 1439115Sigor@sysoev.ru return NXT_ERROR; 1440115Sigor@sysoev.ru } 1441115Sigor@sysoev.ru 1442591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1443591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1444117Sigor@sysoev.ru } 1445117Sigor@sysoev.ru 1446*1183Svbart@nginx.com static_conf = nxt_conf_get_path(conf, &static_path); 1447*1183Svbart@nginx.com 1448*1183Svbart@nginx.com ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf); 1449*1183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1450*1183Svbart@nginx.com return NXT_ERROR; 1451*1183Svbart@nginx.com } 1452*1183Svbart@nginx.com 14531115Svbart@nginx.com router = tmcf->router_conf->router; 14541115Svbart@nginx.com 1455133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 14561115Svbart@nginx.com 14571115Svbart@nginx.com if (applications != NULL) { 14581115Svbart@nginx.com next = 0; 14591115Svbart@nginx.com 14601115Svbart@nginx.com for ( ;; ) { 14611115Svbart@nginx.com application = nxt_conf_next_object_member(applications, &name, &next); 14621115Svbart@nginx.com if (application == NULL) { 14631115Svbart@nginx.com break; 14641115Svbart@nginx.com } 14651115Svbart@nginx.com 14661115Svbart@nginx.com nxt_debug(task, "application \"%V\"", &name); 14671115Svbart@nginx.com 14681115Svbart@nginx.com size = nxt_conf_json_length(application, NULL); 14691115Svbart@nginx.com 14701115Svbart@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 14711115Svbart@nginx.com if (app == NULL) { 14721115Svbart@nginx.com goto fail; 14731115Svbart@nginx.com } 14741115Svbart@nginx.com 14751115Svbart@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 14761115Svbart@nginx.com 14771115Svbart@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 14781115Svbart@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) 14791115Svbart@nginx.com + name.length); 14801115Svbart@nginx.com 14811115Svbart@nginx.com p = nxt_conf_json_print(app->conf.start, application, NULL); 14821115Svbart@nginx.com app->conf.length = p - app->conf.start; 14831115Svbart@nginx.com 14841115Svbart@nginx.com nxt_assert(app->conf.length <= size); 14851115Svbart@nginx.com 14861115Svbart@nginx.com nxt_debug(task, "application conf \"%V\"", &app->conf); 14871115Svbart@nginx.com 14881115Svbart@nginx.com prev = nxt_router_app_find(&router->apps, &name); 14891115Svbart@nginx.com 14901115Svbart@nginx.com if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 14911115Svbart@nginx.com nxt_free(app); 14921115Svbart@nginx.com 14931115Svbart@nginx.com nxt_queue_remove(&prev->link); 14941115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->previous, &prev->link); 14951115Svbart@nginx.com continue; 14961115Svbart@nginx.com } 14971115Svbart@nginx.com 14981115Svbart@nginx.com apcf.processes = 1; 14991115Svbart@nginx.com apcf.max_processes = 1; 15001115Svbart@nginx.com apcf.spare_processes = 0; 15011115Svbart@nginx.com apcf.timeout = 0; 15021115Svbart@nginx.com apcf.res_timeout = 1000; 15031115Svbart@nginx.com apcf.idle_timeout = 15000; 15041115Svbart@nginx.com apcf.requests = 0; 15051115Svbart@nginx.com apcf.limits_value = NULL; 15061115Svbart@nginx.com apcf.processes_value = NULL; 15071115Svbart@nginx.com 15081115Svbart@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 15091115Svbart@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1510318Smax.romanov@nginx.com goto app_fail; 1511318Smax.romanov@nginx.com } 1512318Smax.romanov@nginx.com 15131115Svbart@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 15141115Svbart@nginx.com 15151115Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 15161115Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1517318Smax.romanov@nginx.com if (ret != NXT_OK) { 15181115Svbart@nginx.com nxt_alert(task, "application map error"); 1519318Smax.romanov@nginx.com goto app_fail; 1520318Smax.romanov@nginx.com } 15211115Svbart@nginx.com 15221115Svbart@nginx.com if (apcf.limits_value != NULL) { 15231115Svbart@nginx.com 15241115Svbart@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 15251115Svbart@nginx.com nxt_alert(task, "application limits is not object"); 15261115Svbart@nginx.com goto app_fail; 15271115Svbart@nginx.com } 15281115Svbart@nginx.com 15291115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 15301115Svbart@nginx.com nxt_router_app_limits_conf, 15311115Svbart@nginx.com nxt_nitems(nxt_router_app_limits_conf), 15321115Svbart@nginx.com &apcf); 15331115Svbart@nginx.com if (ret != NXT_OK) { 15341115Svbart@nginx.com nxt_alert(task, "application limits map error"); 15351115Svbart@nginx.com goto app_fail; 15361115Svbart@nginx.com } 15371115Svbart@nginx.com } 15381115Svbart@nginx.com 15391115Svbart@nginx.com if (apcf.processes_value != NULL 15401115Svbart@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 15411115Svbart@nginx.com { 15421115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 15431115Svbart@nginx.com nxt_router_app_processes_conf, 15441115Svbart@nginx.com nxt_nitems(nxt_router_app_processes_conf), 15451115Svbart@nginx.com &apcf); 15461115Svbart@nginx.com if (ret != NXT_OK) { 15471115Svbart@nginx.com nxt_alert(task, "application processes map error"); 15481115Svbart@nginx.com goto app_fail; 15491115Svbart@nginx.com } 15501115Svbart@nginx.com 15511115Svbart@nginx.com } else { 15521115Svbart@nginx.com apcf.max_processes = apcf.processes; 15531115Svbart@nginx.com apcf.spare_processes = apcf.processes; 15541115Svbart@nginx.com } 15551115Svbart@nginx.com 15561115Svbart@nginx.com nxt_debug(task, "application type: %V", &apcf.type); 15571115Svbart@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 15581115Svbart@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 15591115Svbart@nginx.com nxt_debug(task, "application reschedule timeout: %M", 15601115Svbart@nginx.com apcf.res_timeout); 15611115Svbart@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 15621115Svbart@nginx.com 15631115Svbart@nginx.com lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 15641115Svbart@nginx.com 15651115Svbart@nginx.com if (lang == NULL) { 15661115Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1567507Smax.romanov@nginx.com goto app_fail; 1568507Smax.romanov@nginx.com } 1569507Smax.romanov@nginx.com 15701115Svbart@nginx.com nxt_debug(task, "application language module: \"%s\"", lang->file); 15711115Svbart@nginx.com 15721115Svbart@nginx.com ret = nxt_thread_mutex_create(&app->mutex); 15731115Svbart@nginx.com if (ret != NXT_OK) { 15741115Svbart@nginx.com goto app_fail; 15751115Svbart@nginx.com } 15761115Svbart@nginx.com 15771115Svbart@nginx.com nxt_queue_init(&app->ports); 15781115Svbart@nginx.com nxt_queue_init(&app->spare_ports); 15791115Svbart@nginx.com nxt_queue_init(&app->idle_ports); 15801115Svbart@nginx.com nxt_queue_init(&app->requests); 15811115Svbart@nginx.com nxt_queue_init(&app->pending); 15821115Svbart@nginx.com 15831115Svbart@nginx.com app->name.length = name.length; 15841115Svbart@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 15851115Svbart@nginx.com 15861115Svbart@nginx.com app->type = lang->type; 15871115Svbart@nginx.com app->max_processes = apcf.max_processes; 15881115Svbart@nginx.com app->spare_processes = apcf.spare_processes; 15891115Svbart@nginx.com app->max_pending_processes = apcf.spare_processes 15901115Svbart@nginx.com ? apcf.spare_processes : 1; 15911115Svbart@nginx.com app->timeout = apcf.timeout; 15921115Svbart@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 15931115Svbart@nginx.com app->idle_timeout = apcf.idle_timeout; 15941115Svbart@nginx.com app->max_pending_responses = 2; 15951115Svbart@nginx.com app->max_requests = apcf.requests; 15961115Svbart@nginx.com 15971115Svbart@nginx.com engine = task->thread->engine; 15981115Svbart@nginx.com 15991115Svbart@nginx.com app->engine = engine; 16001115Svbart@nginx.com 16011115Svbart@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 16021115Svbart@nginx.com app->adjust_idle_work.task = &engine->task; 16031115Svbart@nginx.com app->adjust_idle_work.obj = app; 16041115Svbart@nginx.com 16051115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->apps, &app->link); 16061115Svbart@nginx.com 16071115Svbart@nginx.com nxt_router_app_use(task, app, 1); 16081115Svbart@nginx.com 16091115Svbart@nginx.com app->joint = app_joint; 16101115Svbart@nginx.com 16111115Svbart@nginx.com app_joint->use_count = 1; 16121115Svbart@nginx.com app_joint->app = app; 16131115Svbart@nginx.com 16141115Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 16151115Svbart@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 16161115Svbart@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 16171115Svbart@nginx.com app_joint->idle_timer.task = &engine->task; 16181115Svbart@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 16191115Svbart@nginx.com 16201115Svbart@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 16211115Svbart@nginx.com app_joint->free_app_work.task = &engine->task; 16221115Svbart@nginx.com app_joint->free_app_work.obj = app_joint; 1623133Sigor@sysoev.ru } 1624133Sigor@sysoev.ru } 1625133Sigor@sysoev.ru 1626964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1627964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1628964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1629964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1630964Sigor@sysoev.ru return NXT_ERROR; 1631964Sigor@sysoev.ru } 1632964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1633964Sigor@sysoev.ru } 1634964Sigor@sysoev.ru 1635133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1636133Sigor@sysoev.ru #if 0 1637133Sigor@sysoev.ru if (http == NULL) { 1638564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1639133Sigor@sysoev.ru return NXT_ERROR; 1640133Sigor@sysoev.ru } 1641133Sigor@sysoev.ru #endif 1642133Sigor@sysoev.ru 16431131Smax.romanov@nginx.com websocket = nxt_conf_get_path(conf, &websocket_path); 16441131Smax.romanov@nginx.com 1645133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 16461115Svbart@nginx.com 16471115Svbart@nginx.com if (listeners != NULL) { 16481115Svbart@nginx.com next = 0; 16491115Svbart@nginx.com 16501115Svbart@nginx.com for ( ;; ) { 16511115Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &name, &next); 16521115Svbart@nginx.com if (listener == NULL) { 16531115Svbart@nginx.com break; 16541115Svbart@nginx.com } 16551115Svbart@nginx.com 16561115Svbart@nginx.com skcf = nxt_router_socket_conf(task, tmcf, &name); 16571115Svbart@nginx.com if (skcf == NULL) { 16581115Svbart@nginx.com goto fail; 16591115Svbart@nginx.com } 16601115Svbart@nginx.com 16611115Svbart@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 16621115Svbart@nginx.com 16631115Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 16641115Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), 16651115Svbart@nginx.com &lscf); 1666133Sigor@sysoev.ru if (ret != NXT_OK) { 16671115Svbart@nginx.com nxt_alert(task, "listener map error"); 1668133Sigor@sysoev.ru goto fail; 1669133Sigor@sysoev.ru } 16701115Svbart@nginx.com 16711115Svbart@nginx.com nxt_debug(task, "application: %V", &lscf.application); 16721115Svbart@nginx.com 16731115Svbart@nginx.com // STUB, default values if http block is not defined. 16741115Svbart@nginx.com skcf->header_buffer_size = 2048; 16751115Svbart@nginx.com skcf->large_header_buffer_size = 8192; 16761115Svbart@nginx.com skcf->large_header_buffers = 4; 16771115Svbart@nginx.com skcf->body_buffer_size = 16 * 1024; 16781115Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 16791115Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 16801115Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 16811115Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 16821115Svbart@nginx.com skcf->send_timeout = 30 * 1000; 16831115Svbart@nginx.com 16841131Smax.romanov@nginx.com skcf->websocket_conf.max_frame_size = 1024 * 1024; 16851131Smax.romanov@nginx.com skcf->websocket_conf.read_timeout = 60 * 1000; 16861131Smax.romanov@nginx.com skcf->websocket_conf.keepalive_interval = 30 * 1000; 16871131Smax.romanov@nginx.com 16881115Svbart@nginx.com if (http != NULL) { 16891115Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 16901115Svbart@nginx.com nxt_nitems(nxt_router_http_conf), 16911115Svbart@nginx.com skcf); 16921115Svbart@nginx.com if (ret != NXT_OK) { 16931115Svbart@nginx.com nxt_alert(task, "http map error"); 16941115Svbart@nginx.com goto fail; 16951115Svbart@nginx.com } 16961115Svbart@nginx.com } 1697115Sigor@sysoev.ru 16981131Smax.romanov@nginx.com if (websocket != NULL) { 16991131Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, websocket, 17001131Smax.romanov@nginx.com nxt_router_websocket_conf, 17011131Smax.romanov@nginx.com nxt_nitems(nxt_router_websocket_conf), 17021131Smax.romanov@nginx.com &skcf->websocket_conf); 17031131Smax.romanov@nginx.com if (ret != NXT_OK) { 17041131Smax.romanov@nginx.com nxt_alert(task, "websocket map error"); 17051131Smax.romanov@nginx.com goto fail; 17061131Smax.romanov@nginx.com } 17071131Smax.romanov@nginx.com } 17081131Smax.romanov@nginx.com 1709774Svbart@nginx.com #if (NXT_TLS) 17101115Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 17111115Svbart@nginx.com 17121115Svbart@nginx.com if (value != NULL) { 17131115Svbart@nginx.com nxt_conf_get_string(value, &name); 17141115Svbart@nginx.com 17151115Svbart@nginx.com tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); 17161115Svbart@nginx.com if (nxt_slow_path(tls == NULL)) { 17171115Svbart@nginx.com goto fail; 17181115Svbart@nginx.com } 17191115Svbart@nginx.com 17201115Svbart@nginx.com tls->name = name; 17211115Svbart@nginx.com tls->conf = skcf; 17221115Svbart@nginx.com 17231115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 1724774Svbart@nginx.com } 1725774Svbart@nginx.com #endif 1726774Svbart@nginx.com 17271115Svbart@nginx.com skcf->listen->handler = nxt_http_conn_init; 17281115Svbart@nginx.com skcf->router_conf = tmcf->router_conf; 17291115Svbart@nginx.com skcf->router_conf->count++; 17301115Svbart@nginx.com 17311115Svbart@nginx.com if (lscf.pass.length != 0) { 17321115Svbart@nginx.com skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass); 17331115Svbart@nginx.com 17341115Svbart@nginx.com /* COMPATIBILITY: listener application. */ 17351115Svbart@nginx.com } else if (lscf.application.length > 0) { 17361115Svbart@nginx.com skcf->pass = nxt_http_pass_application(task, tmcf, 17371115Svbart@nginx.com &lscf.application); 17381115Svbart@nginx.com } 1739770Smax.romanov@nginx.com } 1740115Sigor@sysoev.ru } 174153Sigor@sysoev.ru 1742630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1743630Svbart@nginx.com 1744630Svbart@nginx.com if (value != NULL) { 1745630Svbart@nginx.com nxt_conf_get_string(value, &path); 1746630Svbart@nginx.com 1747630Svbart@nginx.com access_log = router->access_log; 1748630Svbart@nginx.com 1749630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1750630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1751630Svbart@nginx.com access_log->count++; 1752630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1753630Svbart@nginx.com 1754630Svbart@nginx.com } else { 1755630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1756630Svbart@nginx.com + path.length); 1757630Svbart@nginx.com if (access_log == NULL) { 1758630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1759630Svbart@nginx.com goto fail; 1760630Svbart@nginx.com } 1761630Svbart@nginx.com 1762630Svbart@nginx.com access_log->fd = -1; 1763630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1764630Svbart@nginx.com access_log->count = 1; 1765630Svbart@nginx.com 1766630Svbart@nginx.com access_log->path.length = path.length; 1767630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1768630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1769630Svbart@nginx.com 1770630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1771630Svbart@nginx.com } 1772630Svbart@nginx.com 1773630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1774630Svbart@nginx.com } 1775630Svbart@nginx.com 1776964Sigor@sysoev.ru nxt_http_routes_resolve(task, tmcf); 1777964Sigor@sysoev.ru 1778359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1779359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1780198Sigor@sysoev.ru 178153Sigor@sysoev.ru return NXT_OK; 1782133Sigor@sysoev.ru 1783133Sigor@sysoev.ru app_fail: 1784133Sigor@sysoev.ru 1785133Sigor@sysoev.ru nxt_free(app); 1786133Sigor@sysoev.ru 1787133Sigor@sysoev.ru fail: 1788133Sigor@sysoev.ru 1789141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1790141Smax.romanov@nginx.com 1791141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1792133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1793133Sigor@sysoev.ru nxt_free(app); 1794141Smax.romanov@nginx.com 1795141Smax.romanov@nginx.com } nxt_queue_loop; 1796133Sigor@sysoev.ru 1797133Sigor@sysoev.ru return NXT_ERROR; 1798133Sigor@sysoev.ru } 1799133Sigor@sysoev.ru 1800133Sigor@sysoev.ru 1801*1183Svbart@nginx.com static nxt_int_t 1802*1183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, 1803*1183Svbart@nginx.com nxt_conf_value_t *conf) 1804*1183Svbart@nginx.com { 1805*1183Svbart@nginx.com uint32_t next, i; 1806*1183Svbart@nginx.com nxt_mp_t *mp; 1807*1183Svbart@nginx.com nxt_str_t *type, extension, str; 1808*1183Svbart@nginx.com nxt_int_t ret; 1809*1183Svbart@nginx.com nxt_uint_t exts; 1810*1183Svbart@nginx.com nxt_conf_value_t *mtypes_conf, *ext_conf, *value; 1811*1183Svbart@nginx.com 1812*1183Svbart@nginx.com static nxt_str_t mtypes_path = nxt_string("/mime_types"); 1813*1183Svbart@nginx.com 1814*1183Svbart@nginx.com mp = rtcf->mem_pool; 1815*1183Svbart@nginx.com 1816*1183Svbart@nginx.com ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash); 1817*1183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1818*1183Svbart@nginx.com return NXT_ERROR; 1819*1183Svbart@nginx.com } 1820*1183Svbart@nginx.com 1821*1183Svbart@nginx.com if (conf == NULL) { 1822*1183Svbart@nginx.com return NXT_OK; 1823*1183Svbart@nginx.com } 1824*1183Svbart@nginx.com 1825*1183Svbart@nginx.com mtypes_conf = nxt_conf_get_path(conf, &mtypes_path); 1826*1183Svbart@nginx.com 1827*1183Svbart@nginx.com if (mtypes_conf != NULL) { 1828*1183Svbart@nginx.com next = 0; 1829*1183Svbart@nginx.com 1830*1183Svbart@nginx.com for ( ;; ) { 1831*1183Svbart@nginx.com ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next); 1832*1183Svbart@nginx.com 1833*1183Svbart@nginx.com if (ext_conf == NULL) { 1834*1183Svbart@nginx.com break; 1835*1183Svbart@nginx.com } 1836*1183Svbart@nginx.com 1837*1183Svbart@nginx.com type = nxt_str_dup(mp, NULL, &str); 1838*1183Svbart@nginx.com if (nxt_slow_path(type == NULL)) { 1839*1183Svbart@nginx.com return NXT_ERROR; 1840*1183Svbart@nginx.com } 1841*1183Svbart@nginx.com 1842*1183Svbart@nginx.com if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) { 1843*1183Svbart@nginx.com nxt_conf_get_string(ext_conf, &str); 1844*1183Svbart@nginx.com 1845*1183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 1846*1183Svbart@nginx.com return NXT_ERROR; 1847*1183Svbart@nginx.com } 1848*1183Svbart@nginx.com 1849*1183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 1850*1183Svbart@nginx.com &extension, type); 1851*1183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1852*1183Svbart@nginx.com return NXT_ERROR; 1853*1183Svbart@nginx.com } 1854*1183Svbart@nginx.com 1855*1183Svbart@nginx.com continue; 1856*1183Svbart@nginx.com } 1857*1183Svbart@nginx.com 1858*1183Svbart@nginx.com exts = nxt_conf_array_elements_count(ext_conf); 1859*1183Svbart@nginx.com 1860*1183Svbart@nginx.com for (i = 0; i < exts; i++) { 1861*1183Svbart@nginx.com value = nxt_conf_get_array_element(ext_conf, i); 1862*1183Svbart@nginx.com 1863*1183Svbart@nginx.com nxt_conf_get_string(value, &str); 1864*1183Svbart@nginx.com 1865*1183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 1866*1183Svbart@nginx.com return NXT_ERROR; 1867*1183Svbart@nginx.com } 1868*1183Svbart@nginx.com 1869*1183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 1870*1183Svbart@nginx.com &extension, type); 1871*1183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1872*1183Svbart@nginx.com return NXT_ERROR; 1873*1183Svbart@nginx.com } 1874*1183Svbart@nginx.com } 1875*1183Svbart@nginx.com } 1876*1183Svbart@nginx.com } 1877*1183Svbart@nginx.com 1878*1183Svbart@nginx.com return NXT_OK; 1879*1183Svbart@nginx.com } 1880*1183Svbart@nginx.com 1881*1183Svbart@nginx.com 1882133Sigor@sysoev.ru static nxt_app_t * 1883133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1884133Sigor@sysoev.ru { 1885141Smax.romanov@nginx.com nxt_app_t *app; 1886141Smax.romanov@nginx.com 1887141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1888133Sigor@sysoev.ru 1889133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1890133Sigor@sysoev.ru return app; 1891133Sigor@sysoev.ru } 1892141Smax.romanov@nginx.com 1893141Smax.romanov@nginx.com } nxt_queue_loop; 1894133Sigor@sysoev.ru 1895133Sigor@sysoev.ru return NULL; 1896133Sigor@sysoev.ru } 1897133Sigor@sysoev.ru 1898133Sigor@sysoev.ru 1899964Sigor@sysoev.ru nxt_app_t * 1900133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1901133Sigor@sysoev.ru { 1902133Sigor@sysoev.ru nxt_app_t *app; 1903133Sigor@sysoev.ru 1904133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1905133Sigor@sysoev.ru 1906133Sigor@sysoev.ru if (app == NULL) { 1907134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1908133Sigor@sysoev.ru } 1909133Sigor@sysoev.ru 1910133Sigor@sysoev.ru return app; 191153Sigor@sysoev.ru } 191253Sigor@sysoev.ru 191353Sigor@sysoev.ru 191453Sigor@sysoev.ru static nxt_socket_conf_t * 1915359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1916359Sigor@sysoev.ru nxt_str_t *name) 191753Sigor@sysoev.ru { 1918359Sigor@sysoev.ru size_t size; 1919359Sigor@sysoev.ru nxt_int_t ret; 1920359Sigor@sysoev.ru nxt_bool_t wildcard; 1921359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1922359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1923359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1924359Sigor@sysoev.ru 1925359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1926359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1927564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1928359Sigor@sysoev.ru return NULL; 1929359Sigor@sysoev.ru } 1930359Sigor@sysoev.ru 1931359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1932359Sigor@sysoev.ru 1933359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1934493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1935359Sigor@sysoev.ru 1936591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1937163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 193853Sigor@sysoev.ru return NULL; 193953Sigor@sysoev.ru } 194053Sigor@sysoev.ru 1941359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1942359Sigor@sysoev.ru 1943359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1944359Sigor@sysoev.ru 1945359Sigor@sysoev.ru if (ret != NXT_OK) { 1946359Sigor@sysoev.ru 1947359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1948359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1949359Sigor@sysoev.ru return NULL; 1950359Sigor@sysoev.ru } 1951359Sigor@sysoev.ru 1952359Sigor@sysoev.ru skcf->listen = ls; 1953359Sigor@sysoev.ru 1954359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1955359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1956359Sigor@sysoev.ru 1957359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1958359Sigor@sysoev.ru 1959359Sigor@sysoev.ru ls->socket = -1; 1960359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1961359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1962359Sigor@sysoev.ru ls->read_after_accept = 1; 1963359Sigor@sysoev.ru } 1964359Sigor@sysoev.ru 1965359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1966359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1967359Sigor@sysoev.ru case AF_UNIX: 1968359Sigor@sysoev.ru wildcard = 0; 1969359Sigor@sysoev.ru break; 1970359Sigor@sysoev.ru #endif 1971359Sigor@sysoev.ru #if (NXT_INET6) 1972359Sigor@sysoev.ru case AF_INET6: 1973359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1974359Sigor@sysoev.ru break; 1975359Sigor@sysoev.ru #endif 1976359Sigor@sysoev.ru case AF_INET: 1977359Sigor@sysoev.ru default: 1978359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1979359Sigor@sysoev.ru break; 1980359Sigor@sysoev.ru } 1981359Sigor@sysoev.ru 1982359Sigor@sysoev.ru if (!wildcard) { 1983591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1984359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1985359Sigor@sysoev.ru return NULL; 1986359Sigor@sysoev.ru } 1987359Sigor@sysoev.ru 1988359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1989359Sigor@sysoev.ru } 1990163Smax.romanov@nginx.com 1991163Smax.romanov@nginx.com return skcf; 199253Sigor@sysoev.ru } 199353Sigor@sysoev.ru 199453Sigor@sysoev.ru 1995359Sigor@sysoev.ru static nxt_int_t 1996359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1997359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 199853Sigor@sysoev.ru { 1999359Sigor@sysoev.ru nxt_router_t *router; 2000359Sigor@sysoev.ru nxt_queue_link_t *qlk; 2001359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2002359Sigor@sysoev.ru 2003591Sigor@sysoev.ru router = tmcf->router_conf->router; 2004359Sigor@sysoev.ru 2005359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 2006359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 2007359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 200853Sigor@sysoev.ru { 2009359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2010359Sigor@sysoev.ru 2011359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 2012359Sigor@sysoev.ru nskcf->listen = skcf->listen; 2013359Sigor@sysoev.ru 2014359Sigor@sysoev.ru nxt_queue_remove(qlk); 2015359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 2016359Sigor@sysoev.ru 2017359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 2018359Sigor@sysoev.ru 2019359Sigor@sysoev.ru return NXT_OK; 202053Sigor@sysoev.ru } 202153Sigor@sysoev.ru } 202253Sigor@sysoev.ru 2023359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 2024359Sigor@sysoev.ru 2025359Sigor@sysoev.ru return NXT_DECLINED; 202653Sigor@sysoev.ru } 202753Sigor@sysoev.ru 202853Sigor@sysoev.ru 2029198Sigor@sysoev.ru static void 2030198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 2031198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 2032198Sigor@sysoev.ru { 2033358Sigor@sysoev.ru size_t size; 2034198Sigor@sysoev.ru uint32_t stream; 2035648Svbart@nginx.com nxt_int_t ret; 2036198Sigor@sysoev.ru nxt_buf_t *b; 2037198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 2038198Sigor@sysoev.ru nxt_runtime_t *rt; 2039198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 2040198Sigor@sysoev.ru 2041198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2042198Sigor@sysoev.ru if (rpc == NULL) { 2043198Sigor@sysoev.ru goto fail; 2044198Sigor@sysoev.ru } 2045198Sigor@sysoev.ru 2046198Sigor@sysoev.ru rpc->socket_conf = skcf; 2047198Sigor@sysoev.ru rpc->temp_conf = tmcf; 2048198Sigor@sysoev.ru 2049359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 2050358Sigor@sysoev.ru 2051358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2052198Sigor@sysoev.ru if (b == NULL) { 2053198Sigor@sysoev.ru goto fail; 2054198Sigor@sysoev.ru } 2055198Sigor@sysoev.ru 2056359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 2057198Sigor@sysoev.ru 2058198Sigor@sysoev.ru rt = task->thread->runtime; 2059240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2060198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2061198Sigor@sysoev.ru 2062198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 2063198Sigor@sysoev.ru nxt_router_listen_socket_ready, 2064198Sigor@sysoev.ru nxt_router_listen_socket_error, 2065198Sigor@sysoev.ru main_port->pid, rpc); 2066645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 2067198Sigor@sysoev.ru goto fail; 2068198Sigor@sysoev.ru } 2069198Sigor@sysoev.ru 2070648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 2071648Svbart@nginx.com stream, router_port->id, b); 2072648Svbart@nginx.com 2073648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2074648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2075648Svbart@nginx.com goto fail; 2076648Svbart@nginx.com } 2077198Sigor@sysoev.ru 2078198Sigor@sysoev.ru return; 2079198Sigor@sysoev.ru 2080198Sigor@sysoev.ru fail: 2081198Sigor@sysoev.ru 2082198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 2083198Sigor@sysoev.ru } 2084198Sigor@sysoev.ru 2085198Sigor@sysoev.ru 2086198Sigor@sysoev.ru static void 2087198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2088198Sigor@sysoev.ru void *data) 208953Sigor@sysoev.ru { 2090359Sigor@sysoev.ru nxt_int_t ret; 2091359Sigor@sysoev.ru nxt_socket_t s; 2092359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 209353Sigor@sysoev.ru 2094198Sigor@sysoev.ru rpc = data; 2095198Sigor@sysoev.ru 2096198Sigor@sysoev.ru s = msg->fd; 2097198Sigor@sysoev.ru 2098198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 2099198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2100198Sigor@sysoev.ru goto fail; 210153Sigor@sysoev.ru } 210253Sigor@sysoev.ru 2103359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 2104198Sigor@sysoev.ru 2105198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 2106198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2107198Sigor@sysoev.ru goto fail; 2108198Sigor@sysoev.ru } 2109198Sigor@sysoev.ru 2110359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 2111198Sigor@sysoev.ru 2112198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2113198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2114198Sigor@sysoev.ru 2115198Sigor@sysoev.ru return; 2116148Sigor@sysoev.ru 2117148Sigor@sysoev.ru fail: 2118148Sigor@sysoev.ru 2119148Sigor@sysoev.ru nxt_socket_close(task, s); 2120148Sigor@sysoev.ru 2121198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2122198Sigor@sysoev.ru } 2123198Sigor@sysoev.ru 2124198Sigor@sysoev.ru 2125198Sigor@sysoev.ru static void 2126198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2127198Sigor@sysoev.ru void *data) 2128198Sigor@sysoev.ru { 2129955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2130955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2131955Svbart@nginx.com 2132955Svbart@nginx.com rpc = data; 2133955Svbart@nginx.com tmcf = rpc->temp_conf; 2134955Svbart@nginx.com 2135955Svbart@nginx.com #if 0 2136198Sigor@sysoev.ru u_char *p; 2137198Sigor@sysoev.ru size_t size; 2138198Sigor@sysoev.ru uint8_t error; 2139198Sigor@sysoev.ru nxt_buf_t *in, *out; 2140198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2141198Sigor@sysoev.ru 2142198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2143198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2144198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2145198Sigor@sysoev.ru nxt_string("ListenerPort"), 2146198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2147198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2148198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2149198Sigor@sysoev.ru nxt_string("ListenerPath"), 2150198Sigor@sysoev.ru }; 2151198Sigor@sysoev.ru 2152359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2153352Smax.romanov@nginx.com 2154352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2155352Smax.romanov@nginx.com 2156551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2157551Smax.romanov@nginx.com return; 2158551Smax.romanov@nginx.com } 2159352Smax.romanov@nginx.com 2160198Sigor@sysoev.ru p = in->mem.pos; 2161198Sigor@sysoev.ru 2162198Sigor@sysoev.ru error = *p++; 2163198Sigor@sysoev.ru 2164703Svbart@nginx.com size = nxt_length("listen socket error: ") 2165703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2166198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2167198Sigor@sysoev.ru 2168198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2169198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2170198Sigor@sysoev.ru return; 2171198Sigor@sysoev.ru } 2172198Sigor@sysoev.ru 2173198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2174198Sigor@sysoev.ru "listen socket error: " 2175198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2176493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2177198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2178198Sigor@sysoev.ru 2179198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2180955Svbart@nginx.com #endif 2181198Sigor@sysoev.ru 2182198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 218353Sigor@sysoev.ru } 218453Sigor@sysoev.ru 218553Sigor@sysoev.ru 2186774Svbart@nginx.com #if (NXT_TLS) 2187774Svbart@nginx.com 2188774Svbart@nginx.com static void 2189774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2190774Svbart@nginx.com nxt_router_tlssock_t *tls) 2191774Svbart@nginx.com { 2192774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2193774Svbart@nginx.com 2194774Svbart@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2195774Svbart@nginx.com if (rpc == NULL) { 2196774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2197774Svbart@nginx.com return; 2198774Svbart@nginx.com } 2199774Svbart@nginx.com 2200774Svbart@nginx.com rpc->socket_conf = tls->conf; 2201774Svbart@nginx.com rpc->temp_conf = tmcf; 2202774Svbart@nginx.com 2203774Svbart@nginx.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 2204774Svbart@nginx.com nxt_router_tls_rpc_handler, rpc); 2205774Svbart@nginx.com } 2206774Svbart@nginx.com 2207774Svbart@nginx.com 2208774Svbart@nginx.com static void 2209774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2210774Svbart@nginx.com void *data) 2211774Svbart@nginx.com { 2212774Svbart@nginx.com nxt_mp_t *mp; 2213774Svbart@nginx.com nxt_int_t ret; 2214774Svbart@nginx.com nxt_tls_conf_t *tlscf; 2215774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2216774Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2217774Svbart@nginx.com 2218774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2219774Svbart@nginx.com 2220774Svbart@nginx.com rpc = data; 2221774Svbart@nginx.com tmcf = rpc->temp_conf; 2222774Svbart@nginx.com 2223774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2224774Svbart@nginx.com goto fail; 2225774Svbart@nginx.com } 2226774Svbart@nginx.com 2227774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2228774Svbart@nginx.com 2229774Svbart@nginx.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 2230774Svbart@nginx.com if (nxt_slow_path(tlscf == NULL)) { 2231774Svbart@nginx.com goto fail; 2232774Svbart@nginx.com } 2233774Svbart@nginx.com 2234774Svbart@nginx.com tlscf->chain_file = msg->fd; 2235774Svbart@nginx.com 2236774Svbart@nginx.com ret = task->thread->runtime->tls->server_init(task, tlscf); 2237774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2238774Svbart@nginx.com goto fail; 2239774Svbart@nginx.com } 2240774Svbart@nginx.com 2241774Svbart@nginx.com rpc->socket_conf->tls = tlscf; 2242774Svbart@nginx.com 2243774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2244774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2245774Svbart@nginx.com return; 2246774Svbart@nginx.com 2247774Svbart@nginx.com fail: 2248774Svbart@nginx.com 2249774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2250774Svbart@nginx.com } 2251774Svbart@nginx.com 2252774Svbart@nginx.com #endif 2253774Svbart@nginx.com 2254774Svbart@nginx.com 2255507Smax.romanov@nginx.com static void 2256507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2257507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2258507Smax.romanov@nginx.com { 2259507Smax.romanov@nginx.com size_t size; 2260507Smax.romanov@nginx.com uint32_t stream; 2261648Svbart@nginx.com nxt_int_t ret; 2262507Smax.romanov@nginx.com nxt_buf_t *b; 2263507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 2264507Smax.romanov@nginx.com nxt_runtime_t *rt; 2265507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2266507Smax.romanov@nginx.com 2267507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 2268507Smax.romanov@nginx.com if (rpc == NULL) { 2269507Smax.romanov@nginx.com goto fail; 2270507Smax.romanov@nginx.com } 2271507Smax.romanov@nginx.com 2272507Smax.romanov@nginx.com rpc->app = app; 2273507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2274507Smax.romanov@nginx.com 2275507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 2276507Smax.romanov@nginx.com 2277507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 2278507Smax.romanov@nginx.com 2279507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2280507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2281507Smax.romanov@nginx.com goto fail; 2282507Smax.romanov@nginx.com } 2283507Smax.romanov@nginx.com 2284507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 2285507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 2286507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2287507Smax.romanov@nginx.com 2288507Smax.romanov@nginx.com rt = task->thread->runtime; 2289507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2290507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2291507Smax.romanov@nginx.com 2292507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2293507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 2294507Smax.romanov@nginx.com nxt_router_app_prefork_error, 2295507Smax.romanov@nginx.com -1, rpc); 2296507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2297507Smax.romanov@nginx.com goto fail; 2298507Smax.romanov@nginx.com } 2299507Smax.romanov@nginx.com 2300648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2301648Svbart@nginx.com stream, router_port->id, b); 2302648Svbart@nginx.com 2303648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2304648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2305648Svbart@nginx.com goto fail; 2306648Svbart@nginx.com } 2307648Svbart@nginx.com 2308507Smax.romanov@nginx.com app->pending_processes++; 2309507Smax.romanov@nginx.com 2310507Smax.romanov@nginx.com return; 2311507Smax.romanov@nginx.com 2312507Smax.romanov@nginx.com fail: 2313507Smax.romanov@nginx.com 2314507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2315507Smax.romanov@nginx.com } 2316507Smax.romanov@nginx.com 2317507Smax.romanov@nginx.com 2318507Smax.romanov@nginx.com static void 2319507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2320507Smax.romanov@nginx.com void *data) 2321507Smax.romanov@nginx.com { 2322507Smax.romanov@nginx.com nxt_app_t *app; 2323507Smax.romanov@nginx.com nxt_port_t *port; 2324507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2325507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2326507Smax.romanov@nginx.com 2327507Smax.romanov@nginx.com rpc = data; 2328507Smax.romanov@nginx.com app = rpc->app; 2329507Smax.romanov@nginx.com 2330507Smax.romanov@nginx.com port = msg->u.new_port; 2331507Smax.romanov@nginx.com port->app = app; 2332507Smax.romanov@nginx.com 2333507Smax.romanov@nginx.com app->pending_processes--; 2334507Smax.romanov@nginx.com app->processes++; 2335507Smax.romanov@nginx.com app->idle_processes++; 2336507Smax.romanov@nginx.com 2337507Smax.romanov@nginx.com engine = task->thread->engine; 2338507Smax.romanov@nginx.com 2339507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2340507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 2341507Smax.romanov@nginx.com 2342507Smax.romanov@nginx.com port->idle_start = 0; 2343507Smax.romanov@nginx.com 2344507Smax.romanov@nginx.com nxt_port_inc_use(port); 2345507Smax.romanov@nginx.com 2346507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2347507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2348507Smax.romanov@nginx.com } 2349507Smax.romanov@nginx.com 2350507Smax.romanov@nginx.com 2351507Smax.romanov@nginx.com static void 2352507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2353507Smax.romanov@nginx.com void *data) 2354507Smax.romanov@nginx.com { 2355507Smax.romanov@nginx.com nxt_app_t *app; 2356507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2357507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2358507Smax.romanov@nginx.com 2359507Smax.romanov@nginx.com rpc = data; 2360507Smax.romanov@nginx.com app = rpc->app; 2361507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2362507Smax.romanov@nginx.com 2363507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2364507Smax.romanov@nginx.com &app->name); 2365507Smax.romanov@nginx.com 2366507Smax.romanov@nginx.com app->pending_processes--; 2367507Smax.romanov@nginx.com 2368507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2369507Smax.romanov@nginx.com } 2370507Smax.romanov@nginx.com 2371507Smax.romanov@nginx.com 237253Sigor@sysoev.ru static nxt_int_t 237353Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 237453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 237553Sigor@sysoev.ru { 237653Sigor@sysoev.ru nxt_int_t ret; 237753Sigor@sysoev.ru nxt_uint_t n, threads; 237853Sigor@sysoev.ru nxt_queue_link_t *qlk; 237953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 238053Sigor@sysoev.ru 2381591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 238253Sigor@sysoev.ru 238353Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 238453Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 238553Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 238653Sigor@sysoev.ru return NXT_ERROR; 238753Sigor@sysoev.ru } 238853Sigor@sysoev.ru 238953Sigor@sysoev.ru n = 0; 239053Sigor@sysoev.ru 239153Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 239253Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 239353Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 239453Sigor@sysoev.ru { 239553Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 239653Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 239753Sigor@sysoev.ru return NXT_ERROR; 239853Sigor@sysoev.ru } 239953Sigor@sysoev.ru 2400115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 240153Sigor@sysoev.ru 240253Sigor@sysoev.ru if (n < threads) { 2403315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2404115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 240553Sigor@sysoev.ru 240653Sigor@sysoev.ru } else { 2407315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2408115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 240953Sigor@sysoev.ru } 241053Sigor@sysoev.ru 241153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 241253Sigor@sysoev.ru return ret; 241353Sigor@sysoev.ru } 241453Sigor@sysoev.ru 241553Sigor@sysoev.ru n++; 241653Sigor@sysoev.ru } 241753Sigor@sysoev.ru 241853Sigor@sysoev.ru tmcf->new_threads = n; 241953Sigor@sysoev.ru 242053Sigor@sysoev.ru while (n < threads) { 242153Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 242253Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 242353Sigor@sysoev.ru return NXT_ERROR; 242453Sigor@sysoev.ru } 242553Sigor@sysoev.ru 2426315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2427315Sigor@sysoev.ru 242853Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 242953Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 243053Sigor@sysoev.ru return NXT_ERROR; 243153Sigor@sysoev.ru } 243253Sigor@sysoev.ru 2433115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 243453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 243553Sigor@sysoev.ru return ret; 243653Sigor@sysoev.ru } 243753Sigor@sysoev.ru 243853Sigor@sysoev.ru n++; 243953Sigor@sysoev.ru } 244053Sigor@sysoev.ru 244153Sigor@sysoev.ru return NXT_OK; 244253Sigor@sysoev.ru } 244353Sigor@sysoev.ru 244453Sigor@sysoev.ru 244553Sigor@sysoev.ru static nxt_int_t 2446115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2447115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 244853Sigor@sysoev.ru { 2449359Sigor@sysoev.ru nxt_int_t ret; 245053Sigor@sysoev.ru 2451154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2452154Sigor@sysoev.ru nxt_router_listen_socket_create); 2453115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2454115Sigor@sysoev.ru return ret; 2455115Sigor@sysoev.ru } 2456115Sigor@sysoev.ru 2457154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2458154Sigor@sysoev.ru nxt_router_listen_socket_create); 245953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 246053Sigor@sysoev.ru return ret; 246153Sigor@sysoev.ru } 246253Sigor@sysoev.ru 2463115Sigor@sysoev.ru return ret; 246453Sigor@sysoev.ru } 246553Sigor@sysoev.ru 246653Sigor@sysoev.ru 246753Sigor@sysoev.ru static nxt_int_t 2468115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2469115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 247053Sigor@sysoev.ru { 2471359Sigor@sysoev.ru nxt_int_t ret; 247253Sigor@sysoev.ru 2473154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2474154Sigor@sysoev.ru nxt_router_listen_socket_create); 247553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 247653Sigor@sysoev.ru return ret; 247753Sigor@sysoev.ru } 247853Sigor@sysoev.ru 2479154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2480154Sigor@sysoev.ru nxt_router_listen_socket_update); 248153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 248253Sigor@sysoev.ru return ret; 248353Sigor@sysoev.ru } 248453Sigor@sysoev.ru 2485139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2486115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2487115Sigor@sysoev.ru return ret; 2488115Sigor@sysoev.ru } 2489115Sigor@sysoev.ru 2490115Sigor@sysoev.ru return ret; 249153Sigor@sysoev.ru } 249253Sigor@sysoev.ru 249353Sigor@sysoev.ru 249453Sigor@sysoev.ru static nxt_int_t 2495115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2496115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 249753Sigor@sysoev.ru { 249853Sigor@sysoev.ru nxt_int_t ret; 249953Sigor@sysoev.ru 2500313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2501313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2502313Sigor@sysoev.ru return ret; 2503313Sigor@sysoev.ru } 2504313Sigor@sysoev.ru 2505139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 250653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 250753Sigor@sysoev.ru return ret; 250853Sigor@sysoev.ru } 250953Sigor@sysoev.ru 2510139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 251153Sigor@sysoev.ru } 251253Sigor@sysoev.ru 251353Sigor@sysoev.ru 251453Sigor@sysoev.ru static nxt_int_t 2515154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2516154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 251753Sigor@sysoev.ru nxt_work_handler_t handler) 251853Sigor@sysoev.ru { 2519153Sigor@sysoev.ru nxt_joint_job_t *job; 252053Sigor@sysoev.ru nxt_queue_link_t *qlk; 2521155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 252253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 252353Sigor@sysoev.ru 252453Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 252553Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 252653Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 252753Sigor@sysoev.ru { 2528154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2529153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2530139Sigor@sysoev.ru return NXT_ERROR; 2531139Sigor@sysoev.ru } 2532139Sigor@sysoev.ru 2533154Sigor@sysoev.ru job->work.next = recf->jobs; 2534154Sigor@sysoev.ru recf->jobs = &job->work; 2535154Sigor@sysoev.ru 2536153Sigor@sysoev.ru job->task = tmcf->engine->task; 2537153Sigor@sysoev.ru job->work.handler = handler; 2538153Sigor@sysoev.ru job->work.task = &job->task; 2539153Sigor@sysoev.ru job->work.obj = job; 2540153Sigor@sysoev.ru job->tmcf = tmcf; 254153Sigor@sysoev.ru 2542154Sigor@sysoev.ru tmcf->count++; 2543154Sigor@sysoev.ru 2544591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2545154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 254653Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 254753Sigor@sysoev.ru return NXT_ERROR; 254853Sigor@sysoev.ru } 254953Sigor@sysoev.ru 2550153Sigor@sysoev.ru job->work.data = joint; 255153Sigor@sysoev.ru 255253Sigor@sysoev.ru joint->count = 1; 2553155Sigor@sysoev.ru 2554155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2555155Sigor@sysoev.ru skcf->count++; 2556155Sigor@sysoev.ru joint->socket_conf = skcf; 2557155Sigor@sysoev.ru 255888Smax.romanov@nginx.com joint->engine = recf->engine; 255953Sigor@sysoev.ru } 256053Sigor@sysoev.ru 256120Sigor@sysoev.ru return NXT_OK; 256220Sigor@sysoev.ru } 256320Sigor@sysoev.ru 256420Sigor@sysoev.ru 256520Sigor@sysoev.ru static nxt_int_t 2566313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2567313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2568313Sigor@sysoev.ru { 2569313Sigor@sysoev.ru nxt_joint_job_t *job; 2570313Sigor@sysoev.ru 2571313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2572313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2573313Sigor@sysoev.ru return NXT_ERROR; 2574313Sigor@sysoev.ru } 2575313Sigor@sysoev.ru 2576313Sigor@sysoev.ru job->work.next = recf->jobs; 2577313Sigor@sysoev.ru recf->jobs = &job->work; 2578313Sigor@sysoev.ru 2579313Sigor@sysoev.ru job->task = tmcf->engine->task; 2580313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2581313Sigor@sysoev.ru job->work.task = &job->task; 2582313Sigor@sysoev.ru job->work.obj = NULL; 2583313Sigor@sysoev.ru job->work.data = NULL; 2584313Sigor@sysoev.ru job->tmcf = NULL; 2585313Sigor@sysoev.ru 2586313Sigor@sysoev.ru return NXT_OK; 2587313Sigor@sysoev.ru } 2588313Sigor@sysoev.ru 2589313Sigor@sysoev.ru 2590313Sigor@sysoev.ru static nxt_int_t 2591139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2592139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 259320Sigor@sysoev.ru { 2594153Sigor@sysoev.ru nxt_joint_job_t *job; 259553Sigor@sysoev.ru nxt_queue_link_t *qlk; 259620Sigor@sysoev.ru 259753Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 259853Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 259953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 260053Sigor@sysoev.ru { 2601154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2602153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2603139Sigor@sysoev.ru return NXT_ERROR; 2604139Sigor@sysoev.ru } 2605139Sigor@sysoev.ru 2606154Sigor@sysoev.ru job->work.next = recf->jobs; 2607154Sigor@sysoev.ru recf->jobs = &job->work; 2608154Sigor@sysoev.ru 2609153Sigor@sysoev.ru job->task = tmcf->engine->task; 2610153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2611153Sigor@sysoev.ru job->work.task = &job->task; 2612153Sigor@sysoev.ru job->work.obj = job; 2613153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2614153Sigor@sysoev.ru job->tmcf = tmcf; 2615154Sigor@sysoev.ru 2616154Sigor@sysoev.ru tmcf->count++; 261720Sigor@sysoev.ru } 261820Sigor@sysoev.ru 261953Sigor@sysoev.ru return NXT_OK; 262053Sigor@sysoev.ru } 262120Sigor@sysoev.ru 262220Sigor@sysoev.ru 262353Sigor@sysoev.ru static nxt_int_t 262453Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 262553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 262653Sigor@sysoev.ru { 262753Sigor@sysoev.ru nxt_int_t ret; 262853Sigor@sysoev.ru nxt_uint_t i, threads; 262953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 263020Sigor@sysoev.ru 263153Sigor@sysoev.ru recf = tmcf->engines->elts; 2632591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 263320Sigor@sysoev.ru 263453Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 263553Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 263653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 263753Sigor@sysoev.ru return ret; 263853Sigor@sysoev.ru } 263920Sigor@sysoev.ru } 264020Sigor@sysoev.ru 264120Sigor@sysoev.ru return NXT_OK; 264220Sigor@sysoev.ru } 264353Sigor@sysoev.ru 264453Sigor@sysoev.ru 264553Sigor@sysoev.ru static nxt_int_t 264653Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 264753Sigor@sysoev.ru nxt_event_engine_t *engine) 264853Sigor@sysoev.ru { 264953Sigor@sysoev.ru nxt_int_t ret; 265053Sigor@sysoev.ru nxt_thread_link_t *link; 265153Sigor@sysoev.ru nxt_thread_handle_t handle; 265253Sigor@sysoev.ru 265353Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 265453Sigor@sysoev.ru 265553Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 265653Sigor@sysoev.ru return NXT_ERROR; 265753Sigor@sysoev.ru } 265853Sigor@sysoev.ru 265953Sigor@sysoev.ru link->start = nxt_router_thread_start; 266053Sigor@sysoev.ru link->engine = engine; 266153Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 266253Sigor@sysoev.ru link->work.task = task; 266353Sigor@sysoev.ru link->work.data = link; 266453Sigor@sysoev.ru 266553Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 266653Sigor@sysoev.ru 266753Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 266853Sigor@sysoev.ru 266953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 267053Sigor@sysoev.ru nxt_queue_remove(&engine->link); 267153Sigor@sysoev.ru } 267253Sigor@sysoev.ru 267353Sigor@sysoev.ru return ret; 267453Sigor@sysoev.ru } 267553Sigor@sysoev.ru 267653Sigor@sysoev.ru 267753Sigor@sysoev.ru static void 2678343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2679343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2680133Sigor@sysoev.ru { 2681507Smax.romanov@nginx.com nxt_app_t *app; 2682141Smax.romanov@nginx.com 2683141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2684133Sigor@sysoev.ru 2685753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2686343Smax.romanov@nginx.com 2687141Smax.romanov@nginx.com } nxt_queue_loop; 2688133Sigor@sysoev.ru 2689133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2690133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2691133Sigor@sysoev.ru } 2692133Sigor@sysoev.ru 2693133Sigor@sysoev.ru 2694133Sigor@sysoev.ru static void 2695315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 269653Sigor@sysoev.ru { 269753Sigor@sysoev.ru nxt_uint_t n; 2698315Sigor@sysoev.ru nxt_event_engine_t *engine; 269953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 270053Sigor@sysoev.ru 270153Sigor@sysoev.ru recf = tmcf->engines->elts; 270253Sigor@sysoev.ru 270353Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2704315Sigor@sysoev.ru engine = recf->engine; 2705315Sigor@sysoev.ru 2706315Sigor@sysoev.ru switch (recf->action) { 2707315Sigor@sysoev.ru 2708315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2709315Sigor@sysoev.ru break; 2710315Sigor@sysoev.ru 2711315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2712315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2713315Sigor@sysoev.ru break; 2714315Sigor@sysoev.ru 2715315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2716315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2717315Sigor@sysoev.ru break; 2718315Sigor@sysoev.ru } 2719315Sigor@sysoev.ru 2720316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2721316Sigor@sysoev.ru 272253Sigor@sysoev.ru recf++; 272353Sigor@sysoev.ru } 272453Sigor@sysoev.ru } 272553Sigor@sysoev.ru 272653Sigor@sysoev.ru 272753Sigor@sysoev.ru static void 2728315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 272953Sigor@sysoev.ru { 2730154Sigor@sysoev.ru nxt_work_t *work, *next; 2731154Sigor@sysoev.ru 2732315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2733154Sigor@sysoev.ru next = work->next; 2734154Sigor@sysoev.ru work->next = NULL; 2735154Sigor@sysoev.ru 2736315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 273753Sigor@sysoev.ru } 273853Sigor@sysoev.ru } 273953Sigor@sysoev.ru 274053Sigor@sysoev.ru 2741320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2742616Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2743616Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2744616Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 274588Smax.romanov@nginx.com }; 274688Smax.romanov@nginx.com 274788Smax.romanov@nginx.com 274888Smax.romanov@nginx.com static void 274953Sigor@sysoev.ru nxt_router_thread_start(void *data) 275053Sigor@sysoev.ru { 2751141Smax.romanov@nginx.com nxt_int_t ret; 2752141Smax.romanov@nginx.com nxt_port_t *port; 275388Smax.romanov@nginx.com nxt_task_t *task; 275453Sigor@sysoev.ru nxt_thread_t *thread; 275553Sigor@sysoev.ru nxt_thread_link_t *link; 275653Sigor@sysoev.ru nxt_event_engine_t *engine; 275753Sigor@sysoev.ru 275853Sigor@sysoev.ru link = data; 275953Sigor@sysoev.ru engine = link->engine; 276088Smax.romanov@nginx.com task = &engine->task; 276153Sigor@sysoev.ru 276253Sigor@sysoev.ru thread = nxt_thread(); 276353Sigor@sysoev.ru 2764165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2765165Smax.romanov@nginx.com 276653Sigor@sysoev.ru /* STUB */ 276753Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 276853Sigor@sysoev.ru 276953Sigor@sysoev.ru engine->task.thread = thread; 277053Sigor@sysoev.ru engine->task.log = thread->log; 277153Sigor@sysoev.ru thread->engine = engine; 277263Sigor@sysoev.ru thread->task = &engine->task; 2773326Svbart@nginx.com #if 0 277453Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2775326Svbart@nginx.com #endif 277653Sigor@sysoev.ru 277763Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2778337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2779337Sigor@sysoev.ru return; 2780337Sigor@sysoev.ru } 278153Sigor@sysoev.ru 2782197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2783197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2784141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2785141Smax.romanov@nginx.com return; 2786141Smax.romanov@nginx.com } 2787141Smax.romanov@nginx.com 2788141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2789141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2790343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2791141Smax.romanov@nginx.com return; 2792141Smax.romanov@nginx.com } 2793141Smax.romanov@nginx.com 2794141Smax.romanov@nginx.com engine->port = port; 2795141Smax.romanov@nginx.com 2796320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2797141Smax.romanov@nginx.com 279853Sigor@sysoev.ru nxt_event_engine_start(engine); 279953Sigor@sysoev.ru } 280053Sigor@sysoev.ru 280153Sigor@sysoev.ru 280253Sigor@sysoev.ru static void 280353Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 280453Sigor@sysoev.ru { 2805153Sigor@sysoev.ru nxt_joint_job_t *job; 2806359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2807359Sigor@sysoev.ru nxt_listen_event_t *lev; 280853Sigor@sysoev.ru nxt_listen_socket_t *ls; 2809359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 281053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 281153Sigor@sysoev.ru 2812153Sigor@sysoev.ru job = obj; 281353Sigor@sysoev.ru joint = data; 281453Sigor@sysoev.ru 2815159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2816159Sigor@sysoev.ru 2817359Sigor@sysoev.ru skcf = joint->socket_conf; 2818359Sigor@sysoev.ru ls = skcf->listen; 2819359Sigor@sysoev.ru 2820359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2821359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2822359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 282353Sigor@sysoev.ru return; 282453Sigor@sysoev.ru } 282553Sigor@sysoev.ru 2826359Sigor@sysoev.ru lev->socket.data = joint; 2827359Sigor@sysoev.ru 2828359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2829359Sigor@sysoev.ru 2830359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2831359Sigor@sysoev.ru ls->count++; 2832359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2833139Sigor@sysoev.ru 2834153Sigor@sysoev.ru job->work.next = NULL; 2835153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2836153Sigor@sysoev.ru 2837153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 283853Sigor@sysoev.ru } 283953Sigor@sysoev.ru 284053Sigor@sysoev.ru 284153Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 284253Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 284353Sigor@sysoev.ru nxt_socket_conf_t *skcf) 284453Sigor@sysoev.ru { 2845115Sigor@sysoev.ru nxt_socket_t fd; 2846115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2847359Sigor@sysoev.ru nxt_listen_event_t *lev; 2848359Sigor@sysoev.ru 2849359Sigor@sysoev.ru fd = skcf->listen->socket; 285053Sigor@sysoev.ru 2851115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2852115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2853115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 285453Sigor@sysoev.ru { 2855359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2856359Sigor@sysoev.ru 2857359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2858359Sigor@sysoev.ru return lev; 285953Sigor@sysoev.ru } 286053Sigor@sysoev.ru } 286153Sigor@sysoev.ru 286253Sigor@sysoev.ru return NULL; 286353Sigor@sysoev.ru } 286453Sigor@sysoev.ru 286553Sigor@sysoev.ru 286653Sigor@sysoev.ru static void 286753Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 286853Sigor@sysoev.ru { 2869153Sigor@sysoev.ru nxt_joint_job_t *job; 287053Sigor@sysoev.ru nxt_event_engine_t *engine; 2871359Sigor@sysoev.ru nxt_listen_event_t *lev; 287253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 287353Sigor@sysoev.ru 2874153Sigor@sysoev.ru job = obj; 287553Sigor@sysoev.ru joint = data; 287653Sigor@sysoev.ru 2877139Sigor@sysoev.ru engine = task->thread->engine; 2878139Sigor@sysoev.ru 2879159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2880159Sigor@sysoev.ru 2881359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2882359Sigor@sysoev.ru joint->socket_conf); 2883359Sigor@sysoev.ru 2884359Sigor@sysoev.ru old = lev->socket.data; 2885359Sigor@sysoev.ru lev->socket.data = joint; 2886359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 288753Sigor@sysoev.ru 2888153Sigor@sysoev.ru job->work.next = NULL; 2889153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2890153Sigor@sysoev.ru 2891153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2892139Sigor@sysoev.ru 2893181Smax.romanov@nginx.com /* 2894181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2895181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2896181Smax.romanov@nginx.com */ 2897181Smax.romanov@nginx.com 2898181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 289953Sigor@sysoev.ru } 290053Sigor@sysoev.ru 290153Sigor@sysoev.ru 290253Sigor@sysoev.ru static void 290353Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 290453Sigor@sysoev.ru { 2905153Sigor@sysoev.ru nxt_joint_job_t *job; 2906153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2907359Sigor@sysoev.ru nxt_listen_event_t *lev; 2908153Sigor@sysoev.ru nxt_event_engine_t *engine; 2909153Sigor@sysoev.ru 2910153Sigor@sysoev.ru job = obj; 291153Sigor@sysoev.ru skcf = data; 291253Sigor@sysoev.ru 2913139Sigor@sysoev.ru engine = task->thread->engine; 2914139Sigor@sysoev.ru 2915359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2916359Sigor@sysoev.ru 2917359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 291853Sigor@sysoev.ru 2919163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2920359Sigor@sysoev.ru lev->socket.fd); 2921359Sigor@sysoev.ru 2922359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2923359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2924359Sigor@sysoev.ru 2925359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2926139Sigor@sysoev.ru 2927153Sigor@sysoev.ru job->work.next = NULL; 2928153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2929153Sigor@sysoev.ru 2930153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 293153Sigor@sysoev.ru } 293253Sigor@sysoev.ru 293353Sigor@sysoev.ru 293453Sigor@sysoev.ru static void 2935313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2936313Sigor@sysoev.ru { 2937313Sigor@sysoev.ru nxt_event_engine_t *engine; 2938313Sigor@sysoev.ru 2939313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2940313Sigor@sysoev.ru 2941313Sigor@sysoev.ru engine = task->thread->engine; 2942313Sigor@sysoev.ru 2943313Sigor@sysoev.ru engine->shutdown = 1; 2944313Sigor@sysoev.ru 2945313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2946313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2947313Sigor@sysoev.ru } 2948313Sigor@sysoev.ru } 2949313Sigor@sysoev.ru 2950313Sigor@sysoev.ru 2951313Sigor@sysoev.ru static void 295253Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 295353Sigor@sysoev.ru { 295453Sigor@sysoev.ru nxt_timer_t *timer; 2955359Sigor@sysoev.ru nxt_listen_event_t *lev; 295653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 295753Sigor@sysoev.ru 295853Sigor@sysoev.ru timer = obj; 2959359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 296053Sigor@sysoev.ru 2961163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2962359Sigor@sysoev.ru lev->socket.fd); 2963359Sigor@sysoev.ru 2964359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2965359Sigor@sysoev.ru 2966683Sigor@sysoev.ru joint = lev->socket.data; 2967683Sigor@sysoev.ru lev->socket.data = NULL; 2968683Sigor@sysoev.ru 2969359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2970123Smax.romanov@nginx.com task = &task->thread->engine->task; 2971123Smax.romanov@nginx.com 2972359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2973359Sigor@sysoev.ru 2974683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 297553Sigor@sysoev.ru } 297653Sigor@sysoev.ru 297753Sigor@sysoev.ru 297853Sigor@sysoev.ru static void 2979359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 298053Sigor@sysoev.ru { 2981359Sigor@sysoev.ru nxt_listen_socket_t *ls; 298253Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 298353Sigor@sysoev.ru 2984359Sigor@sysoev.ru ls = skcf->listen; 2985118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 298653Sigor@sysoev.ru 298753Sigor@sysoev.ru nxt_thread_spin_lock(lock); 298853Sigor@sysoev.ru 2989359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2990359Sigor@sysoev.ru task->thread->engine, ls->count); 2991359Sigor@sysoev.ru 2992359Sigor@sysoev.ru if (--ls->count != 0) { 2993359Sigor@sysoev.ru ls = NULL; 299453Sigor@sysoev.ru } 299553Sigor@sysoev.ru 299653Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 299753Sigor@sysoev.ru 2998359Sigor@sysoev.ru if (ls != NULL) { 2999359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 3000359Sigor@sysoev.ru nxt_free(ls); 300153Sigor@sysoev.ru } 300253Sigor@sysoev.ru } 300353Sigor@sysoev.ru 300453Sigor@sysoev.ru 3005683Sigor@sysoev.ru void 3006683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 3007683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 3008683Sigor@sysoev.ru { 3009683Sigor@sysoev.ru nxt_event_engine_t *engine; 3010683Sigor@sysoev.ru 3011683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 3012683Sigor@sysoev.ru 3013683Sigor@sysoev.ru if (--lev->count == 0) { 3014683Sigor@sysoev.ru nxt_free(lev); 3015683Sigor@sysoev.ru } 3016683Sigor@sysoev.ru 3017683Sigor@sysoev.ru if (joint != NULL) { 3018683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 3019683Sigor@sysoev.ru } 3020683Sigor@sysoev.ru 3021683Sigor@sysoev.ru engine = task->thread->engine; 3022683Sigor@sysoev.ru 3023683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 3024683Sigor@sysoev.ru nxt_thread_exit(task->thread); 3025683Sigor@sysoev.ru } 3026683Sigor@sysoev.ru } 3027683Sigor@sysoev.ru 3028683Sigor@sysoev.ru 3029683Sigor@sysoev.ru void 303053Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 303153Sigor@sysoev.ru { 303253Sigor@sysoev.ru nxt_socket_conf_t *skcf; 303353Sigor@sysoev.ru nxt_router_conf_t *rtcf; 303453Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 303553Sigor@sysoev.ru 3036163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 303753Sigor@sysoev.ru 303853Sigor@sysoev.ru if (--joint->count != 0) { 303953Sigor@sysoev.ru return; 304053Sigor@sysoev.ru } 304153Sigor@sysoev.ru 304253Sigor@sysoev.ru nxt_queue_remove(&joint->link); 304353Sigor@sysoev.ru 3044530Sigor@sysoev.ru /* 3045530Sigor@sysoev.ru * The joint content can not be safely used after the critical 3046530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 3047530Sigor@sysoev.ru * be already destroyed by another thread. 3048530Sigor@sysoev.ru */ 304953Sigor@sysoev.ru skcf = joint->socket_conf; 305053Sigor@sysoev.ru rtcf = skcf->router_conf; 305153Sigor@sysoev.ru lock = &rtcf->router->lock; 305253Sigor@sysoev.ru 305353Sigor@sysoev.ru nxt_thread_spin_lock(lock); 305453Sigor@sysoev.ru 3055163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 3056163Smax.romanov@nginx.com rtcf, rtcf->count); 3057163Smax.romanov@nginx.com 305853Sigor@sysoev.ru if (--skcf->count != 0) { 3059952Sigor@sysoev.ru skcf = NULL; 306053Sigor@sysoev.ru rtcf = NULL; 306153Sigor@sysoev.ru 306253Sigor@sysoev.ru } else { 306353Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 306453Sigor@sysoev.ru 306553Sigor@sysoev.ru if (--rtcf->count != 0) { 306653Sigor@sysoev.ru rtcf = NULL; 306753Sigor@sysoev.ru } 306853Sigor@sysoev.ru } 306953Sigor@sysoev.ru 307053Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 307153Sigor@sysoev.ru 3072952Sigor@sysoev.ru if (skcf != NULL) { 3073964Sigor@sysoev.ru if (skcf->pass != NULL) { 3074964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 3075964Sigor@sysoev.ru } 3076964Sigor@sysoev.ru 3077952Sigor@sysoev.ru #if (NXT_TLS) 3078952Sigor@sysoev.ru if (skcf->tls != NULL) { 3079952Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 3080952Sigor@sysoev.ru } 3081952Sigor@sysoev.ru #endif 3082952Sigor@sysoev.ru } 3083952Sigor@sysoev.ru 3084141Smax.romanov@nginx.com /* TODO remove engine->port */ 3085141Smax.romanov@nginx.com /* TODO excude from connected ports */ 3086141Smax.romanov@nginx.com 308753Sigor@sysoev.ru if (rtcf != NULL) { 3088115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 3089131Smax.romanov@nginx.com 3090964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 3091964Sigor@sysoev.ru 3092630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 3093630Svbart@nginx.com 3094131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 3095131Smax.romanov@nginx.com 309665Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 309753Sigor@sysoev.ru } 309853Sigor@sysoev.ru } 309953Sigor@sysoev.ru 310053Sigor@sysoev.ru 310153Sigor@sysoev.ru static void 3102630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 3103630Svbart@nginx.com nxt_router_access_log_t *access_log) 3104630Svbart@nginx.com { 3105630Svbart@nginx.com size_t size; 3106630Svbart@nginx.com u_char *buf, *p; 3107630Svbart@nginx.com nxt_off_t bytes; 3108630Svbart@nginx.com 3109630Svbart@nginx.com static nxt_time_string_t date_cache = { 3110630Svbart@nginx.com (nxt_atomic_uint_t) -1, 3111630Svbart@nginx.com nxt_router_access_log_date, 3112630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 3113703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 3114630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 3115630Svbart@nginx.com NXT_THREAD_TIME_SEC, 3116630Svbart@nginx.com }; 3117630Svbart@nginx.com 3118630Svbart@nginx.com size = r->remote->address_length 3119630Svbart@nginx.com + 6 /* ' - - [' */ 3120630Svbart@nginx.com + date_cache.size 3121630Svbart@nginx.com + 3 /* '] "' */ 3122630Svbart@nginx.com + r->method->length 3123630Svbart@nginx.com + 1 /* space */ 3124630Svbart@nginx.com + r->target.length 3125630Svbart@nginx.com + 1 /* space */ 3126630Svbart@nginx.com + r->version.length 3127630Svbart@nginx.com + 2 /* '" ' */ 3128630Svbart@nginx.com + 3 /* status */ 3129630Svbart@nginx.com + 1 /* space */ 3130630Svbart@nginx.com + NXT_OFF_T_LEN 3131630Svbart@nginx.com + 2 /* ' "' */ 3132630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3133630Svbart@nginx.com + 3 /* '" "' */ 3134630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3135630Svbart@nginx.com + 2 /* '"\n' */ 3136630Svbart@nginx.com ; 3137630Svbart@nginx.com 3138630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3139630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3140630Svbart@nginx.com return; 3141630Svbart@nginx.com } 3142630Svbart@nginx.com 3143630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3144630Svbart@nginx.com r->remote->address_length); 3145630Svbart@nginx.com 3146630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3147630Svbart@nginx.com 3148630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3149630Svbart@nginx.com 3150630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3151630Svbart@nginx.com 3152630Svbart@nginx.com if (r->method->length != 0) { 3153630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3154630Svbart@nginx.com 3155630Svbart@nginx.com if (r->target.length != 0) { 3156630Svbart@nginx.com *p++ = ' '; 3157630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3158630Svbart@nginx.com 3159630Svbart@nginx.com if (r->version.length != 0) { 3160630Svbart@nginx.com *p++ = ' '; 3161630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3162630Svbart@nginx.com } 3163630Svbart@nginx.com } 3164630Svbart@nginx.com 3165630Svbart@nginx.com } else { 3166630Svbart@nginx.com *p++ = '-'; 3167630Svbart@nginx.com } 3168630Svbart@nginx.com 3169630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3170630Svbart@nginx.com 3171630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3172630Svbart@nginx.com 3173630Svbart@nginx.com *p++ = ' '; 3174630Svbart@nginx.com 31751112Sigor@sysoev.ru bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); 3176630Svbart@nginx.com 3177630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3178630Svbart@nginx.com 3179630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3180630Svbart@nginx.com 3181630Svbart@nginx.com if (r->referer != NULL) { 3182630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3183630Svbart@nginx.com 3184630Svbart@nginx.com } else { 3185630Svbart@nginx.com *p++ = '-'; 3186630Svbart@nginx.com } 3187630Svbart@nginx.com 3188630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3189630Svbart@nginx.com 3190630Svbart@nginx.com if (r->user_agent != NULL) { 3191630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3192630Svbart@nginx.com 3193630Svbart@nginx.com } else { 3194630Svbart@nginx.com *p++ = '-'; 3195630Svbart@nginx.com } 3196630Svbart@nginx.com 3197630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3198630Svbart@nginx.com 3199630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3200630Svbart@nginx.com } 3201630Svbart@nginx.com 3202630Svbart@nginx.com 3203630Svbart@nginx.com static u_char * 3204630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3205630Svbart@nginx.com size_t size, const char *format) 3206630Svbart@nginx.com { 3207630Svbart@nginx.com u_char sign; 3208630Svbart@nginx.com time_t gmtoff; 3209630Svbart@nginx.com 3210630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3211630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3212630Svbart@nginx.com 3213630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3214630Svbart@nginx.com 3215630Svbart@nginx.com if (gmtoff < 0) { 3216630Svbart@nginx.com gmtoff = -gmtoff; 3217630Svbart@nginx.com sign = '-'; 3218630Svbart@nginx.com 3219630Svbart@nginx.com } else { 3220630Svbart@nginx.com sign = '+'; 3221630Svbart@nginx.com } 3222630Svbart@nginx.com 3223630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3224630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3225630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3226630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3227630Svbart@nginx.com } 3228630Svbart@nginx.com 3229630Svbart@nginx.com 3230630Svbart@nginx.com static void 3231630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3232630Svbart@nginx.com { 3233630Svbart@nginx.com uint32_t stream; 3234648Svbart@nginx.com nxt_int_t ret; 3235630Svbart@nginx.com nxt_buf_t *b; 3236630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3237630Svbart@nginx.com nxt_runtime_t *rt; 3238630Svbart@nginx.com nxt_router_access_log_t *access_log; 3239630Svbart@nginx.com 3240630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3241630Svbart@nginx.com 3242630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3243630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3244630Svbart@nginx.com goto fail; 3245630Svbart@nginx.com } 3246630Svbart@nginx.com 3247630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3248630Svbart@nginx.com *b->mem.free++ = '\0'; 3249630Svbart@nginx.com 3250630Svbart@nginx.com rt = task->thread->runtime; 3251630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3252630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3253630Svbart@nginx.com 3254630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3255630Svbart@nginx.com nxt_router_access_log_ready, 3256630Svbart@nginx.com nxt_router_access_log_error, 3257630Svbart@nginx.com -1, tmcf); 3258630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3259630Svbart@nginx.com goto fail; 3260630Svbart@nginx.com } 3261630Svbart@nginx.com 3262648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3263648Svbart@nginx.com stream, router_port->id, b); 3264648Svbart@nginx.com 3265648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3266648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3267648Svbart@nginx.com goto fail; 3268648Svbart@nginx.com } 3269630Svbart@nginx.com 3270630Svbart@nginx.com return; 3271630Svbart@nginx.com 3272630Svbart@nginx.com fail: 3273630Svbart@nginx.com 3274630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3275630Svbart@nginx.com } 3276630Svbart@nginx.com 3277630Svbart@nginx.com 3278630Svbart@nginx.com static void 3279630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3280630Svbart@nginx.com void *data) 3281630Svbart@nginx.com { 3282630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3283630Svbart@nginx.com nxt_router_access_log_t *access_log; 3284630Svbart@nginx.com 3285630Svbart@nginx.com tmcf = data; 3286630Svbart@nginx.com 3287630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3288630Svbart@nginx.com 3289630Svbart@nginx.com access_log->fd = msg->fd; 3290630Svbart@nginx.com 3291630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3292630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3293630Svbart@nginx.com } 3294630Svbart@nginx.com 3295630Svbart@nginx.com 3296630Svbart@nginx.com static void 3297630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3298630Svbart@nginx.com void *data) 3299630Svbart@nginx.com { 3300630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3301630Svbart@nginx.com 3302630Svbart@nginx.com tmcf = data; 3303630Svbart@nginx.com 3304630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3305630Svbart@nginx.com } 3306630Svbart@nginx.com 3307630Svbart@nginx.com 3308630Svbart@nginx.com static void 3309630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3310630Svbart@nginx.com nxt_router_access_log_t *access_log) 3311630Svbart@nginx.com { 3312630Svbart@nginx.com if (access_log == NULL) { 3313630Svbart@nginx.com return; 3314630Svbart@nginx.com } 3315630Svbart@nginx.com 3316630Svbart@nginx.com nxt_thread_spin_lock(lock); 3317630Svbart@nginx.com 3318630Svbart@nginx.com if (--access_log->count != 0) { 3319630Svbart@nginx.com access_log = NULL; 3320630Svbart@nginx.com } 3321630Svbart@nginx.com 3322630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3323630Svbart@nginx.com 3324630Svbart@nginx.com if (access_log != NULL) { 3325630Svbart@nginx.com 3326630Svbart@nginx.com if (access_log->fd != -1) { 3327630Svbart@nginx.com nxt_fd_close(access_log->fd); 3328630Svbart@nginx.com } 3329630Svbart@nginx.com 3330630Svbart@nginx.com nxt_free(access_log); 3331630Svbart@nginx.com } 3332630Svbart@nginx.com } 3333630Svbart@nginx.com 3334630Svbart@nginx.com 3335631Svbart@nginx.com typedef struct { 3336631Svbart@nginx.com nxt_mp_t *mem_pool; 3337631Svbart@nginx.com nxt_router_access_log_t *access_log; 3338631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3339631Svbart@nginx.com 3340631Svbart@nginx.com 3341631Svbart@nginx.com void 3342631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3343631Svbart@nginx.com { 3344631Svbart@nginx.com nxt_mp_t *mp; 3345631Svbart@nginx.com uint32_t stream; 3346631Svbart@nginx.com nxt_int_t ret; 3347631Svbart@nginx.com nxt_buf_t *b; 3348631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3349631Svbart@nginx.com nxt_runtime_t *rt; 3350631Svbart@nginx.com nxt_router_access_log_t *access_log; 3351631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3352631Svbart@nginx.com 3353631Svbart@nginx.com access_log = nxt_router->access_log; 3354631Svbart@nginx.com 3355631Svbart@nginx.com if (access_log == NULL) { 3356631Svbart@nginx.com return; 3357631Svbart@nginx.com } 3358631Svbart@nginx.com 3359631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3360631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3361631Svbart@nginx.com return; 3362631Svbart@nginx.com } 3363631Svbart@nginx.com 3364631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3365631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3366631Svbart@nginx.com goto fail; 3367631Svbart@nginx.com } 3368631Svbart@nginx.com 3369631Svbart@nginx.com reopen->mem_pool = mp; 3370631Svbart@nginx.com reopen->access_log = access_log; 3371631Svbart@nginx.com 3372631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3373631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3374631Svbart@nginx.com goto fail; 3375631Svbart@nginx.com } 3376631Svbart@nginx.com 3377651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3378651Svbart@nginx.com 3379631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3380631Svbart@nginx.com *b->mem.free++ = '\0'; 3381631Svbart@nginx.com 3382631Svbart@nginx.com rt = task->thread->runtime; 3383631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3384631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3385631Svbart@nginx.com 3386631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3387631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3388631Svbart@nginx.com nxt_router_access_log_reopen_error, 3389631Svbart@nginx.com -1, reopen); 3390631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3391631Svbart@nginx.com goto fail; 3392631Svbart@nginx.com } 3393631Svbart@nginx.com 3394631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3395631Svbart@nginx.com stream, router_port->id, b); 3396631Svbart@nginx.com 3397631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3398631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3399631Svbart@nginx.com goto fail; 3400631Svbart@nginx.com } 3401631Svbart@nginx.com 3402651Svbart@nginx.com nxt_mp_retain(mp); 3403651Svbart@nginx.com 3404631Svbart@nginx.com return; 3405631Svbart@nginx.com 3406631Svbart@nginx.com fail: 3407631Svbart@nginx.com 3408631Svbart@nginx.com nxt_mp_destroy(mp); 3409631Svbart@nginx.com } 3410631Svbart@nginx.com 3411631Svbart@nginx.com 3412631Svbart@nginx.com static void 3413651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3414651Svbart@nginx.com { 3415651Svbart@nginx.com nxt_mp_t *mp; 3416651Svbart@nginx.com nxt_buf_t *b; 3417651Svbart@nginx.com 3418651Svbart@nginx.com b = obj; 3419651Svbart@nginx.com mp = b->data; 3420651Svbart@nginx.com 3421651Svbart@nginx.com nxt_mp_release(mp); 3422651Svbart@nginx.com } 3423651Svbart@nginx.com 3424651Svbart@nginx.com 3425651Svbart@nginx.com static void 3426631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3427631Svbart@nginx.com void *data) 3428631Svbart@nginx.com { 3429631Svbart@nginx.com nxt_router_access_log_t *access_log; 3430631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3431631Svbart@nginx.com 3432631Svbart@nginx.com reopen = data; 3433631Svbart@nginx.com 3434631Svbart@nginx.com access_log = reopen->access_log; 3435631Svbart@nginx.com 3436631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3437631Svbart@nginx.com 3438631Svbart@nginx.com if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) { 3439631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3440631Svbart@nginx.com msg->fd, access_log->fd, nxt_errno); 3441631Svbart@nginx.com } 3442631Svbart@nginx.com } 3443631Svbart@nginx.com 3444631Svbart@nginx.com nxt_fd_close(msg->fd); 3445651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3446631Svbart@nginx.com } 3447631Svbart@nginx.com 3448631Svbart@nginx.com 3449631Svbart@nginx.com static void 3450631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3451631Svbart@nginx.com void *data) 3452631Svbart@nginx.com { 3453631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3454631Svbart@nginx.com 3455631Svbart@nginx.com reopen = data; 3456631Svbart@nginx.com 3457651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3458631Svbart@nginx.com } 3459631Svbart@nginx.com 3460631Svbart@nginx.com 3461630Svbart@nginx.com static void 346253Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 346353Sigor@sysoev.ru { 3464141Smax.romanov@nginx.com nxt_port_t *port; 346553Sigor@sysoev.ru nxt_thread_link_t *link; 346653Sigor@sysoev.ru nxt_event_engine_t *engine; 346753Sigor@sysoev.ru nxt_thread_handle_t handle; 346853Sigor@sysoev.ru 346958Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 347053Sigor@sysoev.ru link = data; 347153Sigor@sysoev.ru 347253Sigor@sysoev.ru nxt_thread_wait(handle); 347353Sigor@sysoev.ru 347453Sigor@sysoev.ru engine = link->engine; 347553Sigor@sysoev.ru 347653Sigor@sysoev.ru nxt_queue_remove(&engine->link); 347753Sigor@sysoev.ru 3478141Smax.romanov@nginx.com port = engine->port; 3479141Smax.romanov@nginx.com 3480141Smax.romanov@nginx.com // TODO notify all apps 3481141Smax.romanov@nginx.com 3482343Smax.romanov@nginx.com port->engine = task->thread->engine; 3483163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3484343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3485163Smax.romanov@nginx.com 3486163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 348763Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 348853Sigor@sysoev.ru 348953Sigor@sysoev.ru nxt_event_engine_free(engine); 349053Sigor@sysoev.ru 349153Sigor@sysoev.ru nxt_free(link); 349253Sigor@sysoev.ru } 349353Sigor@sysoev.ru 349453Sigor@sysoev.ru 349553Sigor@sysoev.ru static void 3496318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3497318Smax.romanov@nginx.com void *data) 349888Smax.romanov@nginx.com { 34991123Smax.romanov@nginx.com nxt_int_t ret; 35001123Smax.romanov@nginx.com nxt_buf_t *b; 35011131Smax.romanov@nginx.com nxt_port_t *app_port; 35021123Smax.romanov@nginx.com nxt_unit_field_t *f; 35031123Smax.romanov@nginx.com nxt_http_field_t *field; 35041123Smax.romanov@nginx.com nxt_http_request_t *r; 35051123Smax.romanov@nginx.com nxt_unit_response_t *resp; 35061131Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 35071123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 350888Smax.romanov@nginx.com 350988Smax.romanov@nginx.com b = msg->buf; 35101123Smax.romanov@nginx.com req_rpc_data = data; 351188Smax.romanov@nginx.com 351288Smax.romanov@nginx.com if (msg->size == 0) { 351388Smax.romanov@nginx.com b = NULL; 351488Smax.romanov@nginx.com } 351588Smax.romanov@nginx.com 35161123Smax.romanov@nginx.com r = req_rpc_data->request; 35171007Salexander.borisov@nginx.com if (nxt_slow_path(r == NULL)) { 3518570Smax.romanov@nginx.com return; 3519570Smax.romanov@nginx.com } 3520425Smax.romanov@nginx.com 35211007Salexander.borisov@nginx.com if (r->error) { 35221123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3523608Sigor@sysoev.ru return; 3524608Sigor@sysoev.ru } 3525608Sigor@sysoev.ru 352688Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 352788Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 352888Smax.romanov@nginx.com 35291007Salexander.borisov@nginx.com nxt_buf_chain_add(&b, nxt_http_buf_last(r)); 3530167Smax.romanov@nginx.com 35311123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3532425Smax.romanov@nginx.com 3533425Smax.romanov@nginx.com } else { 35341123Smax.romanov@nginx.com if (req_rpc_data->app != NULL && req_rpc_data->app->timeout != 0) { 35351007Salexander.borisov@nginx.com r->timer.handler = nxt_router_app_timeout; 35361123Smax.romanov@nginx.com r->timer_data = req_rpc_data; 35371123Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 35381123Smax.romanov@nginx.com req_rpc_data->app->timeout); 3539425Smax.romanov@nginx.com } 354088Smax.romanov@nginx.com } 354188Smax.romanov@nginx.com 354288Smax.romanov@nginx.com if (b == NULL) { 354388Smax.romanov@nginx.com return; 354488Smax.romanov@nginx.com } 354588Smax.romanov@nginx.com 3546206Smax.romanov@nginx.com if (msg->buf == b) { 3547206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3548206Smax.romanov@nginx.com msg->buf = NULL; 3549206Smax.romanov@nginx.com } 3550194Smax.romanov@nginx.com 3551431Sigor@sysoev.ru if (r->header_sent) { 3552431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3553431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3554277Sigor@sysoev.ru 355588Smax.romanov@nginx.com } else { 3556743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3557743Smax.romanov@nginx.com 3558743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3559743Smax.romanov@nginx.com goto fail; 3560743Smax.romanov@nginx.com } 3561743Smax.romanov@nginx.com 3562743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3563743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3564743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3565743Smax.romanov@nginx.com goto fail; 3566743Smax.romanov@nginx.com } 3567743Smax.romanov@nginx.com 35681126Smax.romanov@nginx.com field = NULL; 35691126Smax.romanov@nginx.com 3570743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 35711126Smax.romanov@nginx.com if (f->skip) { 35721126Smax.romanov@nginx.com continue; 35731126Smax.romanov@nginx.com } 35741126Smax.romanov@nginx.com 35751007Salexander.borisov@nginx.com field = nxt_list_add(r->resp.fields); 3576743Smax.romanov@nginx.com 3577743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3578743Smax.romanov@nginx.com goto fail; 3579743Smax.romanov@nginx.com } 3580743Smax.romanov@nginx.com 3581743Smax.romanov@nginx.com field->hash = f->hash; 35821126Smax.romanov@nginx.com field->skip = 0; 3583743Smax.romanov@nginx.com 3584743Smax.romanov@nginx.com field->name_length = f->name_length; 3585743Smax.romanov@nginx.com field->value_length = f->value_length; 3586743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3587743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3588743Smax.romanov@nginx.com 35891126Smax.romanov@nginx.com ret = nxt_http_field_process(field, &nxt_response_fields_hash, r); 35901126Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 35911126Smax.romanov@nginx.com goto fail; 35921126Smax.romanov@nginx.com } 35931126Smax.romanov@nginx.com 35941126Smax.romanov@nginx.com nxt_debug(task, "header%s: %*s: %*s", 35951126Smax.romanov@nginx.com (field->skip ? " skipped" : ""), 3596743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3597743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 35981126Smax.romanov@nginx.com 35991126Smax.romanov@nginx.com if (field->skip) { 36001126Smax.romanov@nginx.com r->resp.fields->last->nelts--; 36011126Smax.romanov@nginx.com } 3602743Smax.romanov@nginx.com } 36031007Salexander.borisov@nginx.com 3604743Smax.romanov@nginx.com r->status = resp->status; 3605743Smax.romanov@nginx.com 3606743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3607743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3608743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3609743Smax.romanov@nginx.com 3610743Smax.romanov@nginx.com } else { 3611743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3612743Smax.romanov@nginx.com } 3613743Smax.romanov@nginx.com 3614435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 3615435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3616435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3617507Smax.romanov@nginx.com 3618520Smax.romanov@nginx.com b = b->next; 3619520Smax.romanov@nginx.com } 3620520Smax.romanov@nginx.com 3621520Smax.romanov@nginx.com if (b != NULL) { 3622431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3623431Sigor@sysoev.ru } 3624431Sigor@sysoev.ru 36251148Sigor@sysoev.ru nxt_http_request_header_send(task, r, nxt_http_request_send_body); 36261127Smax.romanov@nginx.com 36271131Smax.romanov@nginx.com if (r->websocket_handshake 36281131Smax.romanov@nginx.com && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) 36291131Smax.romanov@nginx.com { 36301131Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, 36311131Smax.romanov@nginx.com req_rpc_data->req_app_link, 36321131Smax.romanov@nginx.com req_rpc_data); 36331131Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 36341131Smax.romanov@nginx.com goto fail; 36351131Smax.romanov@nginx.com } 36361131Smax.romanov@nginx.com 36371131Smax.romanov@nginx.com app_port = req_app_link->app_port; 36381131Smax.romanov@nginx.com 36391131Smax.romanov@nginx.com if (app_port == NULL && req_rpc_data->app_port != NULL) { 36401131Smax.romanov@nginx.com req_app_link->app_port = req_rpc_data->app_port; 36411131Smax.romanov@nginx.com app_port = req_app_link->app_port; 36421131Smax.romanov@nginx.com req_app_link->apr_action = req_rpc_data->apr_action; 36431131Smax.romanov@nginx.com 36441131Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 36451131Smax.romanov@nginx.com } 36461131Smax.romanov@nginx.com 36471131Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 36481131Smax.romanov@nginx.com goto fail; 36491131Smax.romanov@nginx.com } 36501131Smax.romanov@nginx.com 36511131Smax.romanov@nginx.com nxt_thread_mutex_lock(&req_rpc_data->app->mutex); 36521131Smax.romanov@nginx.com 36531131Smax.romanov@nginx.com nxt_queue_insert_tail(&app_port->active_websockets, 36541131Smax.romanov@nginx.com &req_app_link->link_port_websockets); 36551131Smax.romanov@nginx.com 36561131Smax.romanov@nginx.com nxt_thread_mutex_unlock(&req_rpc_data->app->mutex); 36571131Smax.romanov@nginx.com 36581131Smax.romanov@nginx.com nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE); 36591131Smax.romanov@nginx.com req_app_link->apr_action = NXT_APR_CLOSE; 36601131Smax.romanov@nginx.com 36611131Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD upgrade", 36621131Smax.romanov@nginx.com req_app_link->stream); 36631131Smax.romanov@nginx.com 36641131Smax.romanov@nginx.com r->state = &nxt_http_websocket; 36651131Smax.romanov@nginx.com 36661131Smax.romanov@nginx.com } else { 36671131Smax.romanov@nginx.com r->state = &nxt_http_request_send_state; 36681131Smax.romanov@nginx.com } 3669431Sigor@sysoev.ru } 3670431Sigor@sysoev.ru 3671431Sigor@sysoev.ru return; 3672431Sigor@sysoev.ru 3673431Sigor@sysoev.ru fail: 3674431Sigor@sysoev.ru 3675615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3676615Smax.romanov@nginx.com 36771123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3678431Sigor@sysoev.ru } 3679431Sigor@sysoev.ru 3680431Sigor@sysoev.ru 3681431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3682431Sigor@sysoev.ru nxt_aligned(64) = 3683431Sigor@sysoev.ru { 3684943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 3685431Sigor@sysoev.ru }; 3686431Sigor@sysoev.ru 3687431Sigor@sysoev.ru 3688431Sigor@sysoev.ru static void 3689431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3690431Sigor@sysoev.ru { 3691431Sigor@sysoev.ru nxt_buf_t *out; 3692431Sigor@sysoev.ru nxt_http_request_t *r; 3693431Sigor@sysoev.ru 3694431Sigor@sysoev.ru r = obj; 3695431Sigor@sysoev.ru 3696431Sigor@sysoev.ru out = r->out; 3697431Sigor@sysoev.ru 3698431Sigor@sysoev.ru if (out != NULL) { 3699431Sigor@sysoev.ru r->out = NULL; 3700431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 370188Smax.romanov@nginx.com } 370288Smax.romanov@nginx.com } 370388Smax.romanov@nginx.com 3704277Sigor@sysoev.ru 3705318Smax.romanov@nginx.com static void 3706318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3707318Smax.romanov@nginx.com void *data) 3708318Smax.romanov@nginx.com { 37091123Smax.romanov@nginx.com nxt_int_t res; 37101123Smax.romanov@nginx.com nxt_port_t *port; 37111123Smax.romanov@nginx.com nxt_bool_t cancelled; 37121123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 37131123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 37141123Smax.romanov@nginx.com 37151123Smax.romanov@nginx.com req_rpc_data = data; 37161123Smax.romanov@nginx.com 37171123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 37181123Smax.romanov@nginx.com 37191123Smax.romanov@nginx.com if (req_app_link != NULL) { 37201123Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &req_app_link->msg_info, 37211123Smax.romanov@nginx.com req_app_link->stream); 3722425Smax.romanov@nginx.com if (cancelled) { 37231123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 37241123Smax.romanov@nginx.com 37251123Smax.romanov@nginx.com res = nxt_router_app_port(task, req_rpc_data->app, req_app_link); 3726425Smax.romanov@nginx.com 3727425Smax.romanov@nginx.com if (res == NXT_OK) { 37281123Smax.romanov@nginx.com port = req_app_link->app_port; 3729425Smax.romanov@nginx.com 3730551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 37311123Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, 37321123Smax.romanov@nginx.com "port is NULL in cancelled req_app_link"); 3733551Smax.romanov@nginx.com return; 3734551Smax.romanov@nginx.com } 3735425Smax.romanov@nginx.com 37361123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, 37371123Smax.romanov@nginx.com req_rpc_data, port->pid); 37381123Smax.romanov@nginx.com 37391123Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 3740425Smax.romanov@nginx.com } 3741425Smax.romanov@nginx.com 3742425Smax.romanov@nginx.com msg->port_msg.last = 0; 3743425Smax.romanov@nginx.com 3744425Smax.romanov@nginx.com return; 3745425Smax.romanov@nginx.com } 3746425Smax.romanov@nginx.com } 3747425Smax.romanov@nginx.com 37481123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 37491123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 3750616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3751616Smax.romanov@nginx.com } 3752318Smax.romanov@nginx.com 37531123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3754318Smax.romanov@nginx.com } 3755318Smax.romanov@nginx.com 3756318Smax.romanov@nginx.com 3757141Smax.romanov@nginx.com static void 3758343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3759343Smax.romanov@nginx.com void *data) 3760192Smax.romanov@nginx.com { 3761753Smax.romanov@nginx.com nxt_app_t *app; 3762753Smax.romanov@nginx.com nxt_port_t *port; 3763753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3764753Smax.romanov@nginx.com 3765753Smax.romanov@nginx.com app_joint = data; 3766347Smax.romanov@nginx.com port = msg->u.new_port; 3767343Smax.romanov@nginx.com 3768753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3769343Smax.romanov@nginx.com nxt_assert(port != NULL); 3770343Smax.romanov@nginx.com 3771753Smax.romanov@nginx.com app = app_joint->app; 3772753Smax.romanov@nginx.com 3773753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3774753Smax.romanov@nginx.com 3775753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3776753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3777753Smax.romanov@nginx.com 3778753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3779753Smax.romanov@nginx.com 3780753Smax.romanov@nginx.com return; 3781753Smax.romanov@nginx.com } 3782753Smax.romanov@nginx.com 3783343Smax.romanov@nginx.com port->app = app; 3784343Smax.romanov@nginx.com 3785343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3786343Smax.romanov@nginx.com 3787507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3788507Smax.romanov@nginx.com 3789507Smax.romanov@nginx.com app->pending_processes--; 3790507Smax.romanov@nginx.com app->processes++; 3791343Smax.romanov@nginx.com 3792343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3793343Smax.romanov@nginx.com 3794507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3795507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3796343Smax.romanov@nginx.com 37971123Smax.romanov@nginx.com nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT); 3798192Smax.romanov@nginx.com } 3799192Smax.romanov@nginx.com 3800192Smax.romanov@nginx.com 3801192Smax.romanov@nginx.com static void 3802343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3803343Smax.romanov@nginx.com void *data) 3804192Smax.romanov@nginx.com { 38051123Smax.romanov@nginx.com nxt_app_t *app; 38061123Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 38071123Smax.romanov@nginx.com nxt_queue_link_t *lnk; 38081123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 3809343Smax.romanov@nginx.com 3810753Smax.romanov@nginx.com app_joint = data; 3811753Smax.romanov@nginx.com 3812753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3813753Smax.romanov@nginx.com 3814753Smax.romanov@nginx.com app = app_joint->app; 3815753Smax.romanov@nginx.com 3816753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3817753Smax.romanov@nginx.com 3818753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3819753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 3820753Smax.romanov@nginx.com 3821753Smax.romanov@nginx.com return; 3822753Smax.romanov@nginx.com } 3823343Smax.romanov@nginx.com 3824343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 3825343Smax.romanov@nginx.com 3826343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3827343Smax.romanov@nginx.com 3828507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3829507Smax.romanov@nginx.com 3830507Smax.romanov@nginx.com app->pending_processes--; 3831318Smax.romanov@nginx.com 3832318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 3833318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 3834318Smax.romanov@nginx.com nxt_queue_remove(lnk); 3835343Smax.romanov@nginx.com lnk->next = NULL; 3836318Smax.romanov@nginx.com 38371123Smax.romanov@nginx.com req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t, 38381123Smax.romanov@nginx.com link_app_requests); 3839318Smax.romanov@nginx.com 3840343Smax.romanov@nginx.com } else { 38411123Smax.romanov@nginx.com req_app_link = NULL; 3842343Smax.romanov@nginx.com } 3843343Smax.romanov@nginx.com 3844343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3845343Smax.romanov@nginx.com 38461123Smax.romanov@nginx.com if (req_app_link != NULL) { 3847318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 38481123Smax.romanov@nginx.com &app->name, app, req_app_link->stream); 38491123Smax.romanov@nginx.com 38501123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 38511123Smax.romanov@nginx.com "Failed to start application process"); 38521123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 3853318Smax.romanov@nginx.com } 3854192Smax.romanov@nginx.com } 3855192Smax.romanov@nginx.com 3856753Smax.romanov@nginx.com nxt_inline nxt_port_t * 3857753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app); 3858192Smax.romanov@nginx.com 3859343Smax.romanov@nginx.com void 3860343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 3861141Smax.romanov@nginx.com { 3862343Smax.romanov@nginx.com int c; 3863343Smax.romanov@nginx.com 3864343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 3865343Smax.romanov@nginx.com 3866343Smax.romanov@nginx.com if (i < 0 && c == -i) { 3867343Smax.romanov@nginx.com 3868753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 3869753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 3870753Smax.romanov@nginx.com 3871753Smax.romanov@nginx.com } else { 3872753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 3873753Smax.romanov@nginx.com } 3874163Smax.romanov@nginx.com } 3875343Smax.romanov@nginx.com } 3876343Smax.romanov@nginx.com 3877343Smax.romanov@nginx.com 3878424Smax.romanov@nginx.com nxt_inline nxt_bool_t 3879424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 3880424Smax.romanov@nginx.com { 3881424Smax.romanov@nginx.com nxt_port_t *port; 3882424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3883424Smax.romanov@nginx.com 3884424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3885424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3886424Smax.romanov@nginx.com 3887424Smax.romanov@nginx.com return port->app_pending_responses > 0; 3888424Smax.romanov@nginx.com } 3889424Smax.romanov@nginx.com 3890424Smax.romanov@nginx.com 3891343Smax.romanov@nginx.com nxt_inline nxt_port_t * 3892427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 3893343Smax.romanov@nginx.com { 3894343Smax.romanov@nginx.com nxt_port_t *port; 3895343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3896343Smax.romanov@nginx.com 3897343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3898343Smax.romanov@nginx.com nxt_queue_remove(lnk); 3899343Smax.romanov@nginx.com 3900343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3901343Smax.romanov@nginx.com 3902424Smax.romanov@nginx.com port->app_pending_responses++; 3903424Smax.romanov@nginx.com 3904507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3905507Smax.romanov@nginx.com app->idle_processes--; 3906507Smax.romanov@nginx.com 3907507Smax.romanov@nginx.com if (port->idle_start == 0) { 3908507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 3909507Smax.romanov@nginx.com 3910507Smax.romanov@nginx.com } else { 3911507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 3912507Smax.romanov@nginx.com 3913507Smax.romanov@nginx.com port->idle_start = 0; 3914507Smax.romanov@nginx.com } 3915507Smax.romanov@nginx.com } 3916507Smax.romanov@nginx.com 3917428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 3918428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3919428Smax.romanov@nginx.com && (app->max_requests == 0 3920428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3921428Smax.romanov@nginx.com < app->max_requests)) 3922277Sigor@sysoev.ru { 3923343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 3924343Smax.romanov@nginx.com 3925425Smax.romanov@nginx.com nxt_port_inc_use(port); 3926425Smax.romanov@nginx.com 3927343Smax.romanov@nginx.com } else { 3928343Smax.romanov@nginx.com lnk->next = NULL; 3929167Smax.romanov@nginx.com } 3930167Smax.romanov@nginx.com 3931343Smax.romanov@nginx.com return port; 3932163Smax.romanov@nginx.com } 3933163Smax.romanov@nginx.com 3934163Smax.romanov@nginx.com 3935507Smax.romanov@nginx.com nxt_inline nxt_port_t * 3936507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 3937141Smax.romanov@nginx.com { 3938343Smax.romanov@nginx.com nxt_port_t *port; 3939141Smax.romanov@nginx.com 3940141Smax.romanov@nginx.com port = NULL; 3941141Smax.romanov@nginx.com 3942141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3943141Smax.romanov@nginx.com 3944343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 3945343Smax.romanov@nginx.com 3946424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3947343Smax.romanov@nginx.com port = NULL; 3948343Smax.romanov@nginx.com 3949343Smax.romanov@nginx.com continue; 3950343Smax.romanov@nginx.com } 3951343Smax.romanov@nginx.com 3952507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 3953507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3954507Smax.romanov@nginx.com 3955507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3956507Smax.romanov@nginx.com app->idle_processes--; 3957507Smax.romanov@nginx.com } 3958507Smax.romanov@nginx.com 3959507Smax.romanov@nginx.com port->app = NULL; 3960507Smax.romanov@nginx.com app->processes--; 3961343Smax.romanov@nginx.com 3962343Smax.romanov@nginx.com break; 3963343Smax.romanov@nginx.com 3964343Smax.romanov@nginx.com } nxt_queue_loop; 3965141Smax.romanov@nginx.com 3966141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3967141Smax.romanov@nginx.com 3968141Smax.romanov@nginx.com return port; 3969141Smax.romanov@nginx.com } 3970141Smax.romanov@nginx.com 3971141Smax.romanov@nginx.com 3972141Smax.romanov@nginx.com static void 3973753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 3974507Smax.romanov@nginx.com { 3975753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 3976507Smax.romanov@nginx.com 3977507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3978507Smax.romanov@nginx.com 3979753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3980507Smax.romanov@nginx.com } 3981507Smax.romanov@nginx.com 3982507Smax.romanov@nginx.com 3983507Smax.romanov@nginx.com static void 3984343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3985141Smax.romanov@nginx.com { 39861123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 39871123Smax.romanov@nginx.com 39881123Smax.romanov@nginx.com req_app_link = data; 3989538Svbart@nginx.com 3990538Svbart@nginx.com #if (NXT_DEBUG) 3991538Svbart@nginx.com { 3992538Svbart@nginx.com nxt_app_t *app; 3993538Svbart@nginx.com 3994343Smax.romanov@nginx.com app = obj; 3995141Smax.romanov@nginx.com 3996141Smax.romanov@nginx.com nxt_assert(app != NULL); 39971123Smax.romanov@nginx.com nxt_assert(req_app_link != NULL); 39981123Smax.romanov@nginx.com nxt_assert(req_app_link->app_port != NULL); 3999343Smax.romanov@nginx.com 4000343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 40011123Smax.romanov@nginx.com &app->name, app, req_app_link->stream); 4002538Svbart@nginx.com } 4003538Svbart@nginx.com #endif 4004343Smax.romanov@nginx.com 40051123Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 4006343Smax.romanov@nginx.com } 4007343Smax.romanov@nginx.com 4008343Smax.romanov@nginx.com 4009343Smax.romanov@nginx.com static void 4010343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 40111123Smax.romanov@nginx.com nxt_apr_action_t action) 4012343Smax.romanov@nginx.com { 40131123Smax.romanov@nginx.com int inc_use; 40141123Smax.romanov@nginx.com uint32_t dec_pending, got_response; 4015427Smax.romanov@nginx.com nxt_app_t *app; 4016507Smax.romanov@nginx.com nxt_bool_t port_unchained; 4017507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 4018427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 40191123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, *pending_ra, *re_ra; 4020427Smax.romanov@nginx.com nxt_port_select_state_t state; 4021343Smax.romanov@nginx.com 4022343Smax.romanov@nginx.com nxt_assert(port != NULL); 4023343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 4024343Smax.romanov@nginx.com 40251123Smax.romanov@nginx.com req_app_link = NULL; 4026427Smax.romanov@nginx.com 4027343Smax.romanov@nginx.com app = port->app; 4028343Smax.romanov@nginx.com 40291123Smax.romanov@nginx.com inc_use = 0; 40301123Smax.romanov@nginx.com dec_pending = 0; 40311123Smax.romanov@nginx.com got_response = 0; 40321123Smax.romanov@nginx.com 40331123Smax.romanov@nginx.com switch (action) { 40341123Smax.romanov@nginx.com case NXT_APR_NEW_PORT: 40351123Smax.romanov@nginx.com break; 40361123Smax.romanov@nginx.com case NXT_APR_REQUEST_FAILED: 40371123Smax.romanov@nginx.com dec_pending = 1; 40381123Smax.romanov@nginx.com inc_use = -1; 40391123Smax.romanov@nginx.com break; 40401123Smax.romanov@nginx.com case NXT_APR_GOT_RESPONSE: 40411123Smax.romanov@nginx.com dec_pending = 1; 40421123Smax.romanov@nginx.com got_response = 1; 40431123Smax.romanov@nginx.com inc_use = -1; 40441123Smax.romanov@nginx.com break; 40451131Smax.romanov@nginx.com case NXT_APR_UPGRADE: 40461131Smax.romanov@nginx.com dec_pending = 1; 40471131Smax.romanov@nginx.com got_response = 1; 40481131Smax.romanov@nginx.com break; 40491123Smax.romanov@nginx.com case NXT_APR_CLOSE: 40501123Smax.romanov@nginx.com inc_use = -1; 40511123Smax.romanov@nginx.com break; 40521123Smax.romanov@nginx.com } 40531123Smax.romanov@nginx.com 4054343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4055343Smax.romanov@nginx.com 40561123Smax.romanov@nginx.com port->app_pending_responses -= dec_pending; 4057343Smax.romanov@nginx.com port->app_responses += got_response; 4058343Smax.romanov@nginx.com 4059427Smax.romanov@nginx.com if (port->pair[1] != -1 4060426Smax.romanov@nginx.com && (app->max_pending_responses == 0 4061428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 4062428Smax.romanov@nginx.com && (app->max_requests == 0 4063428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 4064428Smax.romanov@nginx.com < app->max_requests)) 4065343Smax.romanov@nginx.com { 4066424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 4067424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 4068424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 4069424Smax.romanov@nginx.com 4070424Smax.romanov@nginx.com } else { 4071424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 4072424Smax.romanov@nginx.com } 4073424Smax.romanov@nginx.com 4074425Smax.romanov@nginx.com nxt_port_inc_use(port); 4075424Smax.romanov@nginx.com 4076424Smax.romanov@nginx.com } else { 4077424Smax.romanov@nginx.com if (port->app_pending_responses == 0 4078424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 4079424Smax.romanov@nginx.com { 4080424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 4081424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 4082424Smax.romanov@nginx.com } 4083424Smax.romanov@nginx.com } 4084141Smax.romanov@nginx.com } 4085141Smax.romanov@nginx.com 4086427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 4087426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 4088343Smax.romanov@nginx.com { 4089141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 4090141Smax.romanov@nginx.com nxt_queue_remove(lnk); 4091343Smax.romanov@nginx.com lnk->next = NULL; 4092141Smax.romanov@nginx.com 40931123Smax.romanov@nginx.com req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t, 40941123Smax.romanov@nginx.com link_app_requests); 40951123Smax.romanov@nginx.com 40961123Smax.romanov@nginx.com req_app_link->app_port = nxt_router_pop_first_port(app); 40971123Smax.romanov@nginx.com 40981123Smax.romanov@nginx.com if (req_app_link->app_port->app_pending_responses > 1) { 40991123Smax.romanov@nginx.com nxt_request_app_link_pending(task, app, req_app_link); 4100425Smax.romanov@nginx.com } 4101425Smax.romanov@nginx.com } 4102425Smax.romanov@nginx.com 4103427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 41041123Smax.romanov@nginx.com if (dec_pending > 0 4105425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 4106425Smax.romanov@nginx.com { 4107425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4108425Smax.romanov@nginx.com nxt_queue_remove(lnk); 4109425Smax.romanov@nginx.com lnk->next = NULL; 4110425Smax.romanov@nginx.com 41111123Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 4112427Smax.romanov@nginx.com link_port_pending); 4113427Smax.romanov@nginx.com 4114427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4115427Smax.romanov@nginx.com 4116427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 4117427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 4118425Smax.romanov@nginx.com 4119425Smax.romanov@nginx.com } else { 4120427Smax.romanov@nginx.com pending_ra = NULL; 4121141Smax.romanov@nginx.com } 4122141Smax.romanov@nginx.com 4123427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 4124427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 4125427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 4126427Smax.romanov@nginx.com 41271123Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 41281123Smax.romanov@nginx.com link_app_pending); 4129427Smax.romanov@nginx.com 4130427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 4131427Smax.romanov@nginx.com 4132427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 4133427Smax.romanov@nginx.com &app->name, re_ra->stream); 4134427Smax.romanov@nginx.com 4135427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 4136427Smax.romanov@nginx.com re_ra->stream); 4137427Smax.romanov@nginx.com 4138427Smax.romanov@nginx.com if (cancelled) { 41391123Smax.romanov@nginx.com nxt_request_app_link_inc_use(re_ra); 41401123Smax.romanov@nginx.com 41411123Smax.romanov@nginx.com state.req_app_link = re_ra; 4142427Smax.romanov@nginx.com state.app = app; 4143427Smax.romanov@nginx.com 4144427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4145427Smax.romanov@nginx.com 4146427Smax.romanov@nginx.com goto re_ra_cancelled; 4147427Smax.romanov@nginx.com } 4148427Smax.romanov@nginx.com } 4149427Smax.romanov@nginx.com } 4150427Smax.romanov@nginx.com 4151427Smax.romanov@nginx.com re_ra = NULL; 4152427Smax.romanov@nginx.com 4153427Smax.romanov@nginx.com re_ra_cancelled: 4154427Smax.romanov@nginx.com 4155753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 4156753Smax.romanov@nginx.com && port->app_pending_responses == 0 4157753Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 4158367Smax.romanov@nginx.com 4159507Smax.romanov@nginx.com if (send_quit) { 4160507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 4161507Smax.romanov@nginx.com 4162507Smax.romanov@nginx.com port->app = NULL; 4163507Smax.romanov@nginx.com app->processes--; 4164507Smax.romanov@nginx.com 4165507Smax.romanov@nginx.com } else { 4166507Smax.romanov@nginx.com port_unchained = 0; 4167507Smax.romanov@nginx.com } 4168507Smax.romanov@nginx.com 4169507Smax.romanov@nginx.com adjust_idle_timer = 0; 4170507Smax.romanov@nginx.com 41711131Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0 41721131Smax.romanov@nginx.com && nxt_queue_is_empty(&port->active_websockets) 41731131Smax.romanov@nginx.com && port->idle_link.next == NULL) 41741131Smax.romanov@nginx.com { 4175507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 4176507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 4177507Smax.romanov@nginx.com { 4178507Smax.romanov@nginx.com adjust_idle_timer = 1; 4179507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 4180507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 4181507Smax.romanov@nginx.com } 4182507Smax.romanov@nginx.com 4183507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 4184507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 4185507Smax.romanov@nginx.com 4186507Smax.romanov@nginx.com } else { 4187507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 4188507Smax.romanov@nginx.com 4189507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 4190507Smax.romanov@nginx.com } 4191507Smax.romanov@nginx.com 4192507Smax.romanov@nginx.com app->idle_processes++; 4193507Smax.romanov@nginx.com } 4194507Smax.romanov@nginx.com 4195343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4196343Smax.romanov@nginx.com 4197507Smax.romanov@nginx.com if (adjust_idle_timer) { 4198507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4199507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4200507Smax.romanov@nginx.com } 4201507Smax.romanov@nginx.com 4202427Smax.romanov@nginx.com if (pending_ra != NULL) { 42031123Smax.romanov@nginx.com nxt_request_app_link_use(task, pending_ra, -1); 4204427Smax.romanov@nginx.com } 4205427Smax.romanov@nginx.com 4206427Smax.romanov@nginx.com if (re_ra != NULL) { 4207427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 4208427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4209427Smax.romanov@nginx.com nxt_router_app_process_request, 4210427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 4211427Smax.romanov@nginx.com } 4212425Smax.romanov@nginx.com } 4213425Smax.romanov@nginx.com 42141123Smax.romanov@nginx.com if (req_app_link != NULL) { 42151123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 4216425Smax.romanov@nginx.com 4217343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4218343Smax.romanov@nginx.com nxt_router_app_process_request, 42191123Smax.romanov@nginx.com &task->thread->engine->task, app, req_app_link); 4220343Smax.romanov@nginx.com 4221343Smax.romanov@nginx.com goto adjust_use; 4222343Smax.romanov@nginx.com } 4223343Smax.romanov@nginx.com 4224343Smax.romanov@nginx.com /* ? */ 4225163Smax.romanov@nginx.com if (port->pair[1] == -1) { 4226343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 4227343Smax.romanov@nginx.com &app->name, app, port, port->pid); 4228343Smax.romanov@nginx.com 4229343Smax.romanov@nginx.com goto adjust_use; 4230163Smax.romanov@nginx.com } 4231163Smax.romanov@nginx.com 4232367Smax.romanov@nginx.com if (send_quit) { 4233507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 4234167Smax.romanov@nginx.com &app->name, app); 4235163Smax.romanov@nginx.com 4236163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 4237163Smax.romanov@nginx.com -1, 0, 0, NULL); 4238163Smax.romanov@nginx.com 4239507Smax.romanov@nginx.com if (port_unchained) { 4240507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4241507Smax.romanov@nginx.com } 4242507Smax.romanov@nginx.com 4243343Smax.romanov@nginx.com goto adjust_use; 4244163Smax.romanov@nginx.com } 4245163Smax.romanov@nginx.com 4246167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4247167Smax.romanov@nginx.com &app->name, app); 4248141Smax.romanov@nginx.com 4249343Smax.romanov@nginx.com adjust_use: 4250343Smax.romanov@nginx.com 42511123Smax.romanov@nginx.com nxt_port_use(task, port, inc_use); 4252141Smax.romanov@nginx.com } 4253141Smax.romanov@nginx.com 4254141Smax.romanov@nginx.com 4255343Smax.romanov@nginx.com void 4256343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4257141Smax.romanov@nginx.com { 4258507Smax.romanov@nginx.com nxt_app_t *app; 4259507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4260507Smax.romanov@nginx.com nxt_port_t *idle_port; 4261507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4262141Smax.romanov@nginx.com 4263141Smax.romanov@nginx.com app = port->app; 4264343Smax.romanov@nginx.com 4265343Smax.romanov@nginx.com nxt_assert(app != NULL); 4266141Smax.romanov@nginx.com 4267141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4268141Smax.romanov@nginx.com 4269507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4270507Smax.romanov@nginx.com 4271507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4272507Smax.romanov@nginx.com app->idle_processes--; 4273507Smax.romanov@nginx.com 4274507Smax.romanov@nginx.com if (port->idle_start == 0 4275507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4276507Smax.romanov@nginx.com { 4277507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4278507Smax.romanov@nginx.com 4279507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4280507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4281507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4282507Smax.romanov@nginx.com 4283507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4284507Smax.romanov@nginx.com 4285507Smax.romanov@nginx.com idle_port->idle_start = 0; 4286507Smax.romanov@nginx.com } 4287343Smax.romanov@nginx.com } 4288343Smax.romanov@nginx.com 4289507Smax.romanov@nginx.com app->processes--; 4290507Smax.romanov@nginx.com 4291753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4292507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 4293507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 4294507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 4295507Smax.romanov@nginx.com 4296507Smax.romanov@nginx.com if (start_process) { 4297507Smax.romanov@nginx.com app->pending_processes++; 4298163Smax.romanov@nginx.com } 4299141Smax.romanov@nginx.com 4300141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4301163Smax.romanov@nginx.com 4302507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4303343Smax.romanov@nginx.com 4304343Smax.romanov@nginx.com if (unchain) { 4305343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4306163Smax.romanov@nginx.com } 4307163Smax.romanov@nginx.com 4308507Smax.romanov@nginx.com if (start_process) { 4309507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4310507Smax.romanov@nginx.com } 4311507Smax.romanov@nginx.com } 4312507Smax.romanov@nginx.com 4313507Smax.romanov@nginx.com 4314507Smax.romanov@nginx.com static void 4315507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4316507Smax.romanov@nginx.com { 4317507Smax.romanov@nginx.com nxt_app_t *app; 4318507Smax.romanov@nginx.com nxt_bool_t queued; 4319507Smax.romanov@nginx.com nxt_port_t *port; 4320507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4321507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4322507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4323507Smax.romanov@nginx.com 4324507Smax.romanov@nginx.com app = obj; 4325507Smax.romanov@nginx.com queued = (data == app); 4326507Smax.romanov@nginx.com 4327507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4328507Smax.romanov@nginx.com &app->name, queued); 4329507Smax.romanov@nginx.com 4330507Smax.romanov@nginx.com engine = task->thread->engine; 4331507Smax.romanov@nginx.com 4332507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 4333507Smax.romanov@nginx.com 4334811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 4335507Smax.romanov@nginx.com timeout = 0; 4336507Smax.romanov@nginx.com 4337507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4338507Smax.romanov@nginx.com 4339507Smax.romanov@nginx.com if (queued) { 4340507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 4341343Smax.romanov@nginx.com } 4342507Smax.romanov@nginx.com 4343507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 4344507Smax.romanov@nginx.com 4345551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4346507Smax.romanov@nginx.com 4347507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 4348507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 4349507Smax.romanov@nginx.com 4350507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 4351507Smax.romanov@nginx.com 4352507Smax.romanov@nginx.com if (timeout > threshold) { 4353507Smax.romanov@nginx.com break; 4354507Smax.romanov@nginx.com } 4355507Smax.romanov@nginx.com 4356507Smax.romanov@nginx.com nxt_queue_remove(lnk); 4357507Smax.romanov@nginx.com lnk->next = NULL; 4358507Smax.romanov@nginx.com 4359507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4360507Smax.romanov@nginx.com 4361507Smax.romanov@nginx.com app->idle_processes--; 4362507Smax.romanov@nginx.com app->processes--; 4363507Smax.romanov@nginx.com port->app = NULL; 4364507Smax.romanov@nginx.com 4365507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4366507Smax.romanov@nginx.com 4367507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4368507Smax.romanov@nginx.com &app->name, port->pid); 4369507Smax.romanov@nginx.com 4370507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4371507Smax.romanov@nginx.com 4372507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4373507Smax.romanov@nginx.com 4374507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4375507Smax.romanov@nginx.com } 4376507Smax.romanov@nginx.com 4377507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4378507Smax.romanov@nginx.com 4379507Smax.romanov@nginx.com if (timeout > threshold) { 4380753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4381507Smax.romanov@nginx.com 4382507Smax.romanov@nginx.com } else { 4383753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4384507Smax.romanov@nginx.com } 4385507Smax.romanov@nginx.com 4386507Smax.romanov@nginx.com if (queued) { 4387507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4388507Smax.romanov@nginx.com } 4389507Smax.romanov@nginx.com } 4390507Smax.romanov@nginx.com 4391507Smax.romanov@nginx.com 4392507Smax.romanov@nginx.com static void 4393507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4394507Smax.romanov@nginx.com { 4395753Smax.romanov@nginx.com nxt_timer_t *timer; 4396753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4397507Smax.romanov@nginx.com 4398507Smax.romanov@nginx.com timer = obj; 4399753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4400753Smax.romanov@nginx.com 4401753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4402753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4403753Smax.romanov@nginx.com } 4404753Smax.romanov@nginx.com } 4405753Smax.romanov@nginx.com 4406753Smax.romanov@nginx.com 4407753Smax.romanov@nginx.com static void 4408753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4409753Smax.romanov@nginx.com { 4410753Smax.romanov@nginx.com nxt_timer_t *timer; 4411753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4412753Smax.romanov@nginx.com 4413753Smax.romanov@nginx.com timer = obj; 4414753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4415753Smax.romanov@nginx.com 4416753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4417507Smax.romanov@nginx.com } 4418507Smax.romanov@nginx.com 4419507Smax.romanov@nginx.com 4420507Smax.romanov@nginx.com static void 4421753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4422507Smax.romanov@nginx.com { 4423753Smax.romanov@nginx.com nxt_app_t *app; 4424753Smax.romanov@nginx.com nxt_port_t *port; 4425753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4426753Smax.romanov@nginx.com 4427753Smax.romanov@nginx.com app_joint = obj; 4428753Smax.romanov@nginx.com app = app_joint->app; 4429753Smax.romanov@nginx.com 4430753Smax.romanov@nginx.com for ( ;; ) { 4431753Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 4432753Smax.romanov@nginx.com if (port == NULL) { 4433753Smax.romanov@nginx.com break; 4434753Smax.romanov@nginx.com } 4435753Smax.romanov@nginx.com 4436753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4437753Smax.romanov@nginx.com 4438753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4439753Smax.romanov@nginx.com 4440753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4441753Smax.romanov@nginx.com } 4442753Smax.romanov@nginx.com 4443753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 4444753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4445753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 4446753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4447753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4448753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4449753Smax.romanov@nginx.com 4450753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 4451753Smax.romanov@nginx.com nxt_free(app); 4452753Smax.romanov@nginx.com 4453753Smax.romanov@nginx.com app_joint->app = NULL; 4454753Smax.romanov@nginx.com 4455753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4456753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4457753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4458753Smax.romanov@nginx.com 4459753Smax.romanov@nginx.com } else { 4460753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4461753Smax.romanov@nginx.com } 4462141Smax.romanov@nginx.com } 4463141Smax.romanov@nginx.com 4464141Smax.romanov@nginx.com 4465427Smax.romanov@nginx.com static void 4466427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 4467141Smax.romanov@nginx.com { 44681123Smax.romanov@nginx.com nxt_app_t *app; 44691123Smax.romanov@nginx.com nxt_bool_t can_start_process; 44701123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 44711123Smax.romanov@nginx.com 44721123Smax.romanov@nginx.com req_app_link = state->req_app_link; 4473427Smax.romanov@nginx.com app = state->app; 4474427Smax.romanov@nginx.com 4475427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 4476343Smax.romanov@nginx.com 44771123Smax.romanov@nginx.com if (nxt_queue_chk_remove(&req_app_link->link_app_requests)) 4478425Smax.romanov@nginx.com { 44791123Smax.romanov@nginx.com nxt_request_app_link_dec_use(req_app_link); 44801123Smax.romanov@nginx.com } 44811123Smax.romanov@nginx.com 44821123Smax.romanov@nginx.com if (nxt_queue_chk_remove(&req_app_link->link_port_pending)) 4483425Smax.romanov@nginx.com { 44841123Smax.romanov@nginx.com nxt_assert(req_app_link->link_app_pending.next != NULL); 44851123Smax.romanov@nginx.com 44861123Smax.romanov@nginx.com nxt_queue_remove(&req_app_link->link_app_pending); 44871123Smax.romanov@nginx.com req_app_link->link_app_pending.next = NULL; 44881123Smax.romanov@nginx.com 44891123Smax.romanov@nginx.com nxt_request_app_link_dec_use(req_app_link); 44901123Smax.romanov@nginx.com } 44911123Smax.romanov@nginx.com 44921123Smax.romanov@nginx.com state->failed_port = req_app_link->app_port; 44931123Smax.romanov@nginx.com 44941123Smax.romanov@nginx.com if (req_app_link->app_port != NULL) { 4495427Smax.romanov@nginx.com state->failed_port_use_delta--; 4496427Smax.romanov@nginx.com 4497427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 4498427Smax.romanov@nginx.com 4499427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 4500427Smax.romanov@nginx.com state->failed_port_use_delta--; 4501427Smax.romanov@nginx.com } 4502427Smax.romanov@nginx.com 45031123Smax.romanov@nginx.com req_app_link->app_port = NULL; 4504427Smax.romanov@nginx.com } 4505427Smax.romanov@nginx.com 4506507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 4507507Smax.romanov@nginx.com 4508427Smax.romanov@nginx.com state->port = NULL; 4509507Smax.romanov@nginx.com state->start_process = 0; 4510427Smax.romanov@nginx.com 4511427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 4512507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 4513427Smax.romanov@nginx.com { 45141123Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, req_app_link, 45151123Smax.romanov@nginx.com req_app_link->req_rpc_data); 45161123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4517427Smax.romanov@nginx.com goto fail; 4518427Smax.romanov@nginx.com } 4519427Smax.romanov@nginx.com 4520427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 45211123Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, 45221123Smax.romanov@nginx.com &req_app_link->link_app_requests); 4523427Smax.romanov@nginx.com 4524427Smax.romanov@nginx.com } else { 45251123Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, 45261123Smax.romanov@nginx.com &req_app_link->link_app_requests); 4527427Smax.romanov@nginx.com } 4528427Smax.romanov@nginx.com 45291123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 45301123Smax.romanov@nginx.com 45311123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD enqueue to app->requests", 45321123Smax.romanov@nginx.com req_app_link->stream); 4533427Smax.romanov@nginx.com 4534507Smax.romanov@nginx.com if (can_start_process) { 4535507Smax.romanov@nginx.com app->pending_processes++; 4536507Smax.romanov@nginx.com state->start_process = 1; 4537425Smax.romanov@nginx.com } 4538425Smax.romanov@nginx.com 4539425Smax.romanov@nginx.com } else { 4540427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 4541427Smax.romanov@nginx.com 4542427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 45431123Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, req_app_link, 45441123Smax.romanov@nginx.com req_app_link->req_rpc_data); 45451123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4546427Smax.romanov@nginx.com goto fail; 4547351Smax.romanov@nginx.com } 4548427Smax.romanov@nginx.com 45491123Smax.romanov@nginx.com req_app_link->app_port = state->port; 45501123Smax.romanov@nginx.com 45511123Smax.romanov@nginx.com nxt_request_app_link_pending(task, app, req_app_link); 4552425Smax.romanov@nginx.com } 4553507Smax.romanov@nginx.com 4554507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 4555507Smax.romanov@nginx.com app->pending_processes++; 4556507Smax.romanov@nginx.com state->start_process = 1; 4557507Smax.romanov@nginx.com } 4558343Smax.romanov@nginx.com } 4559343Smax.romanov@nginx.com 4560427Smax.romanov@nginx.com fail: 4561427Smax.romanov@nginx.com 45621123Smax.romanov@nginx.com state->shared_ra = req_app_link; 4563427Smax.romanov@nginx.com } 4564427Smax.romanov@nginx.com 4565427Smax.romanov@nginx.com 4566427Smax.romanov@nginx.com static nxt_int_t 4567427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 4568427Smax.romanov@nginx.com { 45691123Smax.romanov@nginx.com nxt_int_t res; 45701123Smax.romanov@nginx.com nxt_app_t *app; 45711123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 45721123Smax.romanov@nginx.com 45731123Smax.romanov@nginx.com req_app_link = state->shared_ra; 4574427Smax.romanov@nginx.com app = state->app; 4575427Smax.romanov@nginx.com 4576427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 4577427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 4578425Smax.romanov@nginx.com } 4579425Smax.romanov@nginx.com 45801123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4581427Smax.romanov@nginx.com if (state->port != NULL) { 4582427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 4583425Smax.romanov@nginx.com } 4584425Smax.romanov@nginx.com 45851123Smax.romanov@nginx.com nxt_request_app_link_error(state->req_app_link, 500, 4586427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 45871123Smax.romanov@nginx.com nxt_request_app_link_use(task, state->req_app_link, -1); 4588427Smax.romanov@nginx.com 4589351Smax.romanov@nginx.com return NXT_ERROR; 4590351Smax.romanov@nginx.com } 4591351Smax.romanov@nginx.com 4592427Smax.romanov@nginx.com if (state->port != NULL) { 4593343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 4594163Smax.romanov@nginx.com 45951123Smax.romanov@nginx.com req_app_link->app_port = state->port; 4596343Smax.romanov@nginx.com 4597507Smax.romanov@nginx.com if (state->start_process) { 4598507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4599507Smax.romanov@nginx.com } 4600507Smax.romanov@nginx.com 4601141Smax.romanov@nginx.com return NXT_OK; 4602141Smax.romanov@nginx.com } 4603141Smax.romanov@nginx.com 4604507Smax.romanov@nginx.com if (!state->start_process) { 4605507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 4606343Smax.romanov@nginx.com &app->name, app); 4607343Smax.romanov@nginx.com 4608343Smax.romanov@nginx.com return NXT_AGAIN; 4609343Smax.romanov@nginx.com } 4610343Smax.romanov@nginx.com 4611507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 4612343Smax.romanov@nginx.com 4613343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 46141123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 46151123Smax.romanov@nginx.com "Failed to start app process"); 46161123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 4617343Smax.romanov@nginx.com 4618141Smax.romanov@nginx.com return NXT_ERROR; 4619141Smax.romanov@nginx.com } 4620141Smax.romanov@nginx.com 4621141Smax.romanov@nginx.com return NXT_AGAIN; 462288Smax.romanov@nginx.com } 462388Smax.romanov@nginx.com 462488Smax.romanov@nginx.com 4625427Smax.romanov@nginx.com static nxt_int_t 46261123Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 46271123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 4628427Smax.romanov@nginx.com { 4629427Smax.romanov@nginx.com nxt_port_select_state_t state; 4630427Smax.romanov@nginx.com 46311123Smax.romanov@nginx.com state.req_app_link = req_app_link; 4632427Smax.romanov@nginx.com state.app = app; 4633427Smax.romanov@nginx.com 4634427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4635427Smax.romanov@nginx.com 4636427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4637427Smax.romanov@nginx.com 4638427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4639427Smax.romanov@nginx.com 4640427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 4641427Smax.romanov@nginx.com } 4642427Smax.romanov@nginx.com 4643427Smax.romanov@nginx.com 4644431Sigor@sysoev.ru void 46451007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, 4646964Sigor@sysoev.ru nxt_app_t *app) 464753Sigor@sysoev.ru { 46481123Smax.romanov@nginx.com nxt_int_t res; 46491123Smax.romanov@nginx.com nxt_port_t *port; 46501123Smax.romanov@nginx.com nxt_event_engine_t *engine; 46511123Smax.romanov@nginx.com nxt_request_app_link_t ra_local, *req_app_link; 46521123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 4653431Sigor@sysoev.ru 465488Smax.romanov@nginx.com engine = task->thread->engine; 465588Smax.romanov@nginx.com 46561123Smax.romanov@nginx.com req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port, 4657318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4658318Smax.romanov@nginx.com nxt_router_response_error_handler, 46591123Smax.romanov@nginx.com sizeof(nxt_request_rpc_data_t)); 46601123Smax.romanov@nginx.com if (nxt_slow_path(req_rpc_data == NULL)) { 4661431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4662141Smax.romanov@nginx.com return; 466388Smax.romanov@nginx.com } 466488Smax.romanov@nginx.com 46651123Smax.romanov@nginx.com req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data); 46661123Smax.romanov@nginx.com req_rpc_data->app = app; 4667425Smax.romanov@nginx.com 4668425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4669425Smax.romanov@nginx.com 46701123Smax.romanov@nginx.com req_rpc_data->request = r; 46711131Smax.romanov@nginx.com r->req_rpc_data = req_rpc_data; 46721123Smax.romanov@nginx.com 46731123Smax.romanov@nginx.com req_app_link = &ra_local; 46741123Smax.romanov@nginx.com nxt_request_app_link_init(task, req_app_link, req_rpc_data); 46751123Smax.romanov@nginx.com 46761123Smax.romanov@nginx.com res = nxt_router_app_port(task, app, req_app_link); 4677141Smax.romanov@nginx.com 4678141Smax.romanov@nginx.com if (res != NXT_OK) { 4679141Smax.romanov@nginx.com return; 4680141Smax.romanov@nginx.com } 4681141Smax.romanov@nginx.com 46821123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 46831123Smax.romanov@nginx.com port = req_app_link->app_port; 4684141Smax.romanov@nginx.com 4685425Smax.romanov@nginx.com nxt_assert(port != NULL); 4686141Smax.romanov@nginx.com 46871123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, port->pid); 46881123Smax.romanov@nginx.com 46891123Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 4690167Smax.romanov@nginx.com } 4691167Smax.romanov@nginx.com 4692167Smax.romanov@nginx.com 4693167Smax.romanov@nginx.com static void 4694423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4695423Smax.romanov@nginx.com { 4696423Smax.romanov@nginx.com } 4697423Smax.romanov@nginx.com 4698423Smax.romanov@nginx.com 4699423Smax.romanov@nginx.com static void 47001123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, 47011123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 4702167Smax.romanov@nginx.com { 47031123Smax.romanov@nginx.com nxt_buf_t *buf; 47041123Smax.romanov@nginx.com nxt_int_t res; 47051123Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 47061123Smax.romanov@nginx.com nxt_apr_action_t apr_action; 47071123Smax.romanov@nginx.com 47081123Smax.romanov@nginx.com nxt_assert(req_app_link->app_port != NULL); 47091123Smax.romanov@nginx.com 47101123Smax.romanov@nginx.com port = req_app_link->app_port; 47111123Smax.romanov@nginx.com reply_port = req_app_link->reply_port; 47121123Smax.romanov@nginx.com 47131123Smax.romanov@nginx.com apr_action = NXT_APR_REQUEST_FAILED; 4714343Smax.romanov@nginx.com 4715141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 4716141Smax.romanov@nginx.com reply_port->id); 4717141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 4718141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 4719122Smax.romanov@nginx.com 4720122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 47211123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 4722345Smax.romanov@nginx.com "Failed to send reply port to application"); 4723343Smax.romanov@nginx.com goto release_port; 4724122Smax.romanov@nginx.com } 4725122Smax.romanov@nginx.com 4726141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 472788Smax.romanov@nginx.com } 472888Smax.romanov@nginx.com 47291123Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, req_app_link->request, port, 4730743Smax.romanov@nginx.com nxt_app_msg_prefix[port->app->type]); 4731743Smax.romanov@nginx.com 4732743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 47331123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 4734345Smax.romanov@nginx.com "Failed to prepare message for application"); 4735343Smax.romanov@nginx.com goto release_port; 4736122Smax.romanov@nginx.com } 473788Smax.romanov@nginx.com 4738507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4739743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4740743Smax.romanov@nginx.com port->socket.fd); 474188Smax.romanov@nginx.com 47421123Smax.romanov@nginx.com apr_action = NXT_APR_NEW_PORT; 47431123Smax.romanov@nginx.com 47441123Smax.romanov@nginx.com req_app_link->msg_info.buf = buf; 47451123Smax.romanov@nginx.com req_app_link->msg_info.completion_handler = buf->completion_handler; 4746743Smax.romanov@nginx.com 4747743Smax.romanov@nginx.com for (; buf; buf = buf->next) { 4748743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 4749423Smax.romanov@nginx.com } 4750423Smax.romanov@nginx.com 47511123Smax.romanov@nginx.com buf = req_app_link->msg_info.buf; 47521123Smax.romanov@nginx.com 47531123Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, 47541123Smax.romanov@nginx.com &req_app_link->msg_info.tracking, 47551123Smax.romanov@nginx.com req_app_link->stream); 4756423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 47571123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 47581123Smax.romanov@nginx.com "Failed to get tracking area"); 4759423Smax.romanov@nginx.com goto release_port; 4760423Smax.romanov@nginx.com } 4761423Smax.romanov@nginx.com 47621131Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_REQ_HEADERS, 47631123Smax.romanov@nginx.com -1, req_app_link->stream, reply_port->id, buf, 47641123Smax.romanov@nginx.com &req_app_link->msg_info.tracking); 4765122Smax.romanov@nginx.com 4766122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 47671123Smax.romanov@nginx.com nxt_request_app_link_error(req_app_link, 500, 47681123Smax.romanov@nginx.com "Failed to send message to application"); 4769343Smax.romanov@nginx.com goto release_port; 4770122Smax.romanov@nginx.com } 4771343Smax.romanov@nginx.com 4772343Smax.romanov@nginx.com release_port: 4773343Smax.romanov@nginx.com 47741123Smax.romanov@nginx.com nxt_router_app_port_release(task, port, apr_action); 47751123Smax.romanov@nginx.com 47761123Smax.romanov@nginx.com nxt_request_app_link_update_peer(task, req_app_link); 477753Sigor@sysoev.ru } 477853Sigor@sysoev.ru 477953Sigor@sysoev.ru 4780743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4781743Smax.romanov@nginx.com nxt_list_part_t *part; 4782743Smax.romanov@nginx.com nxt_http_field_t *field; 4783743Smax.romanov@nginx.com }; 4784743Smax.romanov@nginx.com 4785743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4786743Smax.romanov@nginx.com 4787743Smax.romanov@nginx.com 4788743Smax.romanov@nginx.com static nxt_http_field_t * 4789743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4790216Sigor@sysoev.ru { 4791743Smax.romanov@nginx.com if (part == NULL) { 4792743Smax.romanov@nginx.com return NULL; 4793216Sigor@sysoev.ru } 4794216Sigor@sysoev.ru 4795743Smax.romanov@nginx.com while (part->nelts == 0) { 4796743Smax.romanov@nginx.com part = part->next; 4797743Smax.romanov@nginx.com if (part == NULL) { 4798743Smax.romanov@nginx.com return NULL; 4799743Smax.romanov@nginx.com } 4800216Sigor@sysoev.ru } 4801216Sigor@sysoev.ru 4802743Smax.romanov@nginx.com i->part = part; 4803743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4804743Smax.romanov@nginx.com 4805743Smax.romanov@nginx.com return i->field; 4806743Smax.romanov@nginx.com } 4807743Smax.romanov@nginx.com 4808743Smax.romanov@nginx.com 4809743Smax.romanov@nginx.com static nxt_http_field_t * 4810743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4811743Smax.romanov@nginx.com { 4812743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4813743Smax.romanov@nginx.com } 4814743Smax.romanov@nginx.com 4815743Smax.romanov@nginx.com 4816743Smax.romanov@nginx.com static nxt_http_field_t * 4817743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4818743Smax.romanov@nginx.com { 4819743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4820743Smax.romanov@nginx.com 4821743Smax.romanov@nginx.com end += i->part->nelts; 4822743Smax.romanov@nginx.com i->field++; 4823743Smax.romanov@nginx.com 4824743Smax.romanov@nginx.com if (i->field < end) { 4825743Smax.romanov@nginx.com return i->field; 4826216Sigor@sysoev.ru } 4827216Sigor@sysoev.ru 4828743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4829216Sigor@sysoev.ru } 4830216Sigor@sysoev.ru 4831216Sigor@sysoev.ru 4832743Smax.romanov@nginx.com static nxt_buf_t * 48331007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, 4834743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix) 4835216Sigor@sysoev.ru { 48361007Salexander.borisov@nginx.com void *target_pos, *query_pos; 48371007Salexander.borisov@nginx.com u_char *pos, *end, *p, c; 48381007Salexander.borisov@nginx.com size_t fields_count, req_size, size, free_size; 48391007Salexander.borisov@nginx.com size_t copy_size; 48401007Salexander.borisov@nginx.com nxt_off_t content_length; 48411007Salexander.borisov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 48421007Salexander.borisov@nginx.com nxt_http_field_t *field, *dup; 48431007Salexander.borisov@nginx.com nxt_unit_field_t *dst_field; 48441007Salexander.borisov@nginx.com nxt_fields_iter_t iter, dup_iter; 48451007Salexander.borisov@nginx.com nxt_unit_request_t *req; 4846216Sigor@sysoev.ru 4847743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 48481007Salexander.borisov@nginx.com + r->method->length + 1 48491007Salexander.borisov@nginx.com + r->version.length + 1 48501007Salexander.borisov@nginx.com + r->remote->length + 1 48511007Salexander.borisov@nginx.com + r->local->length + 1 48521007Salexander.borisov@nginx.com + r->server_name.length + 1 48531007Salexander.borisov@nginx.com + r->target.length + 1 48541007Salexander.borisov@nginx.com + (r->path->start != r->target.start ? r->path->length + 1 : 0); 48551007Salexander.borisov@nginx.com 48561007Salexander.borisov@nginx.com content_length = r->content_length_n < 0 ? 0 : r->content_length_n; 4857743Smax.romanov@nginx.com fields_count = 0; 4858743Smax.romanov@nginx.com 48591007Salexander.borisov@nginx.com nxt_list_each(field, r->fields) { 4860743Smax.romanov@nginx.com fields_count++; 4861743Smax.romanov@nginx.com 4862743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4863743Smax.romanov@nginx.com + field->value_length + 1; 4864743Smax.romanov@nginx.com } nxt_list_loop; 4865743Smax.romanov@nginx.com 4866743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4867743Smax.romanov@nginx.com 4868743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4869743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4870743Smax.romanov@nginx.com (int) req_size); 4871743Smax.romanov@nginx.com 4872743Smax.romanov@nginx.com return NULL; 4873743Smax.romanov@nginx.com } 4874743Smax.romanov@nginx.com 4875743Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, port, 48761007Salexander.borisov@nginx.com nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); 4877743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4878743Smax.romanov@nginx.com return NULL; 4879743Smax.romanov@nginx.com } 4880743Smax.romanov@nginx.com 4881743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4882743Smax.romanov@nginx.com out->mem.free += req_size; 4883743Smax.romanov@nginx.com 48841007Salexander.borisov@nginx.com req->content_length = content_length; 4885743Smax.romanov@nginx.com 4886743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4887743Smax.romanov@nginx.com 4888743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4889743Smax.romanov@nginx.com 48901007Salexander.borisov@nginx.com req->method_length = r->method->length; 4891743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 48921007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 4893743Smax.romanov@nginx.com *p++ = '\0'; 4894743Smax.romanov@nginx.com 48951007Salexander.borisov@nginx.com req->version_length = r->version.length; 4896743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 48971007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 4898743Smax.romanov@nginx.com *p++ = '\0'; 4899743Smax.romanov@nginx.com 49001007Salexander.borisov@nginx.com req->remote_length = r->remote->address_length; 4901743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 49021007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), 49031007Salexander.borisov@nginx.com r->remote->address_length); 4904743Smax.romanov@nginx.com *p++ = '\0'; 4905743Smax.romanov@nginx.com 49061007Salexander.borisov@nginx.com req->local_length = r->local->address_length; 4907743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 49081007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); 4909743Smax.romanov@nginx.com *p++ = '\0'; 4910743Smax.romanov@nginx.com 49111011Smax.romanov@nginx.com req->tls = (r->tls != NULL); 49121131Smax.romanov@nginx.com req->websocket_handshake = r->websocket_handshake; 49131011Smax.romanov@nginx.com 49141007Salexander.borisov@nginx.com req->server_name_length = r->server_name.length; 4915967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 49161007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->server_name.start, r->server_name.length); 4917967Svbart@nginx.com *p++ = '\0'; 4918967Svbart@nginx.com 4919743Smax.romanov@nginx.com target_pos = p; 49201007Salexander.borisov@nginx.com req->target_length = (uint32_t) r->target.length; 4921743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 49221007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 4923743Smax.romanov@nginx.com *p++ = '\0'; 4924743Smax.romanov@nginx.com 49251007Salexander.borisov@nginx.com req->path_length = (uint32_t) r->path->length; 49261007Salexander.borisov@nginx.com if (r->path->start == r->target.start) { 4927743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 4928277Sigor@sysoev.ru 4929216Sigor@sysoev.ru } else { 4930743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 49311007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 4932743Smax.romanov@nginx.com *p++ = '\0'; 4933305Smax.romanov@nginx.com } 4934216Sigor@sysoev.ru 49351007Salexander.borisov@nginx.com req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0; 49361007Salexander.borisov@nginx.com if (r->args != NULL && r->args->start != NULL) { 4937743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 49381007Salexander.borisov@nginx.com r->args->start - r->target.start); 4939743Smax.romanov@nginx.com 4940743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 4941277Sigor@sysoev.ru 4942216Sigor@sysoev.ru } else { 4943743Smax.romanov@nginx.com req->query.offset = 0; 4944216Sigor@sysoev.ru } 4945216Sigor@sysoev.ru 4946743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 4947743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 4948743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 4949743Smax.romanov@nginx.com 4950743Smax.romanov@nginx.com dst_field = req->fields; 4951743Smax.romanov@nginx.com 49521007Salexander.borisov@nginx.com for (field = nxt_fields_first(r->fields, &iter); 4953743Smax.romanov@nginx.com field != NULL; 4954743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 4955743Smax.romanov@nginx.com { 4956743Smax.romanov@nginx.com if (field->skip) { 4957743Smax.romanov@nginx.com continue; 4958743Smax.romanov@nginx.com } 4959743Smax.romanov@nginx.com 4960743Smax.romanov@nginx.com dst_field->hash = field->hash; 4961743Smax.romanov@nginx.com dst_field->skip = 0; 4962743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 4963743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 4964743Smax.romanov@nginx.com 49651007Salexander.borisov@nginx.com if (field == r->content_length) { 4966743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 4967743Smax.romanov@nginx.com 49681007Salexander.borisov@nginx.com } else if (field == r->content_type) { 4969743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 4970743Smax.romanov@nginx.com 49711007Salexander.borisov@nginx.com } else if (field == r->cookie) { 4972743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 4973743Smax.romanov@nginx.com } 4974743Smax.romanov@nginx.com 4975743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 4976743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 4977743Smax.romanov@nginx.com (int) field->name_length, field->name, 4978743Smax.romanov@nginx.com (int) field->value_length, field->value); 4979743Smax.romanov@nginx.com 4980743Smax.romanov@nginx.com if (prefix->length != 0) { 4981743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4982743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 4983743Smax.romanov@nginx.com 4984743Smax.romanov@nginx.com end = field->name + field->name_length; 4985743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 4986743Smax.romanov@nginx.com c = *pos; 4987743Smax.romanov@nginx.com 4988743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 4989743Smax.romanov@nginx.com *p++ = (c & ~0x20); 4990743Smax.romanov@nginx.com continue; 4991743Smax.romanov@nginx.com } 4992743Smax.romanov@nginx.com 4993743Smax.romanov@nginx.com if (c == '-') { 4994743Smax.romanov@nginx.com *p++ = '_'; 4995743Smax.romanov@nginx.com continue; 4996743Smax.romanov@nginx.com } 4997743Smax.romanov@nginx.com 4998743Smax.romanov@nginx.com *p++ = c; 4999743Smax.romanov@nginx.com } 5000743Smax.romanov@nginx.com 5001743Smax.romanov@nginx.com } else { 5002743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 5003743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 5004743Smax.romanov@nginx.com } 5005743Smax.romanov@nginx.com 5006743Smax.romanov@nginx.com *p++ = '\0'; 5007743Smax.romanov@nginx.com 5008743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 5009743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 5010743Smax.romanov@nginx.com 5011743Smax.romanov@nginx.com if (prefix->length != 0) { 5012743Smax.romanov@nginx.com dup_iter = iter; 5013743Smax.romanov@nginx.com 5014743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 5015743Smax.romanov@nginx.com dup != NULL; 5016743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 5017743Smax.romanov@nginx.com { 5018743Smax.romanov@nginx.com if (dup->name_length != field->name_length 5019743Smax.romanov@nginx.com || dup->skip 5020743Smax.romanov@nginx.com || dup->hash != field->hash 5021743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 5022743Smax.romanov@nginx.com { 5023743Smax.romanov@nginx.com continue; 5024743Smax.romanov@nginx.com } 5025743Smax.romanov@nginx.com 5026743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 5027743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 5028743Smax.romanov@nginx.com 5029743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 5030743Smax.romanov@nginx.com 5031743Smax.romanov@nginx.com dup->skip = 1; 5032743Smax.romanov@nginx.com } 5033743Smax.romanov@nginx.com } 5034743Smax.romanov@nginx.com 5035743Smax.romanov@nginx.com *p++ = '\0'; 5036743Smax.romanov@nginx.com 5037743Smax.romanov@nginx.com dst_field++; 5038743Smax.romanov@nginx.com } 5039743Smax.romanov@nginx.com 50401007Salexander.borisov@nginx.com req->fields_count = (uint32_t) (dst_field - req->fields); 5041743Smax.romanov@nginx.com 5042743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 5043743Smax.romanov@nginx.com 5044743Smax.romanov@nginx.com buf = out; 5045743Smax.romanov@nginx.com tail = &buf->next; 5046216Sigor@sysoev.ru 50471007Salexander.borisov@nginx.com for (b = r->body; b != NULL; b = b->next) { 5048743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 5049743Smax.romanov@nginx.com pos = b->mem.pos; 5050743Smax.romanov@nginx.com 5051743Smax.romanov@nginx.com while (size > 0) { 5052743Smax.romanov@nginx.com if (buf == NULL) { 5053743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 5054743Smax.romanov@nginx.com 5055743Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, port, free_size); 5056743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 5057743Smax.romanov@nginx.com while (out != NULL) { 5058743Smax.romanov@nginx.com buf = out->next; 5059743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 5060743Smax.romanov@nginx.com out = buf; 5061743Smax.romanov@nginx.com } 5062743Smax.romanov@nginx.com return NULL; 5063743Smax.romanov@nginx.com } 5064743Smax.romanov@nginx.com 5065743Smax.romanov@nginx.com *tail = buf; 5066743Smax.romanov@nginx.com tail = &buf->next; 5067743Smax.romanov@nginx.com 5068743Smax.romanov@nginx.com } else { 5069743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5070743Smax.romanov@nginx.com if (free_size < size 5071743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 5072743Smax.romanov@nginx.com == NXT_OK) 5073743Smax.romanov@nginx.com { 5074743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5075743Smax.romanov@nginx.com } 5076743Smax.romanov@nginx.com } 5077743Smax.romanov@nginx.com 5078743Smax.romanov@nginx.com if (free_size > 0) { 5079743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 5080743Smax.romanov@nginx.com 5081743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 5082743Smax.romanov@nginx.com 5083743Smax.romanov@nginx.com size -= copy_size; 5084743Smax.romanov@nginx.com pos += copy_size; 5085743Smax.romanov@nginx.com 5086743Smax.romanov@nginx.com if (size == 0) { 5087743Smax.romanov@nginx.com break; 5088743Smax.romanov@nginx.com } 5089743Smax.romanov@nginx.com } 5090743Smax.romanov@nginx.com 5091743Smax.romanov@nginx.com buf = NULL; 5092743Smax.romanov@nginx.com } 5093216Sigor@sysoev.ru } 5094216Sigor@sysoev.ru 5095743Smax.romanov@nginx.com return out; 5096584Salexander.borisov@nginx.com } 5097584Salexander.borisov@nginx.com 5098584Salexander.borisov@nginx.com 509953Sigor@sysoev.ru static void 5100318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 5101318Smax.romanov@nginx.com { 5102615Smax.romanov@nginx.com nxt_app_t *app; 5103615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 5104615Smax.romanov@nginx.com nxt_port_t *port; 5105615Smax.romanov@nginx.com nxt_timer_t *timer; 5106615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 51071007Salexander.borisov@nginx.com nxt_http_request_t *r; 51081123Smax.romanov@nginx.com nxt_request_app_link_t *pending_ra; 51091123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5110615Smax.romanov@nginx.com nxt_port_select_state_t state; 5111318Smax.romanov@nginx.com 5112318Smax.romanov@nginx.com timer = obj; 5113318Smax.romanov@nginx.com 5114318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 5115318Smax.romanov@nginx.com 51161007Salexander.borisov@nginx.com r = nxt_timer_data(timer, nxt_http_request_t, timer); 51171123Smax.romanov@nginx.com req_rpc_data = r->timer_data; 51181123Smax.romanov@nginx.com app = req_rpc_data->app; 5119615Smax.romanov@nginx.com 5120615Smax.romanov@nginx.com if (app == NULL) { 5121615Smax.romanov@nginx.com goto generate_error; 5122615Smax.romanov@nginx.com } 5123615Smax.romanov@nginx.com 5124615Smax.romanov@nginx.com port = NULL; 5125615Smax.romanov@nginx.com pending_ra = NULL; 5126615Smax.romanov@nginx.com 51271123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 51281123Smax.romanov@nginx.com port = req_rpc_data->app_port; 51291123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 51301123Smax.romanov@nginx.com } 51311123Smax.romanov@nginx.com 51321123Smax.romanov@nginx.com if (port == NULL && req_rpc_data->req_app_link != NULL 51331123Smax.romanov@nginx.com && req_rpc_data->req_app_link->app_port != NULL) 51341123Smax.romanov@nginx.com { 51351123Smax.romanov@nginx.com port = req_rpc_data->req_app_link->app_port; 51361123Smax.romanov@nginx.com req_rpc_data->req_app_link->app_port = NULL; 5137615Smax.romanov@nginx.com } 5138615Smax.romanov@nginx.com 5139615Smax.romanov@nginx.com if (port == NULL) { 5140615Smax.romanov@nginx.com goto generate_error; 5141431Sigor@sysoev.ru } 5142615Smax.romanov@nginx.com 5143615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 5144615Smax.romanov@nginx.com 5145615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 5146615Smax.romanov@nginx.com 5147615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 5148615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 5149615Smax.romanov@nginx.com 51501123Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 5151615Smax.romanov@nginx.com link_port_pending); 5152615Smax.romanov@nginx.com 5153615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 5154615Smax.romanov@nginx.com 5155615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 5156615Smax.romanov@nginx.com &app->name, pending_ra->stream); 5157615Smax.romanov@nginx.com 5158615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 5159615Smax.romanov@nginx.com pending_ra->stream); 5160615Smax.romanov@nginx.com 5161615Smax.romanov@nginx.com if (cancelled) { 51621123Smax.romanov@nginx.com nxt_request_app_link_inc_use(pending_ra); 51631123Smax.romanov@nginx.com 51641123Smax.romanov@nginx.com state.req_app_link = pending_ra; 5165615Smax.romanov@nginx.com state.app = app; 5166615Smax.romanov@nginx.com 5167615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 5168615Smax.romanov@nginx.com 5169615Smax.romanov@nginx.com } else { 5170615Smax.romanov@nginx.com pending_ra = NULL; 5171615Smax.romanov@nginx.com } 5172615Smax.romanov@nginx.com } 5173615Smax.romanov@nginx.com 5174615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 5175615Smax.romanov@nginx.com 5176615Smax.romanov@nginx.com if (pending_ra != NULL 5177615Smax.romanov@nginx.com && nxt_router_port_post_select(task, &state) == NXT_OK) 5178615Smax.romanov@nginx.com { 5179615Smax.romanov@nginx.com nxt_router_app_prepare_request(task, pending_ra); 5180615Smax.romanov@nginx.com } 5181615Smax.romanov@nginx.com 5182615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 5183615Smax.romanov@nginx.com 5184615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 5185615Smax.romanov@nginx.com 5186615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 5187615Smax.romanov@nginx.com 5188615Smax.romanov@nginx.com generate_error: 5189615Smax.romanov@nginx.com 51901007Salexander.borisov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 5191615Smax.romanov@nginx.com 51921123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 5193318Smax.romanov@nginx.com } 51941007Salexander.borisov@nginx.com 51951007Salexander.borisov@nginx.com 51961007Salexander.borisov@nginx.com static nxt_int_t 51971007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r) 51981007Salexander.borisov@nginx.com { 51991007Salexander.borisov@nginx.com r->timer.handler = nxt_router_http_request_release; 52001007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 0); 52011007Salexander.borisov@nginx.com 52021007Salexander.borisov@nginx.com return NXT_OK; 52031007Salexander.borisov@nginx.com } 52041007Salexander.borisov@nginx.com 52051007Salexander.borisov@nginx.com 52061007Salexander.borisov@nginx.com static void 52071007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) 52081007Salexander.borisov@nginx.com { 52091007Salexander.borisov@nginx.com nxt_http_request_t *r; 52101007Salexander.borisov@nginx.com 52111007Salexander.borisov@nginx.com nxt_debug(task, "http app release"); 52121007Salexander.borisov@nginx.com 52131007Salexander.borisov@nginx.com r = nxt_timer_data(obj, nxt_http_request_t, timer); 52141007Salexander.borisov@nginx.com 52151007Salexander.borisov@nginx.com nxt_mp_release(r->mem_pool); 52161007Salexander.borisov@nginx.com } 5217