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 981294Smax.romanov@nginx.com nxt_request_app_link_chk_use(nxt_request_app_link_t *req_app_link, int i) 99425Smax.romanov@nginx.com { 100538Svbart@nginx.com #if (NXT_DEBUG) 101425Smax.romanov@nginx.com int c; 102425Smax.romanov@nginx.com 1031294Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&req_app_link->use_count, i); 1041294Smax.romanov@nginx.com 1051294Smax.romanov@nginx.com nxt_assert((c + i) > 0); 106538Svbart@nginx.com #else 1071294Smax.romanov@nginx.com (void) nxt_atomic_fetch_add(&req_app_link->use_count, i); 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); 1251183Svbart@nginx.com static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, 1261183Svbart@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); 2511321Smax.romanov@nginx.com static void nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 2521007Salexander.borisov@nginx.com 2531149Smax.romanov@nginx.com extern const nxt_http_request_state_t nxt_http_websocket; 2541131Smax.romanov@nginx.com 255119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 25620Sigor@sysoev.ru 257743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 258743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 259743Smax.romanov@nginx.com 260743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 261804Svbart@nginx.com &empty_prefix, 262743Smax.romanov@nginx.com &http_prefix, 263743Smax.romanov@nginx.com &http_prefix, 264743Smax.romanov@nginx.com &http_prefix, 265743Smax.romanov@nginx.com &http_prefix, 266977Smax.romanov@gmail.com &empty_prefix, 267216Sigor@sysoev.ru }; 268216Sigor@sysoev.ru 269216Sigor@sysoev.ru 270662Smax.romanov@nginx.com nxt_port_handlers_t nxt_router_process_port_handlers = { 271662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 272662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 273662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 274662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 275662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 276662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 277662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 278662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 279662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2801321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 281662Smax.romanov@nginx.com }; 282662Smax.romanov@nginx.com 283662Smax.romanov@nginx.com 28420Sigor@sysoev.ru nxt_int_t 285141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 28620Sigor@sysoev.ru { 287141Smax.romanov@nginx.com nxt_int_t ret; 288662Smax.romanov@nginx.com nxt_port_t *controller_port; 289141Smax.romanov@nginx.com nxt_router_t *router; 290141Smax.romanov@nginx.com nxt_runtime_t *rt; 291141Smax.romanov@nginx.com 292141Smax.romanov@nginx.com rt = task->thread->runtime; 29353Sigor@sysoev.ru 294771Sigor@sysoev.ru #if (NXT_TLS) 295771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 296771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 297771Sigor@sysoev.ru return NXT_ERROR; 298771Sigor@sysoev.ru } 299771Sigor@sysoev.ru 300771Sigor@sysoev.ru ret = rt->tls->library_init(task); 301771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 302771Sigor@sysoev.ru return ret; 303771Sigor@sysoev.ru } 304771Sigor@sysoev.ru #endif 305771Sigor@sysoev.ru 306*1459Smax.romanov@nginx.com ret = nxt_http_init(task); 30788Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 30888Smax.romanov@nginx.com return ret; 30988Smax.romanov@nginx.com } 31088Smax.romanov@nginx.com 31153Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 31253Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 31353Sigor@sysoev.ru return NXT_ERROR; 31453Sigor@sysoev.ru } 31553Sigor@sysoev.ru 31653Sigor@sysoev.ru nxt_queue_init(&router->engines); 31753Sigor@sysoev.ru nxt_queue_init(&router->sockets); 318133Sigor@sysoev.ru nxt_queue_init(&router->apps); 31953Sigor@sysoev.ru 320119Smax.romanov@nginx.com nxt_router = router; 321119Smax.romanov@nginx.com 322662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 323662Smax.romanov@nginx.com if (controller_port != NULL) { 324662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 325662Smax.romanov@nginx.com } 326662Smax.romanov@nginx.com 327115Sigor@sysoev.ru return NXT_OK; 328115Sigor@sysoev.ru } 329115Sigor@sysoev.ru 330115Sigor@sysoev.ru 331343Smax.romanov@nginx.com static void 332662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 333662Smax.romanov@nginx.com { 334662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 335662Smax.romanov@nginx.com -1, 0, 0, NULL); 336662Smax.romanov@nginx.com } 337662Smax.romanov@nginx.com 338662Smax.romanov@nginx.com 339662Smax.romanov@nginx.com static void 340507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 341507Smax.romanov@nginx.com void *data) 342167Smax.romanov@nginx.com { 343343Smax.romanov@nginx.com size_t size; 344343Smax.romanov@nginx.com uint32_t stream; 345430Sigor@sysoev.ru nxt_mp_t *mp; 346648Svbart@nginx.com nxt_int_t ret; 347343Smax.romanov@nginx.com nxt_app_t *app; 348343Smax.romanov@nginx.com nxt_buf_t *b; 349343Smax.romanov@nginx.com nxt_port_t *main_port; 350343Smax.romanov@nginx.com nxt_runtime_t *rt; 351343Smax.romanov@nginx.com 352343Smax.romanov@nginx.com app = data; 353167Smax.romanov@nginx.com 354167Smax.romanov@nginx.com rt = task->thread->runtime; 355240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 356167Smax.romanov@nginx.com 357507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 358343Smax.romanov@nginx.com 359343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 360343Smax.romanov@nginx.com 361343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 362343Smax.romanov@nginx.com 363343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 364343Smax.romanov@nginx.com goto failed; 365167Smax.romanov@nginx.com } 366167Smax.romanov@nginx.com 367343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 368343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 369343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 370343Smax.romanov@nginx.com 371753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 372753Smax.romanov@nginx.com 373343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 374343Smax.romanov@nginx.com nxt_router_app_port_ready, 375343Smax.romanov@nginx.com nxt_router_app_port_error, 376753Smax.romanov@nginx.com -1, app->joint); 377343Smax.romanov@nginx.com 378343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 379753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 380753Smax.romanov@nginx.com 381343Smax.romanov@nginx.com goto failed; 382343Smax.romanov@nginx.com } 383343Smax.romanov@nginx.com 384648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 385648Svbart@nginx.com stream, port->id, b); 386648Svbart@nginx.com 387648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 388648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 389753Smax.romanov@nginx.com 390753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 391753Smax.romanov@nginx.com 392648Svbart@nginx.com goto failed; 393648Svbart@nginx.com } 394343Smax.romanov@nginx.com 395753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 396753Smax.romanov@nginx.com 397343Smax.romanov@nginx.com return; 398343Smax.romanov@nginx.com 399343Smax.romanov@nginx.com failed: 400343Smax.romanov@nginx.com 401648Svbart@nginx.com if (b != NULL) { 402648Svbart@nginx.com mp = b->data; 403648Svbart@nginx.com nxt_mp_free(mp, b); 404648Svbart@nginx.com nxt_mp_release(mp); 405648Svbart@nginx.com } 406648Svbart@nginx.com 407343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 408343Smax.romanov@nginx.com 409507Smax.romanov@nginx.com app->pending_processes--; 410343Smax.romanov@nginx.com 411343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 412343Smax.romanov@nginx.com 413343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 414167Smax.romanov@nginx.com } 415167Smax.romanov@nginx.com 416167Smax.romanov@nginx.com 417753Smax.romanov@nginx.com static void 418753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 419753Smax.romanov@nginx.com { 420753Smax.romanov@nginx.com app_joint->use_count += i; 421753Smax.romanov@nginx.com 422753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 423753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 424753Smax.romanov@nginx.com 425753Smax.romanov@nginx.com nxt_free(app_joint); 426753Smax.romanov@nginx.com } 427753Smax.romanov@nginx.com } 428753Smax.romanov@nginx.com 429753Smax.romanov@nginx.com 430343Smax.romanov@nginx.com static nxt_int_t 431507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 432141Smax.romanov@nginx.com { 433343Smax.romanov@nginx.com nxt_int_t res; 434343Smax.romanov@nginx.com nxt_port_t *router_port; 435343Smax.romanov@nginx.com nxt_runtime_t *rt; 436343Smax.romanov@nginx.com 437343Smax.romanov@nginx.com rt = task->thread->runtime; 438343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 439343Smax.romanov@nginx.com 440343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 441343Smax.romanov@nginx.com 442507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 443343Smax.romanov@nginx.com app); 444343Smax.romanov@nginx.com 445343Smax.romanov@nginx.com if (res == NXT_OK) { 446343Smax.romanov@nginx.com return res; 447318Smax.romanov@nginx.com } 448318Smax.romanov@nginx.com 449343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 450343Smax.romanov@nginx.com 451507Smax.romanov@nginx.com app->pending_processes--; 452343Smax.romanov@nginx.com 453343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 454343Smax.romanov@nginx.com 455343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 456343Smax.romanov@nginx.com 457343Smax.romanov@nginx.com return NXT_ERROR; 458318Smax.romanov@nginx.com } 459318Smax.romanov@nginx.com 460318Smax.romanov@nginx.com 461351Smax.romanov@nginx.com nxt_inline void 4621123Smax.romanov@nginx.com nxt_request_app_link_init(nxt_task_t *task, 4631123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, nxt_request_rpc_data_t *req_rpc_data) 464167Smax.romanov@nginx.com { 4651414Smax.romanov@nginx.com nxt_buf_t *body; 466318Smax.romanov@nginx.com nxt_event_engine_t *engine; 467351Smax.romanov@nginx.com 468318Smax.romanov@nginx.com engine = task->thread->engine; 469167Smax.romanov@nginx.com 4701123Smax.romanov@nginx.com nxt_memzero(req_app_link, sizeof(nxt_request_app_link_t)); 4711123Smax.romanov@nginx.com 4721123Smax.romanov@nginx.com req_app_link->stream = req_rpc_data->stream; 4731123Smax.romanov@nginx.com req_app_link->use_count = 1; 4741123Smax.romanov@nginx.com req_app_link->req_rpc_data = req_rpc_data; 4751123Smax.romanov@nginx.com req_rpc_data->req_app_link = req_app_link; 4761123Smax.romanov@nginx.com req_app_link->reply_port = engine->port; 4771123Smax.romanov@nginx.com req_app_link->request = req_rpc_data->request; 4781123Smax.romanov@nginx.com req_app_link->apr_action = NXT_APR_GOT_RESPONSE; 4791123Smax.romanov@nginx.com 4801123Smax.romanov@nginx.com req_app_link->work.handler = NULL; 4811123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 4821123Smax.romanov@nginx.com req_app_link->work.obj = req_app_link; 4831123Smax.romanov@nginx.com req_app_link->work.data = engine; 4841414Smax.romanov@nginx.com 4851414Smax.romanov@nginx.com body = req_rpc_data->request->body; 4861414Smax.romanov@nginx.com 4871414Smax.romanov@nginx.com if (body != NULL && nxt_buf_is_file(body)) { 4881414Smax.romanov@nginx.com req_app_link->body_fd = body->file->fd; 4891414Smax.romanov@nginx.com 4901414Smax.romanov@nginx.com body->file->fd = -1; 4911414Smax.romanov@nginx.com 4921414Smax.romanov@nginx.com } else { 4931414Smax.romanov@nginx.com req_app_link->body_fd = -1; 4941414Smax.romanov@nginx.com } 495351Smax.romanov@nginx.com } 496351Smax.romanov@nginx.com 497351Smax.romanov@nginx.com 4981123Smax.romanov@nginx.com nxt_inline nxt_request_app_link_t * 4991123Smax.romanov@nginx.com nxt_request_app_link_alloc(nxt_task_t *task, 5001123Smax.romanov@nginx.com nxt_request_app_link_t *ra_src, nxt_request_rpc_data_t *req_rpc_data) 501351Smax.romanov@nginx.com { 5021123Smax.romanov@nginx.com nxt_mp_t *mp; 5031123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 5041123Smax.romanov@nginx.com 5051123Smax.romanov@nginx.com if (ra_src != NULL && ra_src->mem_pool != NULL) { 506425Smax.romanov@nginx.com return ra_src; 507425Smax.romanov@nginx.com } 508425Smax.romanov@nginx.com 5091123Smax.romanov@nginx.com mp = req_rpc_data->request->mem_pool; 5101123Smax.romanov@nginx.com 5111123Smax.romanov@nginx.com req_app_link = nxt_mp_alloc(mp, sizeof(nxt_request_app_link_t)); 5121123Smax.romanov@nginx.com 5131123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 5141123Smax.romanov@nginx.com 5151123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 5161123Smax.romanov@nginx.com 5171123Smax.romanov@nginx.com if (ra_src != NULL) { 5181123Smax.romanov@nginx.com ra_src->req_rpc_data = NULL; 5191123Smax.romanov@nginx.com } 520351Smax.romanov@nginx.com 521351Smax.romanov@nginx.com return NULL; 522351Smax.romanov@nginx.com } 523351Smax.romanov@nginx.com 524430Sigor@sysoev.ru nxt_mp_retain(mp); 525430Sigor@sysoev.ru 5261123Smax.romanov@nginx.com nxt_request_app_link_init(task, req_app_link, req_rpc_data); 5271123Smax.romanov@nginx.com 5281414Smax.romanov@nginx.com if (ra_src != NULL) { 5291414Smax.romanov@nginx.com req_app_link->body_fd = ra_src->body_fd; 5301414Smax.romanov@nginx.com } 5311414Smax.romanov@nginx.com 5321123Smax.romanov@nginx.com req_app_link->mem_pool = mp; 5331123Smax.romanov@nginx.com 5341123Smax.romanov@nginx.com return req_app_link; 535167Smax.romanov@nginx.com } 536167Smax.romanov@nginx.com 537167Smax.romanov@nginx.com 538423Smax.romanov@nginx.com nxt_inline nxt_bool_t 539423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 540423Smax.romanov@nginx.com uint32_t stream) 541423Smax.romanov@nginx.com { 542423Smax.romanov@nginx.com nxt_buf_t *b, *next; 543423Smax.romanov@nginx.com nxt_bool_t cancelled; 544423Smax.romanov@nginx.com 545423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 546423Smax.romanov@nginx.com return 0; 547423Smax.romanov@nginx.com } 548423Smax.romanov@nginx.com 549423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 550423Smax.romanov@nginx.com stream); 551423Smax.romanov@nginx.com 552423Smax.romanov@nginx.com if (cancelled) { 553423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 554423Smax.romanov@nginx.com } 555423Smax.romanov@nginx.com 556423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 557423Smax.romanov@nginx.com next = b->next; 5581269Sigor@sysoev.ru b->next = NULL; 559423Smax.romanov@nginx.com 560423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 561423Smax.romanov@nginx.com 562423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 563423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 564423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 565423Smax.romanov@nginx.com } 566423Smax.romanov@nginx.com } 567423Smax.romanov@nginx.com 568423Smax.romanov@nginx.com msg_info->buf = NULL; 569423Smax.romanov@nginx.com 570423Smax.romanov@nginx.com return cancelled; 571423Smax.romanov@nginx.com } 572423Smax.romanov@nginx.com 573423Smax.romanov@nginx.com 574167Smax.romanov@nginx.com static void 5751123Smax.romanov@nginx.com nxt_request_app_link_update_peer_handler(nxt_task_t *task, void *obj, 5761123Smax.romanov@nginx.com void *data) 5771123Smax.romanov@nginx.com { 5781123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 5791123Smax.romanov@nginx.com 5801123Smax.romanov@nginx.com req_app_link = obj; 5811123Smax.romanov@nginx.com 5821123Smax.romanov@nginx.com nxt_request_app_link_update_peer(task, req_app_link); 5831123Smax.romanov@nginx.com 5841123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 5851123Smax.romanov@nginx.com } 586425Smax.romanov@nginx.com 587425Smax.romanov@nginx.com 588425Smax.romanov@nginx.com static void 5891123Smax.romanov@nginx.com nxt_request_app_link_update_peer(nxt_task_t *task, 5901123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 591167Smax.romanov@nginx.com { 5921123Smax.romanov@nginx.com nxt_event_engine_t *engine; 5931123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5941123Smax.romanov@nginx.com 5951123Smax.romanov@nginx.com engine = req_app_link->work.data; 5961123Smax.romanov@nginx.com 5971123Smax.romanov@nginx.com if (task->thread->engine != engine) { 5981123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 5991123Smax.romanov@nginx.com 6001123Smax.romanov@nginx.com req_app_link->work.handler = nxt_request_app_link_update_peer_handler; 6011123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 6021123Smax.romanov@nginx.com req_app_link->work.next = NULL; 6031123Smax.romanov@nginx.com 6041123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD post update peer to %p", 6051123Smax.romanov@nginx.com req_app_link->stream, engine); 6061123Smax.romanov@nginx.com 6071123Smax.romanov@nginx.com nxt_event_engine_post(engine, &req_app_link->work); 6081123Smax.romanov@nginx.com 6091123Smax.romanov@nginx.com return; 6101123Smax.romanov@nginx.com } 6111123Smax.romanov@nginx.com 6121123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD update peer", 6131123Smax.romanov@nginx.com req_app_link->stream); 6141123Smax.romanov@nginx.com 6151123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 6161123Smax.romanov@nginx.com 6171123Smax.romanov@nginx.com if (req_rpc_data != NULL && req_app_link->app_port != NULL) { 6181123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, 6191123Smax.romanov@nginx.com req_app_link->app_port->pid); 6201123Smax.romanov@nginx.com } 621425Smax.romanov@nginx.com } 622425Smax.romanov@nginx.com 623425Smax.romanov@nginx.com 624425Smax.romanov@nginx.com static void 6251123Smax.romanov@nginx.com nxt_request_app_link_release(nxt_task_t *task, 6261123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 627425Smax.romanov@nginx.com { 628431Sigor@sysoev.ru nxt_mp_t *mp; 6291131Smax.romanov@nginx.com nxt_http_request_t *r; 6301123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 6311123Smax.romanov@nginx.com 6321123Smax.romanov@nginx.com nxt_assert(task->thread->engine == req_app_link->work.data); 6331123Smax.romanov@nginx.com nxt_assert(req_app_link->use_count == 0); 6341123Smax.romanov@nginx.com 6351123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD release", req_app_link->stream); 6361123Smax.romanov@nginx.com 6371123Smax.romanov@nginx.com req_rpc_data = req_app_link->req_rpc_data; 6381123Smax.romanov@nginx.com 6391123Smax.romanov@nginx.com if (req_rpc_data != NULL) { 6401123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link->err_code != 0)) { 6411123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 6421123Smax.romanov@nginx.com req_app_link->err_code); 643423Smax.romanov@nginx.com 644423Smax.romanov@nginx.com } else { 6451123Smax.romanov@nginx.com req_rpc_data->app_port = req_app_link->app_port; 6461123Smax.romanov@nginx.com req_rpc_data->apr_action = req_app_link->apr_action; 6471123Smax.romanov@nginx.com req_rpc_data->msg_info = req_app_link->msg_info; 6481123Smax.romanov@nginx.com 6491123Smax.romanov@nginx.com if (req_rpc_data->app->timeout != 0) { 6501131Smax.romanov@nginx.com r = req_rpc_data->request; 6511131Smax.romanov@nginx.com 6521131Smax.romanov@nginx.com r->timer.handler = nxt_router_app_timeout; 6531131Smax.romanov@nginx.com r->timer_data = req_rpc_data; 6541131Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 6551123Smax.romanov@nginx.com req_rpc_data->app->timeout); 656425Smax.romanov@nginx.com } 657425Smax.romanov@nginx.com 6581123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6591123Smax.romanov@nginx.com req_app_link->msg_info.buf = NULL; 660423Smax.romanov@nginx.com } 661343Smax.romanov@nginx.com 6621123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 6631123Smax.romanov@nginx.com req_app_link->req_rpc_data = NULL; 6641123Smax.romanov@nginx.com } 6651123Smax.romanov@nginx.com 6661123Smax.romanov@nginx.com if (req_app_link->app_port != NULL) { 6671123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_app_link->app_port, 6681123Smax.romanov@nginx.com req_app_link->apr_action); 6691123Smax.romanov@nginx.com 6701123Smax.romanov@nginx.com req_app_link->app_port = NULL; 6711123Smax.romanov@nginx.com } 6721123Smax.romanov@nginx.com 6731414Smax.romanov@nginx.com if (req_app_link->body_fd != -1) { 6741414Smax.romanov@nginx.com nxt_fd_close(req_app_link->body_fd); 6751414Smax.romanov@nginx.com 6761414Smax.romanov@nginx.com req_app_link->body_fd = -1; 6771414Smax.romanov@nginx.com } 6781414Smax.romanov@nginx.com 6791123Smax.romanov@nginx.com nxt_router_msg_cancel(task, &req_app_link->msg_info, req_app_link->stream); 6801123Smax.romanov@nginx.com 6811123Smax.romanov@nginx.com mp = req_app_link->mem_pool; 682430Sigor@sysoev.ru 683430Sigor@sysoev.ru if (mp != NULL) { 6841123Smax.romanov@nginx.com nxt_mp_free(mp, req_app_link); 685430Sigor@sysoev.ru nxt_mp_release(mp); 686351Smax.romanov@nginx.com } 687167Smax.romanov@nginx.com } 688167Smax.romanov@nginx.com 689167Smax.romanov@nginx.com 690425Smax.romanov@nginx.com static void 6911123Smax.romanov@nginx.com nxt_request_app_link_release_handler(nxt_task_t *task, void *obj, void *data) 692425Smax.romanov@nginx.com { 6931123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 6941123Smax.romanov@nginx.com 6951123Smax.romanov@nginx.com req_app_link = obj; 6961123Smax.romanov@nginx.com 6971123Smax.romanov@nginx.com nxt_assert(req_app_link->work.data == data); 6981123Smax.romanov@nginx.com 6991123Smax.romanov@nginx.com nxt_atomic_fetch_add(&req_app_link->use_count, -1); 7001123Smax.romanov@nginx.com 7011123Smax.romanov@nginx.com nxt_request_app_link_release(task, req_app_link); 702425Smax.romanov@nginx.com } 703425Smax.romanov@nginx.com 704425Smax.romanov@nginx.com 705425Smax.romanov@nginx.com static void 7061123Smax.romanov@nginx.com nxt_request_app_link_use(nxt_task_t *task, nxt_request_app_link_t *req_app_link, 7071123Smax.romanov@nginx.com int i) 708425Smax.romanov@nginx.com { 709425Smax.romanov@nginx.com int c; 710425Smax.romanov@nginx.com nxt_event_engine_t *engine; 711425Smax.romanov@nginx.com 7121123Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&req_app_link->use_count, i); 713425Smax.romanov@nginx.com 714425Smax.romanov@nginx.com if (i < 0 && c == -i) { 7151123Smax.romanov@nginx.com engine = req_app_link->work.data; 716425Smax.romanov@nginx.com 717425Smax.romanov@nginx.com if (task->thread->engine == engine) { 7181123Smax.romanov@nginx.com nxt_request_app_link_release(task, req_app_link); 719425Smax.romanov@nginx.com 720425Smax.romanov@nginx.com return; 721425Smax.romanov@nginx.com } 722425Smax.romanov@nginx.com 7231123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 7241123Smax.romanov@nginx.com 7251123Smax.romanov@nginx.com req_app_link->work.handler = nxt_request_app_link_release_handler; 7261123Smax.romanov@nginx.com req_app_link->work.task = &engine->task; 7271123Smax.romanov@nginx.com req_app_link->work.next = NULL; 7281123Smax.romanov@nginx.com 7291123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD post release to %p", 7301123Smax.romanov@nginx.com req_app_link->stream, engine); 7311123Smax.romanov@nginx.com 7321123Smax.romanov@nginx.com nxt_event_engine_post(engine, &req_app_link->work); 733425Smax.romanov@nginx.com } 734425Smax.romanov@nginx.com } 735425Smax.romanov@nginx.com 736425Smax.romanov@nginx.com 737423Smax.romanov@nginx.com nxt_inline void 7381446Smax.romanov@nginx.com nxt_request_app_link_error(nxt_task_t *task, nxt_app_t *app, 7391446Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, const char *str) 740345Smax.romanov@nginx.com { 7411123Smax.romanov@nginx.com req_app_link->app_port = NULL; 7421446Smax.romanov@nginx.com req_app_link->err_code = 500; 7431123Smax.romanov@nginx.com req_app_link->err_str = str; 7441446Smax.romanov@nginx.com 7451446Smax.romanov@nginx.com nxt_alert(task, "app \"%V\" internal error: %s on #%uD", 7461446Smax.romanov@nginx.com &app->name, str, req_app_link->stream); 747345Smax.romanov@nginx.com } 748345Smax.romanov@nginx.com 749345Smax.romanov@nginx.com 750427Smax.romanov@nginx.com nxt_inline void 7511123Smax.romanov@nginx.com nxt_request_app_link_pending(nxt_task_t *task, nxt_app_t *app, 7521123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 753427Smax.romanov@nginx.com { 7541123Smax.romanov@nginx.com nxt_queue_insert_tail(&req_app_link->app_port->pending_requests, 7551123Smax.romanov@nginx.com &req_app_link->link_port_pending); 7561123Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &req_app_link->link_app_pending); 7571123Smax.romanov@nginx.com 7581123Smax.romanov@nginx.com nxt_request_app_link_inc_use(req_app_link); 7591123Smax.romanov@nginx.com 7601123Smax.romanov@nginx.com req_app_link->res_time = nxt_thread_monotonic_time(task->thread) 7611123Smax.romanov@nginx.com + app->res_timeout; 7621123Smax.romanov@nginx.com 7631123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD enqueue to pending_requests", 7641123Smax.romanov@nginx.com req_app_link->stream); 765427Smax.romanov@nginx.com } 766427Smax.romanov@nginx.com 767427Smax.romanov@nginx.com 768425Smax.romanov@nginx.com nxt_inline nxt_bool_t 769425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 770425Smax.romanov@nginx.com { 771425Smax.romanov@nginx.com if (lnk->next != NULL) { 772425Smax.romanov@nginx.com nxt_queue_remove(lnk); 773425Smax.romanov@nginx.com 774425Smax.romanov@nginx.com lnk->next = NULL; 775425Smax.romanov@nginx.com 776425Smax.romanov@nginx.com return 1; 777425Smax.romanov@nginx.com } 778425Smax.romanov@nginx.com 779425Smax.romanov@nginx.com return 0; 780425Smax.romanov@nginx.com } 781425Smax.romanov@nginx.com 782425Smax.romanov@nginx.com 783343Smax.romanov@nginx.com nxt_inline void 7841123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(nxt_task_t *task, 7851123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data) 786343Smax.romanov@nginx.com { 7871123Smax.romanov@nginx.com int ra_use_delta; 7881123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 7891123Smax.romanov@nginx.com 7901123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 7911123Smax.romanov@nginx.com nxt_router_app_port_release(task, req_rpc_data->app_port, 7921123Smax.romanov@nginx.com req_rpc_data->apr_action); 7931123Smax.romanov@nginx.com 7941123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 7951123Smax.romanov@nginx.com } 7961123Smax.romanov@nginx.com 7971123Smax.romanov@nginx.com nxt_router_msg_cancel(task, &req_rpc_data->msg_info, req_rpc_data->stream); 7981123Smax.romanov@nginx.com 7991123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 8001123Smax.romanov@nginx.com if (req_app_link != NULL) { 8011123Smax.romanov@nginx.com req_rpc_data->req_app_link = NULL; 8021123Smax.romanov@nginx.com req_app_link->req_rpc_data = NULL; 803343Smax.romanov@nginx.com 804425Smax.romanov@nginx.com ra_use_delta = 0; 805425Smax.romanov@nginx.com 8061123Smax.romanov@nginx.com nxt_thread_mutex_lock(&req_rpc_data->app->mutex); 8071123Smax.romanov@nginx.com 8081123Smax.romanov@nginx.com if (req_app_link->link_app_requests.next == NULL 8091123Smax.romanov@nginx.com && req_app_link->link_port_pending.next == NULL 8101131Smax.romanov@nginx.com && req_app_link->link_app_pending.next == NULL 8111131Smax.romanov@nginx.com && req_app_link->link_port_websockets.next == NULL) 812425Smax.romanov@nginx.com { 8131123Smax.romanov@nginx.com req_app_link = NULL; 814343Smax.romanov@nginx.com 815343Smax.romanov@nginx.com } else { 8161123Smax.romanov@nginx.com ra_use_delta -= 8171123Smax.romanov@nginx.com nxt_queue_chk_remove(&req_app_link->link_app_requests) 8181131Smax.romanov@nginx.com + nxt_queue_chk_remove(&req_app_link->link_port_pending) 8191131Smax.romanov@nginx.com + nxt_queue_chk_remove(&req_app_link->link_port_websockets); 8201123Smax.romanov@nginx.com 8211123Smax.romanov@nginx.com nxt_queue_chk_remove(&req_app_link->link_app_pending); 822343Smax.romanov@nginx.com } 823343Smax.romanov@nginx.com 8241123Smax.romanov@nginx.com nxt_thread_mutex_unlock(&req_rpc_data->app->mutex); 8251123Smax.romanov@nginx.com 8261123Smax.romanov@nginx.com if (req_app_link != NULL) { 8271123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, ra_use_delta); 828425Smax.romanov@nginx.com } 829343Smax.romanov@nginx.com } 830343Smax.romanov@nginx.com 8311123Smax.romanov@nginx.com if (req_rpc_data->app != NULL) { 8321123Smax.romanov@nginx.com nxt_router_app_use(task, req_rpc_data->app, -1); 8331123Smax.romanov@nginx.com 8341123Smax.romanov@nginx.com req_rpc_data->app = NULL; 8351123Smax.romanov@nginx.com } 8361123Smax.romanov@nginx.com 8371123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 8381123Smax.romanov@nginx.com req_rpc_data->request->timer_data = NULL; 8391123Smax.romanov@nginx.com 8401123Smax.romanov@nginx.com nxt_router_http_request_done(task, req_rpc_data->request); 8411123Smax.romanov@nginx.com 8421131Smax.romanov@nginx.com req_rpc_data->request->req_rpc_data = NULL; 8431123Smax.romanov@nginx.com req_rpc_data->request = NULL; 844346Smax.romanov@nginx.com } 845343Smax.romanov@nginx.com } 846343Smax.romanov@nginx.com 847343Smax.romanov@nginx.com 848141Smax.romanov@nginx.com void 849141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 850141Smax.romanov@nginx.com { 851141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 852141Smax.romanov@nginx.com 853670Smax.romanov@nginx.com if (msg->u.new_port != NULL 854670Smax.romanov@nginx.com && msg->u.new_port->type == NXT_PROCESS_CONTROLLER) 855670Smax.romanov@nginx.com { 856662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 857662Smax.romanov@nginx.com } 858662Smax.romanov@nginx.com 859192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 860141Smax.romanov@nginx.com return; 861141Smax.romanov@nginx.com } 862141Smax.romanov@nginx.com 863426Smax.romanov@nginx.com if (msg->u.new_port == NULL 864426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 865347Smax.romanov@nginx.com { 866192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 867141Smax.romanov@nginx.com } 868192Smax.romanov@nginx.com 869192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 870141Smax.romanov@nginx.com } 871141Smax.romanov@nginx.com 872141Smax.romanov@nginx.com 873139Sigor@sysoev.ru void 874139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 875115Sigor@sysoev.ru { 876198Sigor@sysoev.ru nxt_int_t ret; 877139Sigor@sysoev.ru nxt_buf_t *b; 878139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 879139Sigor@sysoev.ru 880139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 881139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 882139Sigor@sysoev.ru return; 88353Sigor@sysoev.ru } 88453Sigor@sysoev.ru 885494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 886423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 887493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 888423Smax.romanov@nginx.com 889591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 890139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 891139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 892198Sigor@sysoev.ru msg->port_msg.pid, 893198Sigor@sysoev.ru msg->port_msg.reply_port); 894198Sigor@sysoev.ru 895779Smax.romanov@nginx.com if (nxt_slow_path(tmcf->port == NULL)) { 896779Smax.romanov@nginx.com nxt_alert(task, "reply port not found"); 897779Smax.romanov@nginx.com 898779Smax.romanov@nginx.com return; 899779Smax.romanov@nginx.com } 900779Smax.romanov@nginx.com 901779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 902779Smax.romanov@nginx.com 903591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 904591Sigor@sysoev.ru msg->buf, msg->size); 905551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 906551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 907551Smax.romanov@nginx.com 908551Smax.romanov@nginx.com return; 909551Smax.romanov@nginx.com } 910551Smax.romanov@nginx.com 911198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 912198Sigor@sysoev.ru 913198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 914198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 915198Sigor@sysoev.ru 916198Sigor@sysoev.ru } else { 917198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 918139Sigor@sysoev.ru } 91953Sigor@sysoev.ru } 92053Sigor@sysoev.ru 92153Sigor@sysoev.ru 922347Smax.romanov@nginx.com static void 923507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 924507Smax.romanov@nginx.com void *data) 925347Smax.romanov@nginx.com { 926347Smax.romanov@nginx.com union { 927347Smax.romanov@nginx.com nxt_pid_t removed_pid; 928347Smax.romanov@nginx.com void *data; 929347Smax.romanov@nginx.com } u; 930347Smax.romanov@nginx.com 931347Smax.romanov@nginx.com u.data = data; 932347Smax.romanov@nginx.com 933347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 934347Smax.romanov@nginx.com } 935347Smax.romanov@nginx.com 936347Smax.romanov@nginx.com 937192Smax.romanov@nginx.com void 938192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 939192Smax.romanov@nginx.com { 940347Smax.romanov@nginx.com nxt_event_engine_t *engine; 941318Smax.romanov@nginx.com 942192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 943192Smax.romanov@nginx.com 944318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 945318Smax.romanov@nginx.com { 946507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 947347Smax.romanov@nginx.com msg->u.data); 948318Smax.romanov@nginx.com } 949318Smax.romanov@nginx.com nxt_queue_loop; 950318Smax.romanov@nginx.com 9511085Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 9521085Smax.romanov@nginx.com return; 9531085Smax.romanov@nginx.com } 9541085Smax.romanov@nginx.com 955192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 956192Smax.romanov@nginx.com 957192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 958192Smax.romanov@nginx.com } 959192Smax.romanov@nginx.com 960192Smax.romanov@nginx.com 96153Sigor@sysoev.ru static nxt_router_temp_conf_t * 962139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 96353Sigor@sysoev.ru { 96465Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 96553Sigor@sysoev.ru nxt_router_conf_t *rtcf; 96653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 96753Sigor@sysoev.ru 96865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 96953Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 97053Sigor@sysoev.ru return NULL; 97153Sigor@sysoev.ru } 97253Sigor@sysoev.ru 97365Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 97453Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 97553Sigor@sysoev.ru goto fail; 97653Sigor@sysoev.ru } 97753Sigor@sysoev.ru 97853Sigor@sysoev.ru rtcf->mem_pool = mp; 97953Sigor@sysoev.ru 98065Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 98153Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 98253Sigor@sysoev.ru goto fail; 98353Sigor@sysoev.ru } 98453Sigor@sysoev.ru 98565Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 98653Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 98753Sigor@sysoev.ru goto temp_fail; 98853Sigor@sysoev.ru } 98953Sigor@sysoev.ru 99053Sigor@sysoev.ru tmcf->mem_pool = tmp; 991591Sigor@sysoev.ru tmcf->router_conf = rtcf; 992139Sigor@sysoev.ru tmcf->count = 1; 993139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 99453Sigor@sysoev.ru 99553Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 99653Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 99753Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 99853Sigor@sysoev.ru goto temp_fail; 99953Sigor@sysoev.ru } 100053Sigor@sysoev.ru 100153Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 100253Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 100353Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 100453Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 100553Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 1006416Smax.romanov@nginx.com 1007774Svbart@nginx.com #if (NXT_TLS) 1008774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 1009774Svbart@nginx.com #endif 1010774Svbart@nginx.com 1011133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 1012133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 101353Sigor@sysoev.ru 101453Sigor@sysoev.ru return tmcf; 101553Sigor@sysoev.ru 101653Sigor@sysoev.ru temp_fail: 101753Sigor@sysoev.ru 101865Sigor@sysoev.ru nxt_mp_destroy(tmp); 101953Sigor@sysoev.ru 102053Sigor@sysoev.ru fail: 102153Sigor@sysoev.ru 102265Sigor@sysoev.ru nxt_mp_destroy(mp); 102353Sigor@sysoev.ru 102453Sigor@sysoev.ru return NULL; 102553Sigor@sysoev.ru } 102653Sigor@sysoev.ru 102753Sigor@sysoev.ru 1028507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1029507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 1030507Smax.romanov@nginx.com { 1031507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 1032507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 1033507Smax.romanov@nginx.com } 1034507Smax.romanov@nginx.com 1035507Smax.romanov@nginx.com 1036507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1037507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 1038507Smax.romanov@nginx.com { 1039507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 1040507Smax.romanov@nginx.com < app->spare_processes; 1041507Smax.romanov@nginx.com } 1042507Smax.romanov@nginx.com 1043507Smax.romanov@nginx.com 1044198Sigor@sysoev.ru static void 1045198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 1046139Sigor@sysoev.ru { 1047139Sigor@sysoev.ru nxt_int_t ret; 1048507Smax.romanov@nginx.com nxt_app_t *app; 1049139Sigor@sysoev.ru nxt_router_t *router; 1050139Sigor@sysoev.ru nxt_runtime_t *rt; 1051198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1052198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1053630Svbart@nginx.com nxt_router_conf_t *rtcf; 1054198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1055139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1056774Svbart@nginx.com #if (NXT_TLS) 1057774Svbart@nginx.com nxt_router_tlssock_t *tls; 1058774Svbart@nginx.com #endif 1059139Sigor@sysoev.ru 1060198Sigor@sysoev.ru tmcf = obj; 1061198Sigor@sysoev.ru 1062198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 1063198Sigor@sysoev.ru 1064198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 1065198Sigor@sysoev.ru nxt_queue_remove(qlk); 1066198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 1067198Sigor@sysoev.ru 1068198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1069198Sigor@sysoev.ru 1070198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1071198Sigor@sysoev.ru 1072198Sigor@sysoev.ru return; 1073139Sigor@sysoev.ru } 1074139Sigor@sysoev.ru 1075774Svbart@nginx.com #if (NXT_TLS) 1076774Svbart@nginx.com qlk = nxt_queue_first(&tmcf->tls); 1077774Svbart@nginx.com 1078774Svbart@nginx.com if (qlk != nxt_queue_tail(&tmcf->tls)) { 1079774Svbart@nginx.com nxt_queue_remove(qlk); 1080774Svbart@nginx.com 1081774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 1082774Svbart@nginx.com 1083774Svbart@nginx.com nxt_router_tls_rpc_create(task, tmcf, tls); 1084774Svbart@nginx.com return; 1085774Svbart@nginx.com } 1086774Svbart@nginx.com #endif 1087774Svbart@nginx.com 1088507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1089507Smax.romanov@nginx.com 1090507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1091507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1092507Smax.romanov@nginx.com return; 1093507Smax.romanov@nginx.com } 1094507Smax.romanov@nginx.com 1095507Smax.romanov@nginx.com } nxt_queue_loop; 1096507Smax.romanov@nginx.com 1097630Svbart@nginx.com rtcf = tmcf->router_conf; 1098630Svbart@nginx.com 1099630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1100630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1101630Svbart@nginx.com return; 1102630Svbart@nginx.com } 1103630Svbart@nginx.com 1104139Sigor@sysoev.ru rt = task->thread->runtime; 1105139Sigor@sysoev.ru 1106139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1107139Sigor@sysoev.ru 1108630Svbart@nginx.com router = rtcf->router; 1109198Sigor@sysoev.ru 1110139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1111139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1112198Sigor@sysoev.ru goto fail; 1113139Sigor@sysoev.ru } 1114139Sigor@sysoev.ru 1115139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1116139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1117198Sigor@sysoev.ru goto fail; 1118139Sigor@sysoev.ru } 1119139Sigor@sysoev.ru 1120343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1121139Sigor@sysoev.ru 1122315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1123139Sigor@sysoev.ru 1124139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 1125139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 1126139Sigor@sysoev.ru 1127630Svbart@nginx.com router->access_log = rtcf->access_log; 1128630Svbart@nginx.com 1129198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1130198Sigor@sysoev.ru 1131198Sigor@sysoev.ru return; 1132198Sigor@sysoev.ru 1133198Sigor@sysoev.ru fail: 1134198Sigor@sysoev.ru 1135198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1136198Sigor@sysoev.ru 1137198Sigor@sysoev.ru return; 1138139Sigor@sysoev.ru } 1139139Sigor@sysoev.ru 1140139Sigor@sysoev.ru 1141139Sigor@sysoev.ru static void 1142139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1143139Sigor@sysoev.ru { 1144153Sigor@sysoev.ru nxt_joint_job_t *job; 1145153Sigor@sysoev.ru 1146153Sigor@sysoev.ru job = obj; 1147153Sigor@sysoev.ru 1148198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1149139Sigor@sysoev.ru } 1150139Sigor@sysoev.ru 1151139Sigor@sysoev.ru 1152139Sigor@sysoev.ru static void 1153198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1154139Sigor@sysoev.ru { 1155139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 1156139Sigor@sysoev.ru 1157139Sigor@sysoev.ru if (--tmcf->count == 0) { 1158193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 1159139Sigor@sysoev.ru } 1160139Sigor@sysoev.ru } 1161139Sigor@sysoev.ru 1162139Sigor@sysoev.ru 1163139Sigor@sysoev.ru static void 1164139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1165139Sigor@sysoev.ru { 1166507Smax.romanov@nginx.com nxt_app_t *app; 1167568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1168148Sigor@sysoev.ru nxt_socket_t s; 1169149Sigor@sysoev.ru nxt_router_t *router; 1170148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1171148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1172630Svbart@nginx.com nxt_router_conf_t *rtcf; 1173148Sigor@sysoev.ru 1174564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1175198Sigor@sysoev.ru 1176148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1177148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1178148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1179148Sigor@sysoev.ru { 1180148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1181359Sigor@sysoev.ru s = skcf->listen->socket; 1182148Sigor@sysoev.ru 1183148Sigor@sysoev.ru if (s != -1) { 1184148Sigor@sysoev.ru nxt_socket_close(task, s); 1185148Sigor@sysoev.ru } 1186148Sigor@sysoev.ru 1187359Sigor@sysoev.ru nxt_free(skcf->listen); 1188148Sigor@sysoev.ru } 1189148Sigor@sysoev.ru 1190568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1191568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1192568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1193568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1194568Smax.romanov@nginx.com 1195964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1196964Sigor@sysoev.ru 1197964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 1198964Sigor@sysoev.ru 1199568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1200568Smax.romanov@nginx.com 12011264Sigor@sysoev.ru if (skcf->action != NULL) { 12021264Sigor@sysoev.ru nxt_http_action_cleanup(task, skcf->action); 1203568Smax.romanov@nginx.com } 1204568Smax.romanov@nginx.com 1205568Smax.romanov@nginx.com } nxt_queue_loop; 1206568Smax.romanov@nginx.com 1207507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1208507Smax.romanov@nginx.com 1209753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1210507Smax.romanov@nginx.com 1211507Smax.romanov@nginx.com } nxt_queue_loop; 1212507Smax.romanov@nginx.com 1213630Svbart@nginx.com router = rtcf->router; 1214149Sigor@sysoev.ru 1215149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1216149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1217149Sigor@sysoev.ru 1218416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1219416Smax.romanov@nginx.com 1220148Sigor@sysoev.ru // TODO: new engines and threads 1221148Sigor@sysoev.ru 1222630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1223630Svbart@nginx.com 1224630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1225139Sigor@sysoev.ru 1226193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1227139Sigor@sysoev.ru } 1228139Sigor@sysoev.ru 1229139Sigor@sysoev.ru 1230139Sigor@sysoev.ru static void 1231139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1232193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1233139Sigor@sysoev.ru { 1234193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1235779Smax.romanov@nginx.com 1236779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1237779Smax.romanov@nginx.com 1238779Smax.romanov@nginx.com tmcf->port = NULL; 1239139Sigor@sysoev.ru } 1240139Sigor@sysoev.ru 1241139Sigor@sysoev.ru 1242115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1243115Sigor@sysoev.ru { 1244133Sigor@sysoev.ru nxt_string("listeners_threads"), 1245115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1246115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1247115Sigor@sysoev.ru }, 1248115Sigor@sysoev.ru }; 1249115Sigor@sysoev.ru 1250115Sigor@sysoev.ru 1251133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1252115Sigor@sysoev.ru { 1253133Sigor@sysoev.ru nxt_string("type"), 1254115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1255133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1256115Sigor@sysoev.ru }, 1257115Sigor@sysoev.ru 1258115Sigor@sysoev.ru { 1259507Smax.romanov@nginx.com nxt_string("limits"), 1260507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1261507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1262133Sigor@sysoev.ru }, 1263318Smax.romanov@nginx.com 1264318Smax.romanov@nginx.com { 1265507Smax.romanov@nginx.com nxt_string("processes"), 1266507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1267507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1268507Smax.romanov@nginx.com }, 1269507Smax.romanov@nginx.com 1270507Smax.romanov@nginx.com { 1271507Smax.romanov@nginx.com nxt_string("processes"), 1272318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1273507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1274318Smax.romanov@nginx.com }, 1275318Smax.romanov@nginx.com }; 1276318Smax.romanov@nginx.com 1277318Smax.romanov@nginx.com 1278318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1279318Smax.romanov@nginx.com { 1280318Smax.romanov@nginx.com nxt_string("timeout"), 1281318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1282318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1283318Smax.romanov@nginx.com }, 1284318Smax.romanov@nginx.com 1285318Smax.romanov@nginx.com { 1286427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1287427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1288427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1289427Smax.romanov@nginx.com }, 1290427Smax.romanov@nginx.com 1291427Smax.romanov@nginx.com { 1292318Smax.romanov@nginx.com nxt_string("requests"), 1293318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1294318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1295318Smax.romanov@nginx.com }, 1296133Sigor@sysoev.ru }; 1297133Sigor@sysoev.ru 1298133Sigor@sysoev.ru 1299507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1300507Smax.romanov@nginx.com { 1301507Smax.romanov@nginx.com nxt_string("spare"), 1302507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1303507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1304507Smax.romanov@nginx.com }, 1305507Smax.romanov@nginx.com 1306507Smax.romanov@nginx.com { 1307507Smax.romanov@nginx.com nxt_string("max"), 1308507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1309507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1310507Smax.romanov@nginx.com }, 1311507Smax.romanov@nginx.com 1312507Smax.romanov@nginx.com { 1313507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1314507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1315507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1316507Smax.romanov@nginx.com }, 1317507Smax.romanov@nginx.com }; 1318507Smax.romanov@nginx.com 1319507Smax.romanov@nginx.com 1320133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1321133Sigor@sysoev.ru { 1322964Sigor@sysoev.ru nxt_string("pass"), 1323964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1324964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1325964Sigor@sysoev.ru }, 1326964Sigor@sysoev.ru 1327964Sigor@sysoev.ru { 1328133Sigor@sysoev.ru nxt_string("application"), 1329964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1330133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1331115Sigor@sysoev.ru }, 1332115Sigor@sysoev.ru }; 1333115Sigor@sysoev.ru 1334115Sigor@sysoev.ru 1335115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1336115Sigor@sysoev.ru { 1337115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1338115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1339115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1340115Sigor@sysoev.ru }, 1341115Sigor@sysoev.ru 1342115Sigor@sysoev.ru { 1343115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1344115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1345115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1346115Sigor@sysoev.ru }, 1347115Sigor@sysoev.ru 1348115Sigor@sysoev.ru { 1349206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1350206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1351206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1352206Smax.romanov@nginx.com }, 1353206Smax.romanov@nginx.com 1354206Smax.romanov@nginx.com { 1355206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1356206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1357206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1358206Smax.romanov@nginx.com }, 1359206Smax.romanov@nginx.com 1360206Smax.romanov@nginx.com { 1361206Smax.romanov@nginx.com nxt_string("max_body_size"), 1362206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1363206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1364206Smax.romanov@nginx.com }, 1365206Smax.romanov@nginx.com 1366206Smax.romanov@nginx.com { 1367431Sigor@sysoev.ru nxt_string("idle_timeout"), 1368431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1369431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1370431Sigor@sysoev.ru }, 1371431Sigor@sysoev.ru 1372431Sigor@sysoev.ru { 1373115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1374115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1375115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1376115Sigor@sysoev.ru }, 1377206Smax.romanov@nginx.com 1378206Smax.romanov@nginx.com { 1379206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1380206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1381206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1382206Smax.romanov@nginx.com }, 1383431Sigor@sysoev.ru 1384431Sigor@sysoev.ru { 1385431Sigor@sysoev.ru nxt_string("send_timeout"), 1386431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1387431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1388431Sigor@sysoev.ru }, 13891403Smax.romanov@nginx.com 13901403Smax.romanov@nginx.com { 13911403Smax.romanov@nginx.com nxt_string("body_temp_path"), 13921403Smax.romanov@nginx.com NXT_CONF_MAP_STR, 13931403Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_temp_path), 13941403Smax.romanov@nginx.com }, 1395115Sigor@sysoev.ru }; 1396115Sigor@sysoev.ru 1397115Sigor@sysoev.ru 13981131Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_websocket_conf[] = { 13991131Smax.romanov@nginx.com { 14001131Smax.romanov@nginx.com nxt_string("max_frame_size"), 14011131Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 14021131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, max_frame_size), 14031131Smax.romanov@nginx.com }, 14041131Smax.romanov@nginx.com 14051131Smax.romanov@nginx.com { 14061131Smax.romanov@nginx.com nxt_string("read_timeout"), 14071131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 14081131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, read_timeout), 14091131Smax.romanov@nginx.com }, 14101131Smax.romanov@nginx.com 14111131Smax.romanov@nginx.com { 14121131Smax.romanov@nginx.com nxt_string("keepalive_interval"), 14131131Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 14141131Smax.romanov@nginx.com offsetof(nxt_websocket_conf_t, keepalive_interval), 14151131Smax.romanov@nginx.com }, 14161131Smax.romanov@nginx.com 14171131Smax.romanov@nginx.com }; 14181131Smax.romanov@nginx.com 14191131Smax.romanov@nginx.com 142053Sigor@sysoev.ru static nxt_int_t 1421115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1422115Sigor@sysoev.ru u_char *start, u_char *end) 142353Sigor@sysoev.ru { 1424133Sigor@sysoev.ru u_char *p; 1425133Sigor@sysoev.ru size_t size; 1426115Sigor@sysoev.ru nxt_mp_t *mp; 1427115Sigor@sysoev.ru uint32_t next; 1428115Sigor@sysoev.ru nxt_int_t ret; 1429630Svbart@nginx.com nxt_str_t name, path; 1430133Sigor@sysoev.ru nxt_app_t *app, *prev; 14311403Smax.romanov@nginx.com nxt_str_t *t; 1432359Sigor@sysoev.ru nxt_router_t *router; 1433753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 14341131Smax.romanov@nginx.com nxt_conf_value_t *conf, *http, *value, *websocket; 1435133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1436133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 14371183Svbart@nginx.com nxt_conf_value_t *routes_conf, *static_conf; 1438115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1439964Sigor@sysoev.ru nxt_http_routes_t *routes; 1440507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1441216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1442133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1443630Svbart@nginx.com nxt_router_access_log_t *access_log; 1444115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1445774Svbart@nginx.com #if (NXT_TLS) 1446774Svbart@nginx.com nxt_router_tlssock_t *tls; 1447774Svbart@nginx.com #endif 1448115Sigor@sysoev.ru 1449716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1450133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1451115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1452964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1453630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1454774Svbart@nginx.com #if (NXT_TLS) 1455774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1456774Svbart@nginx.com #endif 14571183Svbart@nginx.com static nxt_str_t static_path = nxt_string("/settings/http/static"); 14581131Smax.romanov@nginx.com static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); 1459115Sigor@sysoev.ru 1460208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1461115Sigor@sysoev.ru if (conf == NULL) { 1462564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1463115Sigor@sysoev.ru return NXT_ERROR; 1464115Sigor@sysoev.ru } 1465115Sigor@sysoev.ru 1466591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1467213Svbart@nginx.com 1468213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1469591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1470115Sigor@sysoev.ru if (ret != NXT_OK) { 1471564Svbart@nginx.com nxt_alert(task, "root map error"); 1472115Sigor@sysoev.ru return NXT_ERROR; 1473115Sigor@sysoev.ru } 1474115Sigor@sysoev.ru 1475591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1476591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1477117Sigor@sysoev.ru } 1478117Sigor@sysoev.ru 14791183Svbart@nginx.com static_conf = nxt_conf_get_path(conf, &static_path); 14801183Svbart@nginx.com 14811183Svbart@nginx.com ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf); 14821183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 14831183Svbart@nginx.com return NXT_ERROR; 14841183Svbart@nginx.com } 14851183Svbart@nginx.com 14861115Svbart@nginx.com router = tmcf->router_conf->router; 14871115Svbart@nginx.com 1488133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 14891115Svbart@nginx.com 14901115Svbart@nginx.com if (applications != NULL) { 14911115Svbart@nginx.com next = 0; 14921115Svbart@nginx.com 14931115Svbart@nginx.com for ( ;; ) { 14941235Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, 14951235Sigor@sysoev.ru &name, &next); 14961115Svbart@nginx.com if (application == NULL) { 14971115Svbart@nginx.com break; 14981115Svbart@nginx.com } 14991115Svbart@nginx.com 15001115Svbart@nginx.com nxt_debug(task, "application \"%V\"", &name); 15011115Svbart@nginx.com 15021115Svbart@nginx.com size = nxt_conf_json_length(application, NULL); 15031115Svbart@nginx.com 15041115Svbart@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 15051115Svbart@nginx.com if (app == NULL) { 15061115Svbart@nginx.com goto fail; 15071115Svbart@nginx.com } 15081115Svbart@nginx.com 15091115Svbart@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 15101115Svbart@nginx.com 15111115Svbart@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 15121115Svbart@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) 15131115Svbart@nginx.com + name.length); 15141115Svbart@nginx.com 15151115Svbart@nginx.com p = nxt_conf_json_print(app->conf.start, application, NULL); 15161115Svbart@nginx.com app->conf.length = p - app->conf.start; 15171115Svbart@nginx.com 15181115Svbart@nginx.com nxt_assert(app->conf.length <= size); 15191115Svbart@nginx.com 15201115Svbart@nginx.com nxt_debug(task, "application conf \"%V\"", &app->conf); 15211115Svbart@nginx.com 15221115Svbart@nginx.com prev = nxt_router_app_find(&router->apps, &name); 15231115Svbart@nginx.com 15241115Svbart@nginx.com if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 15251115Svbart@nginx.com nxt_free(app); 15261115Svbart@nginx.com 15271115Svbart@nginx.com nxt_queue_remove(&prev->link); 15281115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->previous, &prev->link); 15291115Svbart@nginx.com continue; 15301115Svbart@nginx.com } 15311115Svbart@nginx.com 15321115Svbart@nginx.com apcf.processes = 1; 15331115Svbart@nginx.com apcf.max_processes = 1; 15341115Svbart@nginx.com apcf.spare_processes = 0; 15351115Svbart@nginx.com apcf.timeout = 0; 15361115Svbart@nginx.com apcf.res_timeout = 1000; 15371115Svbart@nginx.com apcf.idle_timeout = 15000; 15381115Svbart@nginx.com apcf.requests = 0; 15391115Svbart@nginx.com apcf.limits_value = NULL; 15401115Svbart@nginx.com apcf.processes_value = NULL; 15411115Svbart@nginx.com 15421115Svbart@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 15431115Svbart@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1544318Smax.romanov@nginx.com goto app_fail; 1545318Smax.romanov@nginx.com } 1546318Smax.romanov@nginx.com 15471115Svbart@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 15481115Svbart@nginx.com 15491115Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 15501115Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1551318Smax.romanov@nginx.com if (ret != NXT_OK) { 15521115Svbart@nginx.com nxt_alert(task, "application map error"); 1553318Smax.romanov@nginx.com goto app_fail; 1554318Smax.romanov@nginx.com } 15551115Svbart@nginx.com 15561115Svbart@nginx.com if (apcf.limits_value != NULL) { 15571115Svbart@nginx.com 15581115Svbart@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 15591115Svbart@nginx.com nxt_alert(task, "application limits is not object"); 15601115Svbart@nginx.com goto app_fail; 15611115Svbart@nginx.com } 15621115Svbart@nginx.com 15631115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 15641115Svbart@nginx.com nxt_router_app_limits_conf, 15651115Svbart@nginx.com nxt_nitems(nxt_router_app_limits_conf), 15661115Svbart@nginx.com &apcf); 15671115Svbart@nginx.com if (ret != NXT_OK) { 15681115Svbart@nginx.com nxt_alert(task, "application limits map error"); 15691115Svbart@nginx.com goto app_fail; 15701115Svbart@nginx.com } 15711115Svbart@nginx.com } 15721115Svbart@nginx.com 15731115Svbart@nginx.com if (apcf.processes_value != NULL 15741115Svbart@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 15751115Svbart@nginx.com { 15761115Svbart@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 15771115Svbart@nginx.com nxt_router_app_processes_conf, 15781115Svbart@nginx.com nxt_nitems(nxt_router_app_processes_conf), 15791115Svbart@nginx.com &apcf); 15801115Svbart@nginx.com if (ret != NXT_OK) { 15811115Svbart@nginx.com nxt_alert(task, "application processes map error"); 15821115Svbart@nginx.com goto app_fail; 15831115Svbart@nginx.com } 15841115Svbart@nginx.com 15851115Svbart@nginx.com } else { 15861115Svbart@nginx.com apcf.max_processes = apcf.processes; 15871115Svbart@nginx.com apcf.spare_processes = apcf.processes; 15881115Svbart@nginx.com } 15891115Svbart@nginx.com 15901115Svbart@nginx.com nxt_debug(task, "application type: %V", &apcf.type); 15911115Svbart@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 15921115Svbart@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 15931115Svbart@nginx.com nxt_debug(task, "application reschedule timeout: %M", 15941115Svbart@nginx.com apcf.res_timeout); 15951115Svbart@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 15961115Svbart@nginx.com 15971115Svbart@nginx.com lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 15981115Svbart@nginx.com 15991115Svbart@nginx.com if (lang == NULL) { 16001115Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1601507Smax.romanov@nginx.com goto app_fail; 1602507Smax.romanov@nginx.com } 1603507Smax.romanov@nginx.com 16041115Svbart@nginx.com nxt_debug(task, "application language module: \"%s\"", lang->file); 16051115Svbart@nginx.com 16061115Svbart@nginx.com ret = nxt_thread_mutex_create(&app->mutex); 16071115Svbart@nginx.com if (ret != NXT_OK) { 16081115Svbart@nginx.com goto app_fail; 16091115Svbart@nginx.com } 16101115Svbart@nginx.com 16111115Svbart@nginx.com nxt_queue_init(&app->ports); 16121115Svbart@nginx.com nxt_queue_init(&app->spare_ports); 16131115Svbart@nginx.com nxt_queue_init(&app->idle_ports); 16141115Svbart@nginx.com nxt_queue_init(&app->requests); 16151115Svbart@nginx.com nxt_queue_init(&app->pending); 16161115Svbart@nginx.com 16171115Svbart@nginx.com app->name.length = name.length; 16181115Svbart@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 16191115Svbart@nginx.com 16201115Svbart@nginx.com app->type = lang->type; 16211115Svbart@nginx.com app->max_processes = apcf.max_processes; 16221115Svbart@nginx.com app->spare_processes = apcf.spare_processes; 16231115Svbart@nginx.com app->max_pending_processes = apcf.spare_processes 16241115Svbart@nginx.com ? apcf.spare_processes : 1; 16251115Svbart@nginx.com app->timeout = apcf.timeout; 16261115Svbart@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 16271115Svbart@nginx.com app->idle_timeout = apcf.idle_timeout; 16281115Svbart@nginx.com app->max_pending_responses = 2; 16291115Svbart@nginx.com app->max_requests = apcf.requests; 16301115Svbart@nginx.com 16311115Svbart@nginx.com engine = task->thread->engine; 16321115Svbart@nginx.com 16331115Svbart@nginx.com app->engine = engine; 16341115Svbart@nginx.com 16351115Svbart@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 16361115Svbart@nginx.com app->adjust_idle_work.task = &engine->task; 16371115Svbart@nginx.com app->adjust_idle_work.obj = app; 16381115Svbart@nginx.com 16391115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->apps, &app->link); 16401115Svbart@nginx.com 16411115Svbart@nginx.com nxt_router_app_use(task, app, 1); 16421115Svbart@nginx.com 16431115Svbart@nginx.com app->joint = app_joint; 16441115Svbart@nginx.com 16451115Svbart@nginx.com app_joint->use_count = 1; 16461115Svbart@nginx.com app_joint->app = app; 16471115Svbart@nginx.com 16481115Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 16491115Svbart@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 16501115Svbart@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 16511115Svbart@nginx.com app_joint->idle_timer.task = &engine->task; 16521115Svbart@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 16531115Svbart@nginx.com 16541115Svbart@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 16551115Svbart@nginx.com app_joint->free_app_work.task = &engine->task; 16561115Svbart@nginx.com app_joint->free_app_work.obj = app_joint; 1657133Sigor@sysoev.ru } 1658133Sigor@sysoev.ru } 1659133Sigor@sysoev.ru 1660964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1661964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1662964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1663964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1664964Sigor@sysoev.ru return NXT_ERROR; 1665964Sigor@sysoev.ru } 1666964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1667964Sigor@sysoev.ru } 1668964Sigor@sysoev.ru 16691394Sigor@sysoev.ru ret = nxt_upstreams_create(task, tmcf, conf); 16701394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 16711394Sigor@sysoev.ru return ret; 16721394Sigor@sysoev.ru } 16731394Sigor@sysoev.ru 1674133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1675133Sigor@sysoev.ru #if 0 1676133Sigor@sysoev.ru if (http == NULL) { 1677564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1678133Sigor@sysoev.ru return NXT_ERROR; 1679133Sigor@sysoev.ru } 1680133Sigor@sysoev.ru #endif 1681133Sigor@sysoev.ru 16821131Smax.romanov@nginx.com websocket = nxt_conf_get_path(conf, &websocket_path); 16831131Smax.romanov@nginx.com 1684133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 16851115Svbart@nginx.com 16861115Svbart@nginx.com if (listeners != NULL) { 16871115Svbart@nginx.com next = 0; 16881115Svbart@nginx.com 16891115Svbart@nginx.com for ( ;; ) { 16901115Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &name, &next); 16911115Svbart@nginx.com if (listener == NULL) { 16921115Svbart@nginx.com break; 16931115Svbart@nginx.com } 16941115Svbart@nginx.com 16951115Svbart@nginx.com skcf = nxt_router_socket_conf(task, tmcf, &name); 16961115Svbart@nginx.com if (skcf == NULL) { 16971115Svbart@nginx.com goto fail; 16981115Svbart@nginx.com } 16991115Svbart@nginx.com 17001115Svbart@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 17011115Svbart@nginx.com 17021115Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 17031115Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), 17041115Svbart@nginx.com &lscf); 1705133Sigor@sysoev.ru if (ret != NXT_OK) { 17061115Svbart@nginx.com nxt_alert(task, "listener map error"); 1707133Sigor@sysoev.ru goto fail; 1708133Sigor@sysoev.ru } 17091115Svbart@nginx.com 17101115Svbart@nginx.com nxt_debug(task, "application: %V", &lscf.application); 17111115Svbart@nginx.com 17121115Svbart@nginx.com // STUB, default values if http block is not defined. 17131115Svbart@nginx.com skcf->header_buffer_size = 2048; 17141115Svbart@nginx.com skcf->large_header_buffer_size = 8192; 17151115Svbart@nginx.com skcf->large_header_buffers = 4; 17161115Svbart@nginx.com skcf->body_buffer_size = 16 * 1024; 17171115Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 17181270Sigor@sysoev.ru skcf->proxy_header_buffer_size = 64 * 1024; 17191270Sigor@sysoev.ru skcf->proxy_buffer_size = 4096; 17201270Sigor@sysoev.ru skcf->proxy_buffers = 256; 17211115Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 17221115Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 17231115Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 17241115Svbart@nginx.com skcf->send_timeout = 30 * 1000; 17251270Sigor@sysoev.ru skcf->proxy_timeout = 60 * 1000; 17261270Sigor@sysoev.ru skcf->proxy_send_timeout = 30 * 1000; 17271270Sigor@sysoev.ru skcf->proxy_read_timeout = 30 * 1000; 17281115Svbart@nginx.com 17291131Smax.romanov@nginx.com skcf->websocket_conf.max_frame_size = 1024 * 1024; 17301131Smax.romanov@nginx.com skcf->websocket_conf.read_timeout = 60 * 1000; 17311131Smax.romanov@nginx.com skcf->websocket_conf.keepalive_interval = 30 * 1000; 17321131Smax.romanov@nginx.com 17331403Smax.romanov@nginx.com nxt_str_null(&skcf->body_temp_path); 17341403Smax.romanov@nginx.com 17351115Svbart@nginx.com if (http != NULL) { 17361115Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 17371115Svbart@nginx.com nxt_nitems(nxt_router_http_conf), 17381115Svbart@nginx.com skcf); 17391115Svbart@nginx.com if (ret != NXT_OK) { 17401115Svbart@nginx.com nxt_alert(task, "http map error"); 17411115Svbart@nginx.com goto fail; 17421115Svbart@nginx.com } 17431115Svbart@nginx.com } 1744115Sigor@sysoev.ru 17451131Smax.romanov@nginx.com if (websocket != NULL) { 17461131Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, websocket, 17471131Smax.romanov@nginx.com nxt_router_websocket_conf, 17481131Smax.romanov@nginx.com nxt_nitems(nxt_router_websocket_conf), 17491131Smax.romanov@nginx.com &skcf->websocket_conf); 17501131Smax.romanov@nginx.com if (ret != NXT_OK) { 17511131Smax.romanov@nginx.com nxt_alert(task, "websocket map error"); 17521131Smax.romanov@nginx.com goto fail; 17531131Smax.romanov@nginx.com } 17541131Smax.romanov@nginx.com } 17551131Smax.romanov@nginx.com 17561403Smax.romanov@nginx.com t = &skcf->body_temp_path; 17571403Smax.romanov@nginx.com 17581403Smax.romanov@nginx.com if (t->length == 0) { 17591403Smax.romanov@nginx.com t->start = (u_char *) task->thread->runtime->tmp; 17601403Smax.romanov@nginx.com t->length = nxt_strlen(t->start); 17611403Smax.romanov@nginx.com } 17621403Smax.romanov@nginx.com 1763774Svbart@nginx.com #if (NXT_TLS) 17641115Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 17651115Svbart@nginx.com 17661115Svbart@nginx.com if (value != NULL) { 17671115Svbart@nginx.com nxt_conf_get_string(value, &name); 17681115Svbart@nginx.com 17691115Svbart@nginx.com tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); 17701115Svbart@nginx.com if (nxt_slow_path(tls == NULL)) { 17711115Svbart@nginx.com goto fail; 17721115Svbart@nginx.com } 17731115Svbart@nginx.com 17741115Svbart@nginx.com tls->name = name; 17751115Svbart@nginx.com tls->conf = skcf; 17761115Svbart@nginx.com 17771115Svbart@nginx.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 1778774Svbart@nginx.com } 1779774Svbart@nginx.com #endif 1780774Svbart@nginx.com 17811115Svbart@nginx.com skcf->listen->handler = nxt_http_conn_init; 17821115Svbart@nginx.com skcf->router_conf = tmcf->router_conf; 17831115Svbart@nginx.com skcf->router_conf->count++; 17841115Svbart@nginx.com 17851115Svbart@nginx.com if (lscf.pass.length != 0) { 17861264Sigor@sysoev.ru skcf->action = nxt_http_action_create(task, tmcf, &lscf.pass); 17871115Svbart@nginx.com 17881115Svbart@nginx.com /* COMPATIBILITY: listener application. */ 17891115Svbart@nginx.com } else if (lscf.application.length > 0) { 17901264Sigor@sysoev.ru skcf->action = nxt_http_pass_application(task, tmcf, 17911264Sigor@sysoev.ru &lscf.application); 17921115Svbart@nginx.com } 1793770Smax.romanov@nginx.com } 1794115Sigor@sysoev.ru } 179553Sigor@sysoev.ru 1796630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1797630Svbart@nginx.com 1798630Svbart@nginx.com if (value != NULL) { 1799630Svbart@nginx.com nxt_conf_get_string(value, &path); 1800630Svbart@nginx.com 1801630Svbart@nginx.com access_log = router->access_log; 1802630Svbart@nginx.com 1803630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1804630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1805630Svbart@nginx.com access_log->count++; 1806630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1807630Svbart@nginx.com 1808630Svbart@nginx.com } else { 1809630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1810630Svbart@nginx.com + path.length); 1811630Svbart@nginx.com if (access_log == NULL) { 1812630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1813630Svbart@nginx.com goto fail; 1814630Svbart@nginx.com } 1815630Svbart@nginx.com 1816630Svbart@nginx.com access_log->fd = -1; 1817630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1818630Svbart@nginx.com access_log->count = 1; 1819630Svbart@nginx.com 1820630Svbart@nginx.com access_log->path.length = path.length; 1821630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1822630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1823630Svbart@nginx.com 1824630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1825630Svbart@nginx.com } 1826630Svbart@nginx.com 1827630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1828630Svbart@nginx.com } 1829630Svbart@nginx.com 1830964Sigor@sysoev.ru nxt_http_routes_resolve(task, tmcf); 1831964Sigor@sysoev.ru 1832359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1833359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1834198Sigor@sysoev.ru 183553Sigor@sysoev.ru return NXT_OK; 1836133Sigor@sysoev.ru 1837133Sigor@sysoev.ru app_fail: 1838133Sigor@sysoev.ru 1839133Sigor@sysoev.ru nxt_free(app); 1840133Sigor@sysoev.ru 1841133Sigor@sysoev.ru fail: 1842133Sigor@sysoev.ru 1843141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1844141Smax.romanov@nginx.com 1845141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1846133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1847133Sigor@sysoev.ru nxt_free(app); 1848141Smax.romanov@nginx.com 1849141Smax.romanov@nginx.com } nxt_queue_loop; 1850133Sigor@sysoev.ru 1851133Sigor@sysoev.ru return NXT_ERROR; 1852133Sigor@sysoev.ru } 1853133Sigor@sysoev.ru 1854133Sigor@sysoev.ru 18551183Svbart@nginx.com static nxt_int_t 18561183Svbart@nginx.com nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, 18571183Svbart@nginx.com nxt_conf_value_t *conf) 18581183Svbart@nginx.com { 18591183Svbart@nginx.com uint32_t next, i; 18601183Svbart@nginx.com nxt_mp_t *mp; 18611183Svbart@nginx.com nxt_str_t *type, extension, str; 18621183Svbart@nginx.com nxt_int_t ret; 18631183Svbart@nginx.com nxt_uint_t exts; 18641183Svbart@nginx.com nxt_conf_value_t *mtypes_conf, *ext_conf, *value; 18651183Svbart@nginx.com 18661183Svbart@nginx.com static nxt_str_t mtypes_path = nxt_string("/mime_types"); 18671183Svbart@nginx.com 18681183Svbart@nginx.com mp = rtcf->mem_pool; 18691183Svbart@nginx.com 18701183Svbart@nginx.com ret = nxt_http_static_mtypes_init(mp, &rtcf->mtypes_hash); 18711183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 18721183Svbart@nginx.com return NXT_ERROR; 18731183Svbart@nginx.com } 18741183Svbart@nginx.com 18751183Svbart@nginx.com if (conf == NULL) { 18761183Svbart@nginx.com return NXT_OK; 18771183Svbart@nginx.com } 18781183Svbart@nginx.com 18791183Svbart@nginx.com mtypes_conf = nxt_conf_get_path(conf, &mtypes_path); 18801183Svbart@nginx.com 18811183Svbart@nginx.com if (mtypes_conf != NULL) { 18821183Svbart@nginx.com next = 0; 18831183Svbart@nginx.com 18841183Svbart@nginx.com for ( ;; ) { 18851183Svbart@nginx.com ext_conf = nxt_conf_next_object_member(mtypes_conf, &str, &next); 18861183Svbart@nginx.com 18871183Svbart@nginx.com if (ext_conf == NULL) { 18881183Svbart@nginx.com break; 18891183Svbart@nginx.com } 18901183Svbart@nginx.com 18911183Svbart@nginx.com type = nxt_str_dup(mp, NULL, &str); 18921183Svbart@nginx.com if (nxt_slow_path(type == NULL)) { 18931183Svbart@nginx.com return NXT_ERROR; 18941183Svbart@nginx.com } 18951183Svbart@nginx.com 18961183Svbart@nginx.com if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) { 18971183Svbart@nginx.com nxt_conf_get_string(ext_conf, &str); 18981183Svbart@nginx.com 18991183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 19001183Svbart@nginx.com return NXT_ERROR; 19011183Svbart@nginx.com } 19021183Svbart@nginx.com 19031183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 19041183Svbart@nginx.com &extension, type); 19051183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 19061183Svbart@nginx.com return NXT_ERROR; 19071183Svbart@nginx.com } 19081183Svbart@nginx.com 19091183Svbart@nginx.com continue; 19101183Svbart@nginx.com } 19111183Svbart@nginx.com 19121183Svbart@nginx.com exts = nxt_conf_array_elements_count(ext_conf); 19131183Svbart@nginx.com 19141183Svbart@nginx.com for (i = 0; i < exts; i++) { 19151183Svbart@nginx.com value = nxt_conf_get_array_element(ext_conf, i); 19161183Svbart@nginx.com 19171183Svbart@nginx.com nxt_conf_get_string(value, &str); 19181183Svbart@nginx.com 19191183Svbart@nginx.com if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) { 19201183Svbart@nginx.com return NXT_ERROR; 19211183Svbart@nginx.com } 19221183Svbart@nginx.com 19231183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash, 19241183Svbart@nginx.com &extension, type); 19251183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 19261183Svbart@nginx.com return NXT_ERROR; 19271183Svbart@nginx.com } 19281183Svbart@nginx.com } 19291183Svbart@nginx.com } 19301183Svbart@nginx.com } 19311183Svbart@nginx.com 19321183Svbart@nginx.com return NXT_OK; 19331183Svbart@nginx.com } 19341183Svbart@nginx.com 19351183Svbart@nginx.com 1936133Sigor@sysoev.ru static nxt_app_t * 1937133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1938133Sigor@sysoev.ru { 1939141Smax.romanov@nginx.com nxt_app_t *app; 1940141Smax.romanov@nginx.com 1941141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1942133Sigor@sysoev.ru 1943133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1944133Sigor@sysoev.ru return app; 1945133Sigor@sysoev.ru } 1946141Smax.romanov@nginx.com 1947141Smax.romanov@nginx.com } nxt_queue_loop; 1948133Sigor@sysoev.ru 1949133Sigor@sysoev.ru return NULL; 1950133Sigor@sysoev.ru } 1951133Sigor@sysoev.ru 1952133Sigor@sysoev.ru 19531392Sigor@sysoev.ru void 19541392Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name, 19551392Sigor@sysoev.ru nxt_http_action_t *action) 1956133Sigor@sysoev.ru { 1957133Sigor@sysoev.ru nxt_app_t *app; 1958133Sigor@sysoev.ru 1959133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1960133Sigor@sysoev.ru 1961133Sigor@sysoev.ru if (app == NULL) { 1962134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1963133Sigor@sysoev.ru } 1964133Sigor@sysoev.ru 19651392Sigor@sysoev.ru action->u.application = app; 19661392Sigor@sysoev.ru action->handler = nxt_http_application_handler; 196753Sigor@sysoev.ru } 196853Sigor@sysoev.ru 196953Sigor@sysoev.ru 197053Sigor@sysoev.ru static nxt_socket_conf_t * 1971359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1972359Sigor@sysoev.ru nxt_str_t *name) 197353Sigor@sysoev.ru { 1974359Sigor@sysoev.ru size_t size; 1975359Sigor@sysoev.ru nxt_int_t ret; 1976359Sigor@sysoev.ru nxt_bool_t wildcard; 1977359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1978359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1979359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1980359Sigor@sysoev.ru 1981359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1982359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1983564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1984359Sigor@sysoev.ru return NULL; 1985359Sigor@sysoev.ru } 1986359Sigor@sysoev.ru 1987359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1988359Sigor@sysoev.ru 1989359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1990493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1991359Sigor@sysoev.ru 1992591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1993163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 199453Sigor@sysoev.ru return NULL; 199553Sigor@sysoev.ru } 199653Sigor@sysoev.ru 1997359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1998359Sigor@sysoev.ru 1999359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 2000359Sigor@sysoev.ru 2001359Sigor@sysoev.ru if (ret != NXT_OK) { 2002359Sigor@sysoev.ru 2003359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 2004359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 2005359Sigor@sysoev.ru return NULL; 2006359Sigor@sysoev.ru } 2007359Sigor@sysoev.ru 2008359Sigor@sysoev.ru skcf->listen = ls; 2009359Sigor@sysoev.ru 2010359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 2011359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 2012359Sigor@sysoev.ru 2013359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 2014359Sigor@sysoev.ru 2015359Sigor@sysoev.ru ls->socket = -1; 2016359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 2017359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 2018359Sigor@sysoev.ru ls->read_after_accept = 1; 2019359Sigor@sysoev.ru } 2020359Sigor@sysoev.ru 2021359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 2022359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 2023359Sigor@sysoev.ru case AF_UNIX: 2024359Sigor@sysoev.ru wildcard = 0; 2025359Sigor@sysoev.ru break; 2026359Sigor@sysoev.ru #endif 2027359Sigor@sysoev.ru #if (NXT_INET6) 2028359Sigor@sysoev.ru case AF_INET6: 2029359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 2030359Sigor@sysoev.ru break; 2031359Sigor@sysoev.ru #endif 2032359Sigor@sysoev.ru case AF_INET: 2033359Sigor@sysoev.ru default: 2034359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 2035359Sigor@sysoev.ru break; 2036359Sigor@sysoev.ru } 2037359Sigor@sysoev.ru 2038359Sigor@sysoev.ru if (!wildcard) { 2039591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 2040359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 2041359Sigor@sysoev.ru return NULL; 2042359Sigor@sysoev.ru } 2043359Sigor@sysoev.ru 2044359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 2045359Sigor@sysoev.ru } 2046163Smax.romanov@nginx.com 2047163Smax.romanov@nginx.com return skcf; 204853Sigor@sysoev.ru } 204953Sigor@sysoev.ru 205053Sigor@sysoev.ru 2051359Sigor@sysoev.ru static nxt_int_t 2052359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 2053359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 205453Sigor@sysoev.ru { 2055359Sigor@sysoev.ru nxt_router_t *router; 2056359Sigor@sysoev.ru nxt_queue_link_t *qlk; 2057359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2058359Sigor@sysoev.ru 2059591Sigor@sysoev.ru router = tmcf->router_conf->router; 2060359Sigor@sysoev.ru 2061359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 2062359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 2063359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 206453Sigor@sysoev.ru { 2065359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2066359Sigor@sysoev.ru 2067359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 2068359Sigor@sysoev.ru nskcf->listen = skcf->listen; 2069359Sigor@sysoev.ru 2070359Sigor@sysoev.ru nxt_queue_remove(qlk); 2071359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 2072359Sigor@sysoev.ru 2073359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 2074359Sigor@sysoev.ru 2075359Sigor@sysoev.ru return NXT_OK; 207653Sigor@sysoev.ru } 207753Sigor@sysoev.ru } 207853Sigor@sysoev.ru 2079359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 2080359Sigor@sysoev.ru 2081359Sigor@sysoev.ru return NXT_DECLINED; 208253Sigor@sysoev.ru } 208353Sigor@sysoev.ru 208453Sigor@sysoev.ru 2085198Sigor@sysoev.ru static void 2086198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 2087198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 2088198Sigor@sysoev.ru { 2089358Sigor@sysoev.ru size_t size; 2090198Sigor@sysoev.ru uint32_t stream; 2091648Svbart@nginx.com nxt_int_t ret; 2092198Sigor@sysoev.ru nxt_buf_t *b; 2093198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 2094198Sigor@sysoev.ru nxt_runtime_t *rt; 2095198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 2096198Sigor@sysoev.ru 2097198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2098198Sigor@sysoev.ru if (rpc == NULL) { 2099198Sigor@sysoev.ru goto fail; 2100198Sigor@sysoev.ru } 2101198Sigor@sysoev.ru 2102198Sigor@sysoev.ru rpc->socket_conf = skcf; 2103198Sigor@sysoev.ru rpc->temp_conf = tmcf; 2104198Sigor@sysoev.ru 2105359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 2106358Sigor@sysoev.ru 2107358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2108198Sigor@sysoev.ru if (b == NULL) { 2109198Sigor@sysoev.ru goto fail; 2110198Sigor@sysoev.ru } 2111198Sigor@sysoev.ru 2112359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 2113198Sigor@sysoev.ru 2114198Sigor@sysoev.ru rt = task->thread->runtime; 2115240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2116198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2117198Sigor@sysoev.ru 2118198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 2119198Sigor@sysoev.ru nxt_router_listen_socket_ready, 2120198Sigor@sysoev.ru nxt_router_listen_socket_error, 2121198Sigor@sysoev.ru main_port->pid, rpc); 2122645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 2123198Sigor@sysoev.ru goto fail; 2124198Sigor@sysoev.ru } 2125198Sigor@sysoev.ru 2126648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 2127648Svbart@nginx.com stream, router_port->id, b); 2128648Svbart@nginx.com 2129648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2130648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2131648Svbart@nginx.com goto fail; 2132648Svbart@nginx.com } 2133198Sigor@sysoev.ru 2134198Sigor@sysoev.ru return; 2135198Sigor@sysoev.ru 2136198Sigor@sysoev.ru fail: 2137198Sigor@sysoev.ru 2138198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 2139198Sigor@sysoev.ru } 2140198Sigor@sysoev.ru 2141198Sigor@sysoev.ru 2142198Sigor@sysoev.ru static void 2143198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2144198Sigor@sysoev.ru void *data) 214553Sigor@sysoev.ru { 2146359Sigor@sysoev.ru nxt_int_t ret; 2147359Sigor@sysoev.ru nxt_socket_t s; 2148359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 214953Sigor@sysoev.ru 2150198Sigor@sysoev.ru rpc = data; 2151198Sigor@sysoev.ru 2152198Sigor@sysoev.ru s = msg->fd; 2153198Sigor@sysoev.ru 2154198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 2155198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2156198Sigor@sysoev.ru goto fail; 215753Sigor@sysoev.ru } 215853Sigor@sysoev.ru 2159359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 2160198Sigor@sysoev.ru 2161198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 2162198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2163198Sigor@sysoev.ru goto fail; 2164198Sigor@sysoev.ru } 2165198Sigor@sysoev.ru 2166359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 2167198Sigor@sysoev.ru 2168198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2169198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2170198Sigor@sysoev.ru 2171198Sigor@sysoev.ru return; 2172148Sigor@sysoev.ru 2173148Sigor@sysoev.ru fail: 2174148Sigor@sysoev.ru 2175148Sigor@sysoev.ru nxt_socket_close(task, s); 2176148Sigor@sysoev.ru 2177198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2178198Sigor@sysoev.ru } 2179198Sigor@sysoev.ru 2180198Sigor@sysoev.ru 2181198Sigor@sysoev.ru static void 2182198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2183198Sigor@sysoev.ru void *data) 2184198Sigor@sysoev.ru { 2185955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2186955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2187955Svbart@nginx.com 2188955Svbart@nginx.com rpc = data; 2189955Svbart@nginx.com tmcf = rpc->temp_conf; 2190955Svbart@nginx.com 2191955Svbart@nginx.com #if 0 2192198Sigor@sysoev.ru u_char *p; 2193198Sigor@sysoev.ru size_t size; 2194198Sigor@sysoev.ru uint8_t error; 2195198Sigor@sysoev.ru nxt_buf_t *in, *out; 2196198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2197198Sigor@sysoev.ru 2198198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2199198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2200198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2201198Sigor@sysoev.ru nxt_string("ListenerPort"), 2202198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2203198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2204198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2205198Sigor@sysoev.ru nxt_string("ListenerPath"), 2206198Sigor@sysoev.ru }; 2207198Sigor@sysoev.ru 2208359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2209352Smax.romanov@nginx.com 2210352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2211352Smax.romanov@nginx.com 2212551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2213551Smax.romanov@nginx.com return; 2214551Smax.romanov@nginx.com } 2215352Smax.romanov@nginx.com 2216198Sigor@sysoev.ru p = in->mem.pos; 2217198Sigor@sysoev.ru 2218198Sigor@sysoev.ru error = *p++; 2219198Sigor@sysoev.ru 2220703Svbart@nginx.com size = nxt_length("listen socket error: ") 2221703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2222198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2223198Sigor@sysoev.ru 2224198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2225198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2226198Sigor@sysoev.ru return; 2227198Sigor@sysoev.ru } 2228198Sigor@sysoev.ru 2229198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2230198Sigor@sysoev.ru "listen socket error: " 2231198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2232493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2233198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2234198Sigor@sysoev.ru 2235198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2236955Svbart@nginx.com #endif 2237198Sigor@sysoev.ru 2238198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 223953Sigor@sysoev.ru } 224053Sigor@sysoev.ru 224153Sigor@sysoev.ru 2242774Svbart@nginx.com #if (NXT_TLS) 2243774Svbart@nginx.com 2244774Svbart@nginx.com static void 2245774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2246774Svbart@nginx.com nxt_router_tlssock_t *tls) 2247774Svbart@nginx.com { 2248774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2249774Svbart@nginx.com 2250774Svbart@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2251774Svbart@nginx.com if (rpc == NULL) { 2252774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2253774Svbart@nginx.com return; 2254774Svbart@nginx.com } 2255774Svbart@nginx.com 2256774Svbart@nginx.com rpc->socket_conf = tls->conf; 2257774Svbart@nginx.com rpc->temp_conf = tmcf; 2258774Svbart@nginx.com 2259774Svbart@nginx.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 2260774Svbart@nginx.com nxt_router_tls_rpc_handler, rpc); 2261774Svbart@nginx.com } 2262774Svbart@nginx.com 2263774Svbart@nginx.com 2264774Svbart@nginx.com static void 2265774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2266774Svbart@nginx.com void *data) 2267774Svbart@nginx.com { 2268774Svbart@nginx.com nxt_mp_t *mp; 2269774Svbart@nginx.com nxt_int_t ret; 2270774Svbart@nginx.com nxt_tls_conf_t *tlscf; 2271774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2272774Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2273774Svbart@nginx.com 2274774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2275774Svbart@nginx.com 2276774Svbart@nginx.com rpc = data; 2277774Svbart@nginx.com tmcf = rpc->temp_conf; 2278774Svbart@nginx.com 2279774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2280774Svbart@nginx.com goto fail; 2281774Svbart@nginx.com } 2282774Svbart@nginx.com 2283774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2284774Svbart@nginx.com 2285774Svbart@nginx.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 2286774Svbart@nginx.com if (nxt_slow_path(tlscf == NULL)) { 2287774Svbart@nginx.com goto fail; 2288774Svbart@nginx.com } 2289774Svbart@nginx.com 2290774Svbart@nginx.com tlscf->chain_file = msg->fd; 2291774Svbart@nginx.com 2292774Svbart@nginx.com ret = task->thread->runtime->tls->server_init(task, tlscf); 2293774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2294774Svbart@nginx.com goto fail; 2295774Svbart@nginx.com } 2296774Svbart@nginx.com 2297774Svbart@nginx.com rpc->socket_conf->tls = tlscf; 2298774Svbart@nginx.com 2299774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2300774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2301774Svbart@nginx.com return; 2302774Svbart@nginx.com 2303774Svbart@nginx.com fail: 2304774Svbart@nginx.com 2305774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2306774Svbart@nginx.com } 2307774Svbart@nginx.com 2308774Svbart@nginx.com #endif 2309774Svbart@nginx.com 2310774Svbart@nginx.com 2311507Smax.romanov@nginx.com static void 2312507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2313507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2314507Smax.romanov@nginx.com { 2315507Smax.romanov@nginx.com size_t size; 2316507Smax.romanov@nginx.com uint32_t stream; 2317648Svbart@nginx.com nxt_int_t ret; 2318507Smax.romanov@nginx.com nxt_buf_t *b; 2319507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 2320507Smax.romanov@nginx.com nxt_runtime_t *rt; 2321507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2322507Smax.romanov@nginx.com 2323507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 2324507Smax.romanov@nginx.com if (rpc == NULL) { 2325507Smax.romanov@nginx.com goto fail; 2326507Smax.romanov@nginx.com } 2327507Smax.romanov@nginx.com 2328507Smax.romanov@nginx.com rpc->app = app; 2329507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2330507Smax.romanov@nginx.com 2331507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 2332507Smax.romanov@nginx.com 2333507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 2334507Smax.romanov@nginx.com 2335507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2336507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2337507Smax.romanov@nginx.com goto fail; 2338507Smax.romanov@nginx.com } 2339507Smax.romanov@nginx.com 2340507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 2341507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 2342507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2343507Smax.romanov@nginx.com 2344507Smax.romanov@nginx.com rt = task->thread->runtime; 2345507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2346507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2347507Smax.romanov@nginx.com 2348507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2349507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 2350507Smax.romanov@nginx.com nxt_router_app_prefork_error, 2351507Smax.romanov@nginx.com -1, rpc); 2352507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2353507Smax.romanov@nginx.com goto fail; 2354507Smax.romanov@nginx.com } 2355507Smax.romanov@nginx.com 2356648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2357648Svbart@nginx.com stream, router_port->id, b); 2358648Svbart@nginx.com 2359648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2360648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2361648Svbart@nginx.com goto fail; 2362648Svbart@nginx.com } 2363648Svbart@nginx.com 2364507Smax.romanov@nginx.com app->pending_processes++; 2365507Smax.romanov@nginx.com 2366507Smax.romanov@nginx.com return; 2367507Smax.romanov@nginx.com 2368507Smax.romanov@nginx.com fail: 2369507Smax.romanov@nginx.com 2370507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2371507Smax.romanov@nginx.com } 2372507Smax.romanov@nginx.com 2373507Smax.romanov@nginx.com 2374507Smax.romanov@nginx.com static void 2375507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2376507Smax.romanov@nginx.com void *data) 2377507Smax.romanov@nginx.com { 2378507Smax.romanov@nginx.com nxt_app_t *app; 2379507Smax.romanov@nginx.com nxt_port_t *port; 2380507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2381507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2382507Smax.romanov@nginx.com 2383507Smax.romanov@nginx.com rpc = data; 2384507Smax.romanov@nginx.com app = rpc->app; 2385507Smax.romanov@nginx.com 2386507Smax.romanov@nginx.com port = msg->u.new_port; 2387507Smax.romanov@nginx.com port->app = app; 2388507Smax.romanov@nginx.com 2389507Smax.romanov@nginx.com app->pending_processes--; 2390507Smax.romanov@nginx.com app->processes++; 2391507Smax.romanov@nginx.com app->idle_processes++; 2392507Smax.romanov@nginx.com 2393507Smax.romanov@nginx.com engine = task->thread->engine; 2394507Smax.romanov@nginx.com 2395507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2396507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 2397507Smax.romanov@nginx.com 2398507Smax.romanov@nginx.com port->idle_start = 0; 2399507Smax.romanov@nginx.com 2400507Smax.romanov@nginx.com nxt_port_inc_use(port); 2401507Smax.romanov@nginx.com 2402507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2403507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2404507Smax.romanov@nginx.com } 2405507Smax.romanov@nginx.com 2406507Smax.romanov@nginx.com 2407507Smax.romanov@nginx.com static void 2408507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2409507Smax.romanov@nginx.com void *data) 2410507Smax.romanov@nginx.com { 2411507Smax.romanov@nginx.com nxt_app_t *app; 2412507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2413507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2414507Smax.romanov@nginx.com 2415507Smax.romanov@nginx.com rpc = data; 2416507Smax.romanov@nginx.com app = rpc->app; 2417507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2418507Smax.romanov@nginx.com 2419507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2420507Smax.romanov@nginx.com &app->name); 2421507Smax.romanov@nginx.com 2422507Smax.romanov@nginx.com app->pending_processes--; 2423507Smax.romanov@nginx.com 2424507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2425507Smax.romanov@nginx.com } 2426507Smax.romanov@nginx.com 2427507Smax.romanov@nginx.com 242853Sigor@sysoev.ru static nxt_int_t 242953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 243053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 243153Sigor@sysoev.ru { 243253Sigor@sysoev.ru nxt_int_t ret; 243353Sigor@sysoev.ru nxt_uint_t n, threads; 243453Sigor@sysoev.ru nxt_queue_link_t *qlk; 243553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 243653Sigor@sysoev.ru 2437591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 243853Sigor@sysoev.ru 243953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 244053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 244153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 244253Sigor@sysoev.ru return NXT_ERROR; 244353Sigor@sysoev.ru } 244453Sigor@sysoev.ru 244553Sigor@sysoev.ru n = 0; 244653Sigor@sysoev.ru 244753Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 244853Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 244953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 245053Sigor@sysoev.ru { 245153Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 245253Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 245353Sigor@sysoev.ru return NXT_ERROR; 245453Sigor@sysoev.ru } 245553Sigor@sysoev.ru 2456115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 245753Sigor@sysoev.ru 245853Sigor@sysoev.ru if (n < threads) { 2459315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2460115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 246153Sigor@sysoev.ru 246253Sigor@sysoev.ru } else { 2463315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2464115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 246553Sigor@sysoev.ru } 246653Sigor@sysoev.ru 246753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 246853Sigor@sysoev.ru return ret; 246953Sigor@sysoev.ru } 247053Sigor@sysoev.ru 247153Sigor@sysoev.ru n++; 247253Sigor@sysoev.ru } 247353Sigor@sysoev.ru 247453Sigor@sysoev.ru tmcf->new_threads = n; 247553Sigor@sysoev.ru 247653Sigor@sysoev.ru while (n < threads) { 247753Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 247853Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 247953Sigor@sysoev.ru return NXT_ERROR; 248053Sigor@sysoev.ru } 248153Sigor@sysoev.ru 2482315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2483315Sigor@sysoev.ru 248453Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 248553Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 248653Sigor@sysoev.ru return NXT_ERROR; 248753Sigor@sysoev.ru } 248853Sigor@sysoev.ru 2489115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 249053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 249153Sigor@sysoev.ru return ret; 249253Sigor@sysoev.ru } 249353Sigor@sysoev.ru 249453Sigor@sysoev.ru n++; 249553Sigor@sysoev.ru } 249653Sigor@sysoev.ru 249753Sigor@sysoev.ru return NXT_OK; 249853Sigor@sysoev.ru } 249953Sigor@sysoev.ru 250053Sigor@sysoev.ru 250153Sigor@sysoev.ru static nxt_int_t 2502115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2503115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 250453Sigor@sysoev.ru { 2505359Sigor@sysoev.ru nxt_int_t ret; 250653Sigor@sysoev.ru 2507154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2508154Sigor@sysoev.ru nxt_router_listen_socket_create); 2509115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2510115Sigor@sysoev.ru return ret; 2511115Sigor@sysoev.ru } 2512115Sigor@sysoev.ru 2513154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2514154Sigor@sysoev.ru nxt_router_listen_socket_create); 251553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 251653Sigor@sysoev.ru return ret; 251753Sigor@sysoev.ru } 251853Sigor@sysoev.ru 2519115Sigor@sysoev.ru return ret; 252053Sigor@sysoev.ru } 252153Sigor@sysoev.ru 252253Sigor@sysoev.ru 252353Sigor@sysoev.ru static nxt_int_t 2524115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2525115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 252653Sigor@sysoev.ru { 2527359Sigor@sysoev.ru nxt_int_t ret; 252853Sigor@sysoev.ru 2529154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2530154Sigor@sysoev.ru nxt_router_listen_socket_create); 253153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 253253Sigor@sysoev.ru return ret; 253353Sigor@sysoev.ru } 253453Sigor@sysoev.ru 2535154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2536154Sigor@sysoev.ru nxt_router_listen_socket_update); 253753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 253853Sigor@sysoev.ru return ret; 253953Sigor@sysoev.ru } 254053Sigor@sysoev.ru 2541139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2542115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2543115Sigor@sysoev.ru return ret; 2544115Sigor@sysoev.ru } 2545115Sigor@sysoev.ru 2546115Sigor@sysoev.ru return ret; 254753Sigor@sysoev.ru } 254853Sigor@sysoev.ru 254953Sigor@sysoev.ru 255053Sigor@sysoev.ru static nxt_int_t 2551115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2552115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 255353Sigor@sysoev.ru { 255453Sigor@sysoev.ru nxt_int_t ret; 255553Sigor@sysoev.ru 2556313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2557313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2558313Sigor@sysoev.ru return ret; 2559313Sigor@sysoev.ru } 2560313Sigor@sysoev.ru 2561139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 256253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 256353Sigor@sysoev.ru return ret; 256453Sigor@sysoev.ru } 256553Sigor@sysoev.ru 2566139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 256753Sigor@sysoev.ru } 256853Sigor@sysoev.ru 256953Sigor@sysoev.ru 257053Sigor@sysoev.ru static nxt_int_t 2571154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2572154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 257353Sigor@sysoev.ru nxt_work_handler_t handler) 257453Sigor@sysoev.ru { 25751394Sigor@sysoev.ru nxt_int_t ret; 2576153Sigor@sysoev.ru nxt_joint_job_t *job; 257753Sigor@sysoev.ru nxt_queue_link_t *qlk; 2578155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 257953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 258053Sigor@sysoev.ru 258153Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 258253Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 258353Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 258453Sigor@sysoev.ru { 2585154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2586153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2587139Sigor@sysoev.ru return NXT_ERROR; 2588139Sigor@sysoev.ru } 2589139Sigor@sysoev.ru 2590154Sigor@sysoev.ru job->work.next = recf->jobs; 2591154Sigor@sysoev.ru recf->jobs = &job->work; 2592154Sigor@sysoev.ru 2593153Sigor@sysoev.ru job->task = tmcf->engine->task; 2594153Sigor@sysoev.ru job->work.handler = handler; 2595153Sigor@sysoev.ru job->work.task = &job->task; 2596153Sigor@sysoev.ru job->work.obj = job; 2597153Sigor@sysoev.ru job->tmcf = tmcf; 259853Sigor@sysoev.ru 2599154Sigor@sysoev.ru tmcf->count++; 2600154Sigor@sysoev.ru 2601591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2602154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 260353Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 260453Sigor@sysoev.ru return NXT_ERROR; 260553Sigor@sysoev.ru } 260653Sigor@sysoev.ru 2607153Sigor@sysoev.ru job->work.data = joint; 260853Sigor@sysoev.ru 26091394Sigor@sysoev.ru ret = nxt_upstreams_joint_create(tmcf, &joint->upstreams); 26101394Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 26111394Sigor@sysoev.ru return ret; 26121394Sigor@sysoev.ru } 26131394Sigor@sysoev.ru 261453Sigor@sysoev.ru joint->count = 1; 2615155Sigor@sysoev.ru 2616155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2617155Sigor@sysoev.ru skcf->count++; 2618155Sigor@sysoev.ru joint->socket_conf = skcf; 2619155Sigor@sysoev.ru 262088Smax.romanov@nginx.com joint->engine = recf->engine; 262153Sigor@sysoev.ru } 262253Sigor@sysoev.ru 262320Sigor@sysoev.ru return NXT_OK; 262420Sigor@sysoev.ru } 262520Sigor@sysoev.ru 262620Sigor@sysoev.ru 262720Sigor@sysoev.ru static nxt_int_t 2628313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2629313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2630313Sigor@sysoev.ru { 2631313Sigor@sysoev.ru nxt_joint_job_t *job; 2632313Sigor@sysoev.ru 2633313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2634313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2635313Sigor@sysoev.ru return NXT_ERROR; 2636313Sigor@sysoev.ru } 2637313Sigor@sysoev.ru 2638313Sigor@sysoev.ru job->work.next = recf->jobs; 2639313Sigor@sysoev.ru recf->jobs = &job->work; 2640313Sigor@sysoev.ru 2641313Sigor@sysoev.ru job->task = tmcf->engine->task; 2642313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2643313Sigor@sysoev.ru job->work.task = &job->task; 2644313Sigor@sysoev.ru job->work.obj = NULL; 2645313Sigor@sysoev.ru job->work.data = NULL; 2646313Sigor@sysoev.ru job->tmcf = NULL; 2647313Sigor@sysoev.ru 2648313Sigor@sysoev.ru return NXT_OK; 2649313Sigor@sysoev.ru } 2650313Sigor@sysoev.ru 2651313Sigor@sysoev.ru 2652313Sigor@sysoev.ru static nxt_int_t 2653139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2654139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 265520Sigor@sysoev.ru { 2656153Sigor@sysoev.ru nxt_joint_job_t *job; 265753Sigor@sysoev.ru nxt_queue_link_t *qlk; 265820Sigor@sysoev.ru 265953Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 266053Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 266153Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 266253Sigor@sysoev.ru { 2663154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2664153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2665139Sigor@sysoev.ru return NXT_ERROR; 2666139Sigor@sysoev.ru } 2667139Sigor@sysoev.ru 2668154Sigor@sysoev.ru job->work.next = recf->jobs; 2669154Sigor@sysoev.ru recf->jobs = &job->work; 2670154Sigor@sysoev.ru 2671153Sigor@sysoev.ru job->task = tmcf->engine->task; 2672153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2673153Sigor@sysoev.ru job->work.task = &job->task; 2674153Sigor@sysoev.ru job->work.obj = job; 2675153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2676153Sigor@sysoev.ru job->tmcf = tmcf; 2677154Sigor@sysoev.ru 2678154Sigor@sysoev.ru tmcf->count++; 267920Sigor@sysoev.ru } 268020Sigor@sysoev.ru 268153Sigor@sysoev.ru return NXT_OK; 268253Sigor@sysoev.ru } 268320Sigor@sysoev.ru 268420Sigor@sysoev.ru 268553Sigor@sysoev.ru static nxt_int_t 268653Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 268753Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 268853Sigor@sysoev.ru { 268953Sigor@sysoev.ru nxt_int_t ret; 269053Sigor@sysoev.ru nxt_uint_t i, threads; 269153Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 269220Sigor@sysoev.ru 269353Sigor@sysoev.ru recf = tmcf->engines->elts; 2694591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 269520Sigor@sysoev.ru 269653Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 269753Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 269853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 269953Sigor@sysoev.ru return ret; 270053Sigor@sysoev.ru } 270120Sigor@sysoev.ru } 270220Sigor@sysoev.ru 270320Sigor@sysoev.ru return NXT_OK; 270420Sigor@sysoev.ru } 270553Sigor@sysoev.ru 270653Sigor@sysoev.ru 270753Sigor@sysoev.ru static nxt_int_t 270853Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 270953Sigor@sysoev.ru nxt_event_engine_t *engine) 271053Sigor@sysoev.ru { 271153Sigor@sysoev.ru nxt_int_t ret; 271253Sigor@sysoev.ru nxt_thread_link_t *link; 271353Sigor@sysoev.ru nxt_thread_handle_t handle; 271453Sigor@sysoev.ru 271553Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 271653Sigor@sysoev.ru 271753Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 271853Sigor@sysoev.ru return NXT_ERROR; 271953Sigor@sysoev.ru } 272053Sigor@sysoev.ru 272153Sigor@sysoev.ru link->start = nxt_router_thread_start; 272253Sigor@sysoev.ru link->engine = engine; 272353Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 272453Sigor@sysoev.ru link->work.task = task; 272553Sigor@sysoev.ru link->work.data = link; 272653Sigor@sysoev.ru 272753Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 272853Sigor@sysoev.ru 272953Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 273053Sigor@sysoev.ru 273153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 273253Sigor@sysoev.ru nxt_queue_remove(&engine->link); 273353Sigor@sysoev.ru } 273453Sigor@sysoev.ru 273553Sigor@sysoev.ru return ret; 273653Sigor@sysoev.ru } 273753Sigor@sysoev.ru 273853Sigor@sysoev.ru 273953Sigor@sysoev.ru static void 2740343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2741343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2742133Sigor@sysoev.ru { 2743507Smax.romanov@nginx.com nxt_app_t *app; 2744141Smax.romanov@nginx.com 2745141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2746133Sigor@sysoev.ru 2747753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2748343Smax.romanov@nginx.com 2749141Smax.romanov@nginx.com } nxt_queue_loop; 2750133Sigor@sysoev.ru 2751133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2752133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2753133Sigor@sysoev.ru } 2754133Sigor@sysoev.ru 2755133Sigor@sysoev.ru 2756133Sigor@sysoev.ru static void 2757315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 275853Sigor@sysoev.ru { 275953Sigor@sysoev.ru nxt_uint_t n; 2760315Sigor@sysoev.ru nxt_event_engine_t *engine; 276153Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 276253Sigor@sysoev.ru 276353Sigor@sysoev.ru recf = tmcf->engines->elts; 276453Sigor@sysoev.ru 276553Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2766315Sigor@sysoev.ru engine = recf->engine; 2767315Sigor@sysoev.ru 2768315Sigor@sysoev.ru switch (recf->action) { 2769315Sigor@sysoev.ru 2770315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2771315Sigor@sysoev.ru break; 2772315Sigor@sysoev.ru 2773315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2774315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2775315Sigor@sysoev.ru break; 2776315Sigor@sysoev.ru 2777315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2778315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2779315Sigor@sysoev.ru break; 2780315Sigor@sysoev.ru } 2781315Sigor@sysoev.ru 2782316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2783316Sigor@sysoev.ru 278453Sigor@sysoev.ru recf++; 278553Sigor@sysoev.ru } 278653Sigor@sysoev.ru } 278753Sigor@sysoev.ru 278853Sigor@sysoev.ru 278953Sigor@sysoev.ru static void 2790315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 279153Sigor@sysoev.ru { 2792154Sigor@sysoev.ru nxt_work_t *work, *next; 2793154Sigor@sysoev.ru 2794315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2795154Sigor@sysoev.ru next = work->next; 2796154Sigor@sysoev.ru work->next = NULL; 2797154Sigor@sysoev.ru 2798315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 279953Sigor@sysoev.ru } 280053Sigor@sysoev.ru } 280153Sigor@sysoev.ru 280253Sigor@sysoev.ru 2803320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2804616Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2805616Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2806616Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 28071321Smax.romanov@nginx.com .oosm = nxt_router_oosm_handler, 280888Smax.romanov@nginx.com }; 280988Smax.romanov@nginx.com 281088Smax.romanov@nginx.com 281188Smax.romanov@nginx.com static void 281253Sigor@sysoev.ru nxt_router_thread_start(void *data) 281353Sigor@sysoev.ru { 2814141Smax.romanov@nginx.com nxt_int_t ret; 2815141Smax.romanov@nginx.com nxt_port_t *port; 281688Smax.romanov@nginx.com nxt_task_t *task; 281753Sigor@sysoev.ru nxt_thread_t *thread; 281853Sigor@sysoev.ru nxt_thread_link_t *link; 281953Sigor@sysoev.ru nxt_event_engine_t *engine; 282053Sigor@sysoev.ru 282153Sigor@sysoev.ru link = data; 282253Sigor@sysoev.ru engine = link->engine; 282388Smax.romanov@nginx.com task = &engine->task; 282453Sigor@sysoev.ru 282553Sigor@sysoev.ru thread = nxt_thread(); 282653Sigor@sysoev.ru 2827165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2828165Smax.romanov@nginx.com 282953Sigor@sysoev.ru /* STUB */ 283053Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 283153Sigor@sysoev.ru 283253Sigor@sysoev.ru engine->task.thread = thread; 283353Sigor@sysoev.ru engine->task.log = thread->log; 283453Sigor@sysoev.ru thread->engine = engine; 283563Sigor@sysoev.ru thread->task = &engine->task; 2836326Svbart@nginx.com #if 0 283753Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2838326Svbart@nginx.com #endif 283953Sigor@sysoev.ru 284063Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2841337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2842337Sigor@sysoev.ru return; 2843337Sigor@sysoev.ru } 284453Sigor@sysoev.ru 2845197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2846197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2847141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2848141Smax.romanov@nginx.com return; 2849141Smax.romanov@nginx.com } 2850141Smax.romanov@nginx.com 2851141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2852141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2853343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2854141Smax.romanov@nginx.com return; 2855141Smax.romanov@nginx.com } 2856141Smax.romanov@nginx.com 2857141Smax.romanov@nginx.com engine->port = port; 2858141Smax.romanov@nginx.com 2859320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2860141Smax.romanov@nginx.com 286153Sigor@sysoev.ru nxt_event_engine_start(engine); 286253Sigor@sysoev.ru } 286353Sigor@sysoev.ru 286453Sigor@sysoev.ru 286553Sigor@sysoev.ru static void 286653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 286753Sigor@sysoev.ru { 2868153Sigor@sysoev.ru nxt_joint_job_t *job; 2869359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2870359Sigor@sysoev.ru nxt_listen_event_t *lev; 287153Sigor@sysoev.ru nxt_listen_socket_t *ls; 2872359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 287353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 287453Sigor@sysoev.ru 2875153Sigor@sysoev.ru job = obj; 287653Sigor@sysoev.ru joint = data; 287753Sigor@sysoev.ru 2878159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2879159Sigor@sysoev.ru 2880359Sigor@sysoev.ru skcf = joint->socket_conf; 2881359Sigor@sysoev.ru ls = skcf->listen; 2882359Sigor@sysoev.ru 2883359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2884359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2885359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 288653Sigor@sysoev.ru return; 288753Sigor@sysoev.ru } 288853Sigor@sysoev.ru 2889359Sigor@sysoev.ru lev->socket.data = joint; 2890359Sigor@sysoev.ru 2891359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2892359Sigor@sysoev.ru 2893359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2894359Sigor@sysoev.ru ls->count++; 2895359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2896139Sigor@sysoev.ru 2897153Sigor@sysoev.ru job->work.next = NULL; 2898153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2899153Sigor@sysoev.ru 2900153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 290153Sigor@sysoev.ru } 290253Sigor@sysoev.ru 290353Sigor@sysoev.ru 290453Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 290553Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 290653Sigor@sysoev.ru nxt_socket_conf_t *skcf) 290753Sigor@sysoev.ru { 2908115Sigor@sysoev.ru nxt_socket_t fd; 2909115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2910359Sigor@sysoev.ru nxt_listen_event_t *lev; 2911359Sigor@sysoev.ru 2912359Sigor@sysoev.ru fd = skcf->listen->socket; 291353Sigor@sysoev.ru 2914115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2915115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2916115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 291753Sigor@sysoev.ru { 2918359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2919359Sigor@sysoev.ru 2920359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2921359Sigor@sysoev.ru return lev; 292253Sigor@sysoev.ru } 292353Sigor@sysoev.ru } 292453Sigor@sysoev.ru 292553Sigor@sysoev.ru return NULL; 292653Sigor@sysoev.ru } 292753Sigor@sysoev.ru 292853Sigor@sysoev.ru 292953Sigor@sysoev.ru static void 293053Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 293153Sigor@sysoev.ru { 2932153Sigor@sysoev.ru nxt_joint_job_t *job; 293353Sigor@sysoev.ru nxt_event_engine_t *engine; 2934359Sigor@sysoev.ru nxt_listen_event_t *lev; 293553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 293653Sigor@sysoev.ru 2937153Sigor@sysoev.ru job = obj; 293853Sigor@sysoev.ru joint = data; 293953Sigor@sysoev.ru 2940139Sigor@sysoev.ru engine = task->thread->engine; 2941139Sigor@sysoev.ru 2942159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2943159Sigor@sysoev.ru 2944359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2945359Sigor@sysoev.ru joint->socket_conf); 2946359Sigor@sysoev.ru 2947359Sigor@sysoev.ru old = lev->socket.data; 2948359Sigor@sysoev.ru lev->socket.data = joint; 2949359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 295053Sigor@sysoev.ru 2951153Sigor@sysoev.ru job->work.next = NULL; 2952153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2953153Sigor@sysoev.ru 2954153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2955139Sigor@sysoev.ru 2956181Smax.romanov@nginx.com /* 2957181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2958181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2959181Smax.romanov@nginx.com */ 2960181Smax.romanov@nginx.com 2961181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 296253Sigor@sysoev.ru } 296353Sigor@sysoev.ru 296453Sigor@sysoev.ru 296553Sigor@sysoev.ru static void 296653Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 296753Sigor@sysoev.ru { 2968153Sigor@sysoev.ru nxt_joint_job_t *job; 2969153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2970359Sigor@sysoev.ru nxt_listen_event_t *lev; 2971153Sigor@sysoev.ru nxt_event_engine_t *engine; 2972153Sigor@sysoev.ru 2973153Sigor@sysoev.ru job = obj; 297453Sigor@sysoev.ru skcf = data; 297553Sigor@sysoev.ru 2976139Sigor@sysoev.ru engine = task->thread->engine; 2977139Sigor@sysoev.ru 2978359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2979359Sigor@sysoev.ru 2980359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 298153Sigor@sysoev.ru 2982163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2983359Sigor@sysoev.ru lev->socket.fd); 2984359Sigor@sysoev.ru 2985359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2986359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2987359Sigor@sysoev.ru 2988359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2989139Sigor@sysoev.ru 2990153Sigor@sysoev.ru job->work.next = NULL; 2991153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2992153Sigor@sysoev.ru 2993153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 299453Sigor@sysoev.ru } 299553Sigor@sysoev.ru 299653Sigor@sysoev.ru 299753Sigor@sysoev.ru static void 2998313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2999313Sigor@sysoev.ru { 3000313Sigor@sysoev.ru nxt_event_engine_t *engine; 3001313Sigor@sysoev.ru 3002313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 3003313Sigor@sysoev.ru 3004313Sigor@sysoev.ru engine = task->thread->engine; 3005313Sigor@sysoev.ru 3006313Sigor@sysoev.ru engine->shutdown = 1; 3007313Sigor@sysoev.ru 3008313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 3009313Sigor@sysoev.ru nxt_thread_exit(task->thread); 3010313Sigor@sysoev.ru } 3011313Sigor@sysoev.ru } 3012313Sigor@sysoev.ru 3013313Sigor@sysoev.ru 3014313Sigor@sysoev.ru static void 301553Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 301653Sigor@sysoev.ru { 301753Sigor@sysoev.ru nxt_timer_t *timer; 3018359Sigor@sysoev.ru nxt_listen_event_t *lev; 301953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 302053Sigor@sysoev.ru 302153Sigor@sysoev.ru timer = obj; 3022359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 302353Sigor@sysoev.ru 3024163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 3025359Sigor@sysoev.ru lev->socket.fd); 3026359Sigor@sysoev.ru 3027359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 3028359Sigor@sysoev.ru 3029683Sigor@sysoev.ru joint = lev->socket.data; 3030683Sigor@sysoev.ru lev->socket.data = NULL; 3031683Sigor@sysoev.ru 3032359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 3033123Smax.romanov@nginx.com task = &task->thread->engine->task; 3034123Smax.romanov@nginx.com 3035359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 3036359Sigor@sysoev.ru 3037683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 303853Sigor@sysoev.ru } 303953Sigor@sysoev.ru 304053Sigor@sysoev.ru 304153Sigor@sysoev.ru static void 3042359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 304353Sigor@sysoev.ru { 3044359Sigor@sysoev.ru nxt_listen_socket_t *ls; 304553Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 304653Sigor@sysoev.ru 3047359Sigor@sysoev.ru ls = skcf->listen; 3048118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 304953Sigor@sysoev.ru 305053Sigor@sysoev.ru nxt_thread_spin_lock(lock); 305153Sigor@sysoev.ru 3052359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 3053359Sigor@sysoev.ru task->thread->engine, ls->count); 3054359Sigor@sysoev.ru 3055359Sigor@sysoev.ru if (--ls->count != 0) { 3056359Sigor@sysoev.ru ls = NULL; 305753Sigor@sysoev.ru } 305853Sigor@sysoev.ru 305953Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 306053Sigor@sysoev.ru 3061359Sigor@sysoev.ru if (ls != NULL) { 3062359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 3063359Sigor@sysoev.ru nxt_free(ls); 306453Sigor@sysoev.ru } 306553Sigor@sysoev.ru } 306653Sigor@sysoev.ru 306753Sigor@sysoev.ru 3068683Sigor@sysoev.ru void 3069683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 3070683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 3071683Sigor@sysoev.ru { 3072683Sigor@sysoev.ru nxt_event_engine_t *engine; 3073683Sigor@sysoev.ru 3074683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 3075683Sigor@sysoev.ru 3076683Sigor@sysoev.ru if (--lev->count == 0) { 3077683Sigor@sysoev.ru nxt_free(lev); 3078683Sigor@sysoev.ru } 3079683Sigor@sysoev.ru 3080683Sigor@sysoev.ru if (joint != NULL) { 3081683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 3082683Sigor@sysoev.ru } 3083683Sigor@sysoev.ru 3084683Sigor@sysoev.ru engine = task->thread->engine; 3085683Sigor@sysoev.ru 3086683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 3087683Sigor@sysoev.ru nxt_thread_exit(task->thread); 3088683Sigor@sysoev.ru } 3089683Sigor@sysoev.ru } 3090683Sigor@sysoev.ru 3091683Sigor@sysoev.ru 3092683Sigor@sysoev.ru void 309353Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 309453Sigor@sysoev.ru { 309553Sigor@sysoev.ru nxt_socket_conf_t *skcf; 309653Sigor@sysoev.ru nxt_router_conf_t *rtcf; 309753Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 309853Sigor@sysoev.ru 3099163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 310053Sigor@sysoev.ru 310153Sigor@sysoev.ru if (--joint->count != 0) { 310253Sigor@sysoev.ru return; 310353Sigor@sysoev.ru } 310453Sigor@sysoev.ru 310553Sigor@sysoev.ru nxt_queue_remove(&joint->link); 310653Sigor@sysoev.ru 3107530Sigor@sysoev.ru /* 3108530Sigor@sysoev.ru * The joint content can not be safely used after the critical 3109530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 3110530Sigor@sysoev.ru * be already destroyed by another thread. 3111530Sigor@sysoev.ru */ 311253Sigor@sysoev.ru skcf = joint->socket_conf; 311353Sigor@sysoev.ru rtcf = skcf->router_conf; 311453Sigor@sysoev.ru lock = &rtcf->router->lock; 311553Sigor@sysoev.ru 311653Sigor@sysoev.ru nxt_thread_spin_lock(lock); 311753Sigor@sysoev.ru 3118163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 3119163Smax.romanov@nginx.com rtcf, rtcf->count); 3120163Smax.romanov@nginx.com 312153Sigor@sysoev.ru if (--skcf->count != 0) { 3122952Sigor@sysoev.ru skcf = NULL; 312353Sigor@sysoev.ru rtcf = NULL; 312453Sigor@sysoev.ru 312553Sigor@sysoev.ru } else { 312653Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 312753Sigor@sysoev.ru 312853Sigor@sysoev.ru if (--rtcf->count != 0) { 312953Sigor@sysoev.ru rtcf = NULL; 313053Sigor@sysoev.ru } 313153Sigor@sysoev.ru } 313253Sigor@sysoev.ru 313353Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 313453Sigor@sysoev.ru 3135952Sigor@sysoev.ru if (skcf != NULL) { 31361264Sigor@sysoev.ru if (skcf->action != NULL) { 31371264Sigor@sysoev.ru nxt_http_action_cleanup(task, skcf->action); 3138964Sigor@sysoev.ru } 3139964Sigor@sysoev.ru 3140952Sigor@sysoev.ru #if (NXT_TLS) 3141952Sigor@sysoev.ru if (skcf->tls != NULL) { 3142952Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 3143952Sigor@sysoev.ru } 3144952Sigor@sysoev.ru #endif 3145952Sigor@sysoev.ru } 3146952Sigor@sysoev.ru 3147141Smax.romanov@nginx.com /* TODO remove engine->port */ 3148141Smax.romanov@nginx.com /* TODO excude from connected ports */ 3149141Smax.romanov@nginx.com 315053Sigor@sysoev.ru if (rtcf != NULL) { 3151115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 3152131Smax.romanov@nginx.com 3153964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 3154964Sigor@sysoev.ru 3155630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 3156630Svbart@nginx.com 3157131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 3158131Smax.romanov@nginx.com 315965Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 316053Sigor@sysoev.ru } 316153Sigor@sysoev.ru } 316253Sigor@sysoev.ru 316353Sigor@sysoev.ru 316453Sigor@sysoev.ru static void 3165630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 3166630Svbart@nginx.com nxt_router_access_log_t *access_log) 3167630Svbart@nginx.com { 3168630Svbart@nginx.com size_t size; 3169630Svbart@nginx.com u_char *buf, *p; 3170630Svbart@nginx.com nxt_off_t bytes; 3171630Svbart@nginx.com 3172630Svbart@nginx.com static nxt_time_string_t date_cache = { 3173630Svbart@nginx.com (nxt_atomic_uint_t) -1, 3174630Svbart@nginx.com nxt_router_access_log_date, 3175630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 3176703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 3177630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 3178630Svbart@nginx.com NXT_THREAD_TIME_SEC, 3179630Svbart@nginx.com }; 3180630Svbart@nginx.com 3181630Svbart@nginx.com size = r->remote->address_length 3182630Svbart@nginx.com + 6 /* ' - - [' */ 3183630Svbart@nginx.com + date_cache.size 3184630Svbart@nginx.com + 3 /* '] "' */ 3185630Svbart@nginx.com + r->method->length 3186630Svbart@nginx.com + 1 /* space */ 3187630Svbart@nginx.com + r->target.length 3188630Svbart@nginx.com + 1 /* space */ 3189630Svbart@nginx.com + r->version.length 3190630Svbart@nginx.com + 2 /* '" ' */ 3191630Svbart@nginx.com + 3 /* status */ 3192630Svbart@nginx.com + 1 /* space */ 3193630Svbart@nginx.com + NXT_OFF_T_LEN 3194630Svbart@nginx.com + 2 /* ' "' */ 3195630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3196630Svbart@nginx.com + 3 /* '" "' */ 3197630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3198630Svbart@nginx.com + 2 /* '"\n' */ 3199630Svbart@nginx.com ; 3200630Svbart@nginx.com 3201630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3202630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3203630Svbart@nginx.com return; 3204630Svbart@nginx.com } 3205630Svbart@nginx.com 3206630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3207630Svbart@nginx.com r->remote->address_length); 3208630Svbart@nginx.com 3209630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3210630Svbart@nginx.com 3211630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3212630Svbart@nginx.com 3213630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3214630Svbart@nginx.com 3215630Svbart@nginx.com if (r->method->length != 0) { 3216630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3217630Svbart@nginx.com 3218630Svbart@nginx.com if (r->target.length != 0) { 3219630Svbart@nginx.com *p++ = ' '; 3220630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3221630Svbart@nginx.com 3222630Svbart@nginx.com if (r->version.length != 0) { 3223630Svbart@nginx.com *p++ = ' '; 3224630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3225630Svbart@nginx.com } 3226630Svbart@nginx.com } 3227630Svbart@nginx.com 3228630Svbart@nginx.com } else { 3229630Svbart@nginx.com *p++ = '-'; 3230630Svbart@nginx.com } 3231630Svbart@nginx.com 3232630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3233630Svbart@nginx.com 3234630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3235630Svbart@nginx.com 3236630Svbart@nginx.com *p++ = ' '; 3237630Svbart@nginx.com 32381112Sigor@sysoev.ru bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); 3239630Svbart@nginx.com 3240630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3241630Svbart@nginx.com 3242630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3243630Svbart@nginx.com 3244630Svbart@nginx.com if (r->referer != NULL) { 3245630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3246630Svbart@nginx.com 3247630Svbart@nginx.com } else { 3248630Svbart@nginx.com *p++ = '-'; 3249630Svbart@nginx.com } 3250630Svbart@nginx.com 3251630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3252630Svbart@nginx.com 3253630Svbart@nginx.com if (r->user_agent != NULL) { 3254630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3255630Svbart@nginx.com 3256630Svbart@nginx.com } else { 3257630Svbart@nginx.com *p++ = '-'; 3258630Svbart@nginx.com } 3259630Svbart@nginx.com 3260630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3261630Svbart@nginx.com 3262630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3263630Svbart@nginx.com } 3264630Svbart@nginx.com 3265630Svbart@nginx.com 3266630Svbart@nginx.com static u_char * 3267630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3268630Svbart@nginx.com size_t size, const char *format) 3269630Svbart@nginx.com { 3270630Svbart@nginx.com u_char sign; 3271630Svbart@nginx.com time_t gmtoff; 3272630Svbart@nginx.com 3273630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3274630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3275630Svbart@nginx.com 3276630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3277630Svbart@nginx.com 3278630Svbart@nginx.com if (gmtoff < 0) { 3279630Svbart@nginx.com gmtoff = -gmtoff; 3280630Svbart@nginx.com sign = '-'; 3281630Svbart@nginx.com 3282630Svbart@nginx.com } else { 3283630Svbart@nginx.com sign = '+'; 3284630Svbart@nginx.com } 3285630Svbart@nginx.com 3286630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3287630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3288630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3289630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3290630Svbart@nginx.com } 3291630Svbart@nginx.com 3292630Svbart@nginx.com 3293630Svbart@nginx.com static void 3294630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3295630Svbart@nginx.com { 3296630Svbart@nginx.com uint32_t stream; 3297648Svbart@nginx.com nxt_int_t ret; 3298630Svbart@nginx.com nxt_buf_t *b; 3299630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3300630Svbart@nginx.com nxt_runtime_t *rt; 3301630Svbart@nginx.com nxt_router_access_log_t *access_log; 3302630Svbart@nginx.com 3303630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3304630Svbart@nginx.com 3305630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3306630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3307630Svbart@nginx.com goto fail; 3308630Svbart@nginx.com } 3309630Svbart@nginx.com 3310630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3311630Svbart@nginx.com *b->mem.free++ = '\0'; 3312630Svbart@nginx.com 3313630Svbart@nginx.com rt = task->thread->runtime; 3314630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3315630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3316630Svbart@nginx.com 3317630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3318630Svbart@nginx.com nxt_router_access_log_ready, 3319630Svbart@nginx.com nxt_router_access_log_error, 3320630Svbart@nginx.com -1, tmcf); 3321630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3322630Svbart@nginx.com goto fail; 3323630Svbart@nginx.com } 3324630Svbart@nginx.com 3325648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3326648Svbart@nginx.com stream, router_port->id, b); 3327648Svbart@nginx.com 3328648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3329648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3330648Svbart@nginx.com goto fail; 3331648Svbart@nginx.com } 3332630Svbart@nginx.com 3333630Svbart@nginx.com return; 3334630Svbart@nginx.com 3335630Svbart@nginx.com fail: 3336630Svbart@nginx.com 3337630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3338630Svbart@nginx.com } 3339630Svbart@nginx.com 3340630Svbart@nginx.com 3341630Svbart@nginx.com static void 3342630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3343630Svbart@nginx.com void *data) 3344630Svbart@nginx.com { 3345630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3346630Svbart@nginx.com nxt_router_access_log_t *access_log; 3347630Svbart@nginx.com 3348630Svbart@nginx.com tmcf = data; 3349630Svbart@nginx.com 3350630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3351630Svbart@nginx.com 3352630Svbart@nginx.com access_log->fd = msg->fd; 3353630Svbart@nginx.com 3354630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3355630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3356630Svbart@nginx.com } 3357630Svbart@nginx.com 3358630Svbart@nginx.com 3359630Svbart@nginx.com static void 3360630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3361630Svbart@nginx.com void *data) 3362630Svbart@nginx.com { 3363630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3364630Svbart@nginx.com 3365630Svbart@nginx.com tmcf = data; 3366630Svbart@nginx.com 3367630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3368630Svbart@nginx.com } 3369630Svbart@nginx.com 3370630Svbart@nginx.com 3371630Svbart@nginx.com static void 3372630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3373630Svbart@nginx.com nxt_router_access_log_t *access_log) 3374630Svbart@nginx.com { 3375630Svbart@nginx.com if (access_log == NULL) { 3376630Svbart@nginx.com return; 3377630Svbart@nginx.com } 3378630Svbart@nginx.com 3379630Svbart@nginx.com nxt_thread_spin_lock(lock); 3380630Svbart@nginx.com 3381630Svbart@nginx.com if (--access_log->count != 0) { 3382630Svbart@nginx.com access_log = NULL; 3383630Svbart@nginx.com } 3384630Svbart@nginx.com 3385630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3386630Svbart@nginx.com 3387630Svbart@nginx.com if (access_log != NULL) { 3388630Svbart@nginx.com 3389630Svbart@nginx.com if (access_log->fd != -1) { 3390630Svbart@nginx.com nxt_fd_close(access_log->fd); 3391630Svbart@nginx.com } 3392630Svbart@nginx.com 3393630Svbart@nginx.com nxt_free(access_log); 3394630Svbart@nginx.com } 3395630Svbart@nginx.com } 3396630Svbart@nginx.com 3397630Svbart@nginx.com 3398631Svbart@nginx.com typedef struct { 3399631Svbart@nginx.com nxt_mp_t *mem_pool; 3400631Svbart@nginx.com nxt_router_access_log_t *access_log; 3401631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3402631Svbart@nginx.com 3403631Svbart@nginx.com 3404631Svbart@nginx.com void 3405631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3406631Svbart@nginx.com { 3407631Svbart@nginx.com nxt_mp_t *mp; 3408631Svbart@nginx.com uint32_t stream; 3409631Svbart@nginx.com nxt_int_t ret; 3410631Svbart@nginx.com nxt_buf_t *b; 3411631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3412631Svbart@nginx.com nxt_runtime_t *rt; 3413631Svbart@nginx.com nxt_router_access_log_t *access_log; 3414631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3415631Svbart@nginx.com 3416631Svbart@nginx.com access_log = nxt_router->access_log; 3417631Svbart@nginx.com 3418631Svbart@nginx.com if (access_log == NULL) { 3419631Svbart@nginx.com return; 3420631Svbart@nginx.com } 3421631Svbart@nginx.com 3422631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3423631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3424631Svbart@nginx.com return; 3425631Svbart@nginx.com } 3426631Svbart@nginx.com 3427631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3428631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3429631Svbart@nginx.com goto fail; 3430631Svbart@nginx.com } 3431631Svbart@nginx.com 3432631Svbart@nginx.com reopen->mem_pool = mp; 3433631Svbart@nginx.com reopen->access_log = access_log; 3434631Svbart@nginx.com 3435631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3436631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3437631Svbart@nginx.com goto fail; 3438631Svbart@nginx.com } 3439631Svbart@nginx.com 3440651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3441651Svbart@nginx.com 3442631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3443631Svbart@nginx.com *b->mem.free++ = '\0'; 3444631Svbart@nginx.com 3445631Svbart@nginx.com rt = task->thread->runtime; 3446631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3447631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3448631Svbart@nginx.com 3449631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3450631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3451631Svbart@nginx.com nxt_router_access_log_reopen_error, 3452631Svbart@nginx.com -1, reopen); 3453631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3454631Svbart@nginx.com goto fail; 3455631Svbart@nginx.com } 3456631Svbart@nginx.com 3457631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3458631Svbart@nginx.com stream, router_port->id, b); 3459631Svbart@nginx.com 3460631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3461631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3462631Svbart@nginx.com goto fail; 3463631Svbart@nginx.com } 3464631Svbart@nginx.com 3465651Svbart@nginx.com nxt_mp_retain(mp); 3466651Svbart@nginx.com 3467631Svbart@nginx.com return; 3468631Svbart@nginx.com 3469631Svbart@nginx.com fail: 3470631Svbart@nginx.com 3471631Svbart@nginx.com nxt_mp_destroy(mp); 3472631Svbart@nginx.com } 3473631Svbart@nginx.com 3474631Svbart@nginx.com 3475631Svbart@nginx.com static void 3476651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3477651Svbart@nginx.com { 3478651Svbart@nginx.com nxt_mp_t *mp; 3479651Svbart@nginx.com nxt_buf_t *b; 3480651Svbart@nginx.com 3481651Svbart@nginx.com b = obj; 3482651Svbart@nginx.com mp = b->data; 3483651Svbart@nginx.com 3484651Svbart@nginx.com nxt_mp_release(mp); 3485651Svbart@nginx.com } 3486651Svbart@nginx.com 3487651Svbart@nginx.com 3488651Svbart@nginx.com static void 3489631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3490631Svbart@nginx.com void *data) 3491631Svbart@nginx.com { 3492631Svbart@nginx.com nxt_router_access_log_t *access_log; 3493631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3494631Svbart@nginx.com 3495631Svbart@nginx.com reopen = data; 3496631Svbart@nginx.com 3497631Svbart@nginx.com access_log = reopen->access_log; 3498631Svbart@nginx.com 3499631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3500631Svbart@nginx.com 3501631Svbart@nginx.com if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) { 3502631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3503631Svbart@nginx.com msg->fd, access_log->fd, nxt_errno); 3504631Svbart@nginx.com } 3505631Svbart@nginx.com } 3506631Svbart@nginx.com 3507631Svbart@nginx.com nxt_fd_close(msg->fd); 3508651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3509631Svbart@nginx.com } 3510631Svbart@nginx.com 3511631Svbart@nginx.com 3512631Svbart@nginx.com static void 3513631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3514631Svbart@nginx.com void *data) 3515631Svbart@nginx.com { 3516631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3517631Svbart@nginx.com 3518631Svbart@nginx.com reopen = data; 3519631Svbart@nginx.com 3520651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3521631Svbart@nginx.com } 3522631Svbart@nginx.com 3523631Svbart@nginx.com 3524630Svbart@nginx.com static void 352553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 352653Sigor@sysoev.ru { 3527141Smax.romanov@nginx.com nxt_port_t *port; 352853Sigor@sysoev.ru nxt_thread_link_t *link; 352953Sigor@sysoev.ru nxt_event_engine_t *engine; 353053Sigor@sysoev.ru nxt_thread_handle_t handle; 353153Sigor@sysoev.ru 353258Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 353353Sigor@sysoev.ru link = data; 353453Sigor@sysoev.ru 353553Sigor@sysoev.ru nxt_thread_wait(handle); 353653Sigor@sysoev.ru 353753Sigor@sysoev.ru engine = link->engine; 353853Sigor@sysoev.ru 353953Sigor@sysoev.ru nxt_queue_remove(&engine->link); 354053Sigor@sysoev.ru 3541141Smax.romanov@nginx.com port = engine->port; 3542141Smax.romanov@nginx.com 3543141Smax.romanov@nginx.com // TODO notify all apps 3544141Smax.romanov@nginx.com 3545343Smax.romanov@nginx.com port->engine = task->thread->engine; 3546163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3547343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3548163Smax.romanov@nginx.com 3549163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 355063Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 355153Sigor@sysoev.ru 355253Sigor@sysoev.ru nxt_event_engine_free(engine); 355353Sigor@sysoev.ru 355453Sigor@sysoev.ru nxt_free(link); 355553Sigor@sysoev.ru } 355653Sigor@sysoev.ru 355753Sigor@sysoev.ru 355853Sigor@sysoev.ru static void 3559318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3560318Smax.romanov@nginx.com void *data) 356188Smax.romanov@nginx.com { 35621123Smax.romanov@nginx.com nxt_int_t ret; 35631269Sigor@sysoev.ru nxt_buf_t *b, *next; 35641131Smax.romanov@nginx.com nxt_port_t *app_port; 35651123Smax.romanov@nginx.com nxt_unit_field_t *f; 35661123Smax.romanov@nginx.com nxt_http_field_t *field; 35671123Smax.romanov@nginx.com nxt_http_request_t *r; 35681123Smax.romanov@nginx.com nxt_unit_response_t *resp; 35691131Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 35701123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 357188Smax.romanov@nginx.com 357288Smax.romanov@nginx.com b = msg->buf; 35731123Smax.romanov@nginx.com req_rpc_data = data; 357488Smax.romanov@nginx.com 357588Smax.romanov@nginx.com if (msg->size == 0) { 357688Smax.romanov@nginx.com b = NULL; 357788Smax.romanov@nginx.com } 357888Smax.romanov@nginx.com 35791123Smax.romanov@nginx.com r = req_rpc_data->request; 35801007Salexander.borisov@nginx.com if (nxt_slow_path(r == NULL)) { 3581570Smax.romanov@nginx.com return; 3582570Smax.romanov@nginx.com } 3583425Smax.romanov@nginx.com 35841007Salexander.borisov@nginx.com if (r->error) { 35851123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3586608Sigor@sysoev.ru return; 3587608Sigor@sysoev.ru } 3588608Sigor@sysoev.ru 358988Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 359088Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 359188Smax.romanov@nginx.com 35921007Salexander.borisov@nginx.com nxt_buf_chain_add(&b, nxt_http_buf_last(r)); 3593167Smax.romanov@nginx.com 35941123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3595425Smax.romanov@nginx.com 3596425Smax.romanov@nginx.com } else { 35971123Smax.romanov@nginx.com if (req_rpc_data->app != NULL && req_rpc_data->app->timeout != 0) { 35981007Salexander.borisov@nginx.com r->timer.handler = nxt_router_app_timeout; 35991123Smax.romanov@nginx.com r->timer_data = req_rpc_data; 36001123Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 36011123Smax.romanov@nginx.com req_rpc_data->app->timeout); 3602425Smax.romanov@nginx.com } 360388Smax.romanov@nginx.com } 360488Smax.romanov@nginx.com 360588Smax.romanov@nginx.com if (b == NULL) { 360688Smax.romanov@nginx.com return; 360788Smax.romanov@nginx.com } 360888Smax.romanov@nginx.com 3609206Smax.romanov@nginx.com if (msg->buf == b) { 3610206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3611206Smax.romanov@nginx.com msg->buf = NULL; 3612206Smax.romanov@nginx.com } 3613194Smax.romanov@nginx.com 3614431Sigor@sysoev.ru if (r->header_sent) { 3615431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3616431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3617277Sigor@sysoev.ru 361888Smax.romanov@nginx.com } else { 3619743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3620743Smax.romanov@nginx.com 3621743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3622743Smax.romanov@nginx.com goto fail; 3623743Smax.romanov@nginx.com } 3624743Smax.romanov@nginx.com 3625743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3626743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3627743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3628743Smax.romanov@nginx.com goto fail; 3629743Smax.romanov@nginx.com } 3630743Smax.romanov@nginx.com 36311126Smax.romanov@nginx.com field = NULL; 36321126Smax.romanov@nginx.com 3633743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 36341126Smax.romanov@nginx.com if (f->skip) { 36351126Smax.romanov@nginx.com continue; 36361126Smax.romanov@nginx.com } 36371126Smax.romanov@nginx.com 36381007Salexander.borisov@nginx.com field = nxt_list_add(r->resp.fields); 3639743Smax.romanov@nginx.com 3640743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3641743Smax.romanov@nginx.com goto fail; 3642743Smax.romanov@nginx.com } 3643743Smax.romanov@nginx.com 3644743Smax.romanov@nginx.com field->hash = f->hash; 36451126Smax.romanov@nginx.com field->skip = 0; 36461270Sigor@sysoev.ru field->hopbyhop = 0; 3647743Smax.romanov@nginx.com 3648743Smax.romanov@nginx.com field->name_length = f->name_length; 3649743Smax.romanov@nginx.com field->value_length = f->value_length; 3650743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3651743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3652743Smax.romanov@nginx.com 36531126Smax.romanov@nginx.com ret = nxt_http_field_process(field, &nxt_response_fields_hash, r); 36541126Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 36551126Smax.romanov@nginx.com goto fail; 36561126Smax.romanov@nginx.com } 36571126Smax.romanov@nginx.com 36581126Smax.romanov@nginx.com nxt_debug(task, "header%s: %*s: %*s", 36591126Smax.romanov@nginx.com (field->skip ? " skipped" : ""), 3660743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3661743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 36621126Smax.romanov@nginx.com 36631126Smax.romanov@nginx.com if (field->skip) { 36641126Smax.romanov@nginx.com r->resp.fields->last->nelts--; 36651126Smax.romanov@nginx.com } 3666743Smax.romanov@nginx.com } 36671007Salexander.borisov@nginx.com 3668743Smax.romanov@nginx.com r->status = resp->status; 3669743Smax.romanov@nginx.com 3670743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3671743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3672743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3673743Smax.romanov@nginx.com 3674743Smax.romanov@nginx.com } else { 3675743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3676743Smax.romanov@nginx.com } 3677743Smax.romanov@nginx.com 3678435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 36791269Sigor@sysoev.ru next = b->next; 36801269Sigor@sysoev.ru b->next = NULL; 36811269Sigor@sysoev.ru 3682435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3683435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3684507Smax.romanov@nginx.com 36851269Sigor@sysoev.ru b = next; 3686520Smax.romanov@nginx.com } 3687520Smax.romanov@nginx.com 3688520Smax.romanov@nginx.com if (b != NULL) { 3689431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3690431Sigor@sysoev.ru } 3691431Sigor@sysoev.ru 36921270Sigor@sysoev.ru nxt_http_request_header_send(task, r, nxt_http_request_send_body, NULL); 36931127Smax.romanov@nginx.com 36941131Smax.romanov@nginx.com if (r->websocket_handshake 36951131Smax.romanov@nginx.com && r->status == NXT_HTTP_SWITCHING_PROTOCOLS) 36961131Smax.romanov@nginx.com { 36971131Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, 36981131Smax.romanov@nginx.com req_rpc_data->req_app_link, 36991131Smax.romanov@nginx.com req_rpc_data); 37001131Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 37011131Smax.romanov@nginx.com goto fail; 37021131Smax.romanov@nginx.com } 37031131Smax.romanov@nginx.com 37041131Smax.romanov@nginx.com app_port = req_app_link->app_port; 37051131Smax.romanov@nginx.com 37061131Smax.romanov@nginx.com if (app_port == NULL && req_rpc_data->app_port != NULL) { 37071131Smax.romanov@nginx.com req_app_link->app_port = req_rpc_data->app_port; 37081131Smax.romanov@nginx.com app_port = req_app_link->app_port; 37091131Smax.romanov@nginx.com req_app_link->apr_action = req_rpc_data->apr_action; 37101131Smax.romanov@nginx.com 37111131Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 37121131Smax.romanov@nginx.com } 37131131Smax.romanov@nginx.com 37141131Smax.romanov@nginx.com if (nxt_slow_path(app_port == NULL)) { 37151131Smax.romanov@nginx.com goto fail; 37161131Smax.romanov@nginx.com } 37171131Smax.romanov@nginx.com 37181131Smax.romanov@nginx.com nxt_thread_mutex_lock(&req_rpc_data->app->mutex); 37191131Smax.romanov@nginx.com 37201131Smax.romanov@nginx.com nxt_queue_insert_tail(&app_port->active_websockets, 37211131Smax.romanov@nginx.com &req_app_link->link_port_websockets); 37221131Smax.romanov@nginx.com 37231131Smax.romanov@nginx.com nxt_thread_mutex_unlock(&req_rpc_data->app->mutex); 37241131Smax.romanov@nginx.com 37251131Smax.romanov@nginx.com nxt_router_app_port_release(task, app_port, NXT_APR_UPGRADE); 37261131Smax.romanov@nginx.com req_app_link->apr_action = NXT_APR_CLOSE; 37271131Smax.romanov@nginx.com 37281131Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD upgrade", 37291131Smax.romanov@nginx.com req_app_link->stream); 37301131Smax.romanov@nginx.com 37311131Smax.romanov@nginx.com r->state = &nxt_http_websocket; 37321131Smax.romanov@nginx.com 37331131Smax.romanov@nginx.com } else { 37341131Smax.romanov@nginx.com r->state = &nxt_http_request_send_state; 37351131Smax.romanov@nginx.com } 3736431Sigor@sysoev.ru } 3737431Sigor@sysoev.ru 3738431Sigor@sysoev.ru return; 3739431Sigor@sysoev.ru 3740431Sigor@sysoev.ru fail: 3741431Sigor@sysoev.ru 3742615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3743615Smax.romanov@nginx.com 37441123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3745431Sigor@sysoev.ru } 3746431Sigor@sysoev.ru 3747431Sigor@sysoev.ru 3748431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3749431Sigor@sysoev.ru nxt_aligned(64) = 3750431Sigor@sysoev.ru { 3751943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 3752431Sigor@sysoev.ru }; 3753431Sigor@sysoev.ru 3754431Sigor@sysoev.ru 3755431Sigor@sysoev.ru static void 3756431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3757431Sigor@sysoev.ru { 3758431Sigor@sysoev.ru nxt_buf_t *out; 3759431Sigor@sysoev.ru nxt_http_request_t *r; 3760431Sigor@sysoev.ru 3761431Sigor@sysoev.ru r = obj; 3762431Sigor@sysoev.ru 3763431Sigor@sysoev.ru out = r->out; 3764431Sigor@sysoev.ru 3765431Sigor@sysoev.ru if (out != NULL) { 3766431Sigor@sysoev.ru r->out = NULL; 3767431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 376888Smax.romanov@nginx.com } 376988Smax.romanov@nginx.com } 377088Smax.romanov@nginx.com 3771277Sigor@sysoev.ru 3772318Smax.romanov@nginx.com static void 3773318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3774318Smax.romanov@nginx.com void *data) 3775318Smax.romanov@nginx.com { 37761123Smax.romanov@nginx.com nxt_int_t res; 37771123Smax.romanov@nginx.com nxt_port_t *port; 37781123Smax.romanov@nginx.com nxt_bool_t cancelled; 37791123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 37801123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 37811123Smax.romanov@nginx.com 37821123Smax.romanov@nginx.com req_rpc_data = data; 37831123Smax.romanov@nginx.com 37841123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 37851123Smax.romanov@nginx.com 37861123Smax.romanov@nginx.com if (req_app_link != NULL) { 37871123Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &req_app_link->msg_info, 37881123Smax.romanov@nginx.com req_app_link->stream); 3789425Smax.romanov@nginx.com if (cancelled) { 37901123Smax.romanov@nginx.com res = nxt_router_app_port(task, req_rpc_data->app, req_app_link); 3791425Smax.romanov@nginx.com 3792425Smax.romanov@nginx.com if (res == NXT_OK) { 37931123Smax.romanov@nginx.com port = req_app_link->app_port; 3794425Smax.romanov@nginx.com 3795551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 37961123Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, 37971123Smax.romanov@nginx.com "port is NULL in cancelled req_app_link"); 3798551Smax.romanov@nginx.com return; 3799551Smax.romanov@nginx.com } 3800425Smax.romanov@nginx.com 38011123Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, 38021123Smax.romanov@nginx.com req_rpc_data, port->pid); 38031123Smax.romanov@nginx.com 38041123Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 3805425Smax.romanov@nginx.com } 3806425Smax.romanov@nginx.com 3807425Smax.romanov@nginx.com msg->port_msg.last = 0; 3808425Smax.romanov@nginx.com 3809425Smax.romanov@nginx.com return; 3810425Smax.romanov@nginx.com } 3811425Smax.romanov@nginx.com } 3812425Smax.romanov@nginx.com 38131123Smax.romanov@nginx.com if (req_rpc_data->request != NULL) { 38141123Smax.romanov@nginx.com nxt_http_request_error(task, req_rpc_data->request, 3815616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3816616Smax.romanov@nginx.com } 3817318Smax.romanov@nginx.com 38181123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 3819318Smax.romanov@nginx.com } 3820318Smax.romanov@nginx.com 3821318Smax.romanov@nginx.com 3822141Smax.romanov@nginx.com static void 3823343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3824343Smax.romanov@nginx.com void *data) 3825192Smax.romanov@nginx.com { 3826753Smax.romanov@nginx.com nxt_app_t *app; 3827753Smax.romanov@nginx.com nxt_port_t *port; 3828753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3829753Smax.romanov@nginx.com 3830753Smax.romanov@nginx.com app_joint = data; 3831347Smax.romanov@nginx.com port = msg->u.new_port; 3832343Smax.romanov@nginx.com 3833753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3834343Smax.romanov@nginx.com nxt_assert(port != NULL); 3835343Smax.romanov@nginx.com 3836753Smax.romanov@nginx.com app = app_joint->app; 3837753Smax.romanov@nginx.com 3838753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3839753Smax.romanov@nginx.com 3840753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3841753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3842753Smax.romanov@nginx.com 3843753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3844753Smax.romanov@nginx.com 3845753Smax.romanov@nginx.com return; 3846753Smax.romanov@nginx.com } 3847753Smax.romanov@nginx.com 3848343Smax.romanov@nginx.com port->app = app; 3849343Smax.romanov@nginx.com 3850343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3851343Smax.romanov@nginx.com 3852507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3853507Smax.romanov@nginx.com 3854507Smax.romanov@nginx.com app->pending_processes--; 3855507Smax.romanov@nginx.com app->processes++; 3856343Smax.romanov@nginx.com 3857343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3858343Smax.romanov@nginx.com 3859507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3860507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3861343Smax.romanov@nginx.com 38621123Smax.romanov@nginx.com nxt_router_app_port_release(task, port, NXT_APR_NEW_PORT); 3863192Smax.romanov@nginx.com } 3864192Smax.romanov@nginx.com 3865192Smax.romanov@nginx.com 3866192Smax.romanov@nginx.com static void 3867343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3868343Smax.romanov@nginx.com void *data) 3869192Smax.romanov@nginx.com { 38701123Smax.romanov@nginx.com nxt_app_t *app; 38711123Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 38721123Smax.romanov@nginx.com nxt_queue_link_t *lnk; 38731123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 3874343Smax.romanov@nginx.com 3875753Smax.romanov@nginx.com app_joint = data; 3876753Smax.romanov@nginx.com 3877753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3878753Smax.romanov@nginx.com 3879753Smax.romanov@nginx.com app = app_joint->app; 3880753Smax.romanov@nginx.com 3881753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3882753Smax.romanov@nginx.com 3883753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3884753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 3885753Smax.romanov@nginx.com 3886753Smax.romanov@nginx.com return; 3887753Smax.romanov@nginx.com } 3888343Smax.romanov@nginx.com 3889343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 3890343Smax.romanov@nginx.com 3891343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3892343Smax.romanov@nginx.com 3893507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3894507Smax.romanov@nginx.com 3895507Smax.romanov@nginx.com app->pending_processes--; 3896318Smax.romanov@nginx.com 3897318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 3898318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 3899318Smax.romanov@nginx.com nxt_queue_remove(lnk); 3900343Smax.romanov@nginx.com lnk->next = NULL; 3901318Smax.romanov@nginx.com 39021123Smax.romanov@nginx.com req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t, 39031123Smax.romanov@nginx.com link_app_requests); 3904318Smax.romanov@nginx.com 3905343Smax.romanov@nginx.com } else { 39061123Smax.romanov@nginx.com req_app_link = NULL; 3907343Smax.romanov@nginx.com } 3908343Smax.romanov@nginx.com 3909343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3910343Smax.romanov@nginx.com 39111123Smax.romanov@nginx.com if (req_app_link != NULL) { 3912318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 39131123Smax.romanov@nginx.com &app->name, app, req_app_link->stream); 39141123Smax.romanov@nginx.com 39151446Smax.romanov@nginx.com nxt_request_app_link_error(task, app, req_app_link, 39161123Smax.romanov@nginx.com "Failed to start application process"); 39171123Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 3918318Smax.romanov@nginx.com } 3919192Smax.romanov@nginx.com } 3920192Smax.romanov@nginx.com 3921753Smax.romanov@nginx.com nxt_inline nxt_port_t * 3922753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app); 3923192Smax.romanov@nginx.com 3924343Smax.romanov@nginx.com void 3925343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 3926141Smax.romanov@nginx.com { 3927343Smax.romanov@nginx.com int c; 3928343Smax.romanov@nginx.com 3929343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 3930343Smax.romanov@nginx.com 3931343Smax.romanov@nginx.com if (i < 0 && c == -i) { 3932343Smax.romanov@nginx.com 3933753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 3934753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 3935753Smax.romanov@nginx.com 3936753Smax.romanov@nginx.com } else { 3937753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 3938753Smax.romanov@nginx.com } 3939163Smax.romanov@nginx.com } 3940343Smax.romanov@nginx.com } 3941343Smax.romanov@nginx.com 3942343Smax.romanov@nginx.com 3943424Smax.romanov@nginx.com nxt_inline nxt_bool_t 3944424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 3945424Smax.romanov@nginx.com { 3946424Smax.romanov@nginx.com nxt_port_t *port; 3947424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3948424Smax.romanov@nginx.com 3949424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3950424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3951424Smax.romanov@nginx.com 3952424Smax.romanov@nginx.com return port->app_pending_responses > 0; 3953424Smax.romanov@nginx.com } 3954424Smax.romanov@nginx.com 3955424Smax.romanov@nginx.com 3956343Smax.romanov@nginx.com nxt_inline nxt_port_t * 3957427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 3958343Smax.romanov@nginx.com { 3959343Smax.romanov@nginx.com nxt_port_t *port; 3960343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3961343Smax.romanov@nginx.com 3962343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3963343Smax.romanov@nginx.com nxt_queue_remove(lnk); 3964343Smax.romanov@nginx.com 3965343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3966343Smax.romanov@nginx.com 3967424Smax.romanov@nginx.com port->app_pending_responses++; 3968424Smax.romanov@nginx.com 3969507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3970507Smax.romanov@nginx.com app->idle_processes--; 3971507Smax.romanov@nginx.com 3972507Smax.romanov@nginx.com if (port->idle_start == 0) { 3973507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 3974507Smax.romanov@nginx.com 3975507Smax.romanov@nginx.com } else { 3976507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 3977507Smax.romanov@nginx.com 3978507Smax.romanov@nginx.com port->idle_start = 0; 3979507Smax.romanov@nginx.com } 3980507Smax.romanov@nginx.com } 3981507Smax.romanov@nginx.com 3982428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 3983428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3984428Smax.romanov@nginx.com && (app->max_requests == 0 3985428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3986428Smax.romanov@nginx.com < app->max_requests)) 3987277Sigor@sysoev.ru { 3988343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 3989343Smax.romanov@nginx.com 3990425Smax.romanov@nginx.com nxt_port_inc_use(port); 3991425Smax.romanov@nginx.com 3992343Smax.romanov@nginx.com } else { 3993343Smax.romanov@nginx.com lnk->next = NULL; 3994167Smax.romanov@nginx.com } 3995167Smax.romanov@nginx.com 3996343Smax.romanov@nginx.com return port; 3997163Smax.romanov@nginx.com } 3998163Smax.romanov@nginx.com 3999163Smax.romanov@nginx.com 4000507Smax.romanov@nginx.com nxt_inline nxt_port_t * 4001507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 4002141Smax.romanov@nginx.com { 4003343Smax.romanov@nginx.com nxt_port_t *port; 4004141Smax.romanov@nginx.com 4005141Smax.romanov@nginx.com port = NULL; 4006141Smax.romanov@nginx.com 4007141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4008141Smax.romanov@nginx.com 4009343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 4010343Smax.romanov@nginx.com 4011424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 4012343Smax.romanov@nginx.com port = NULL; 4013343Smax.romanov@nginx.com 4014343Smax.romanov@nginx.com continue; 4015343Smax.romanov@nginx.com } 4016343Smax.romanov@nginx.com 4017507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 4018507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4019507Smax.romanov@nginx.com 4020507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4021507Smax.romanov@nginx.com app->idle_processes--; 4022507Smax.romanov@nginx.com } 4023507Smax.romanov@nginx.com 4024507Smax.romanov@nginx.com port->app = NULL; 4025507Smax.romanov@nginx.com app->processes--; 4026343Smax.romanov@nginx.com 4027343Smax.romanov@nginx.com break; 4028343Smax.romanov@nginx.com 4029343Smax.romanov@nginx.com } nxt_queue_loop; 4030141Smax.romanov@nginx.com 4031141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4032141Smax.romanov@nginx.com 4033141Smax.romanov@nginx.com return port; 4034141Smax.romanov@nginx.com } 4035141Smax.romanov@nginx.com 4036141Smax.romanov@nginx.com 4037141Smax.romanov@nginx.com static void 4038753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 4039507Smax.romanov@nginx.com { 4040753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 4041507Smax.romanov@nginx.com 4042507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 4043507Smax.romanov@nginx.com 4044753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4045507Smax.romanov@nginx.com } 4046507Smax.romanov@nginx.com 4047507Smax.romanov@nginx.com 4048507Smax.romanov@nginx.com static void 4049343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 4050141Smax.romanov@nginx.com { 40511123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 40521123Smax.romanov@nginx.com 40531123Smax.romanov@nginx.com req_app_link = data; 4054538Svbart@nginx.com 4055538Svbart@nginx.com #if (NXT_DEBUG) 4056538Svbart@nginx.com { 4057538Svbart@nginx.com nxt_app_t *app; 4058538Svbart@nginx.com 4059343Smax.romanov@nginx.com app = obj; 4060141Smax.romanov@nginx.com 4061141Smax.romanov@nginx.com nxt_assert(app != NULL); 40621123Smax.romanov@nginx.com nxt_assert(req_app_link != NULL); 40631123Smax.romanov@nginx.com nxt_assert(req_app_link->app_port != NULL); 4064343Smax.romanov@nginx.com 4065343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 40661123Smax.romanov@nginx.com &app->name, app, req_app_link->stream); 4067538Svbart@nginx.com } 4068538Svbart@nginx.com #endif 4069343Smax.romanov@nginx.com 40701123Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 40711294Smax.romanov@nginx.com 40721294Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 4073343Smax.romanov@nginx.com } 4074343Smax.romanov@nginx.com 4075343Smax.romanov@nginx.com 4076343Smax.romanov@nginx.com static void 4077343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 40781123Smax.romanov@nginx.com nxt_apr_action_t action) 4079343Smax.romanov@nginx.com { 40801123Smax.romanov@nginx.com int inc_use; 40811123Smax.romanov@nginx.com uint32_t dec_pending, got_response; 4082427Smax.romanov@nginx.com nxt_app_t *app; 4083507Smax.romanov@nginx.com nxt_bool_t port_unchained; 4084507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 4085427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 40861123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link, *pending_ra, *re_ra; 4087427Smax.romanov@nginx.com nxt_port_select_state_t state; 4088343Smax.romanov@nginx.com 4089343Smax.romanov@nginx.com nxt_assert(port != NULL); 4090343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 4091343Smax.romanov@nginx.com 40921123Smax.romanov@nginx.com req_app_link = NULL; 4093427Smax.romanov@nginx.com 4094343Smax.romanov@nginx.com app = port->app; 4095343Smax.romanov@nginx.com 40961123Smax.romanov@nginx.com inc_use = 0; 40971123Smax.romanov@nginx.com dec_pending = 0; 40981123Smax.romanov@nginx.com got_response = 0; 40991123Smax.romanov@nginx.com 41001123Smax.romanov@nginx.com switch (action) { 41011123Smax.romanov@nginx.com case NXT_APR_NEW_PORT: 41021123Smax.romanov@nginx.com break; 41031123Smax.romanov@nginx.com case NXT_APR_REQUEST_FAILED: 41041123Smax.romanov@nginx.com dec_pending = 1; 41051123Smax.romanov@nginx.com inc_use = -1; 41061123Smax.romanov@nginx.com break; 41071123Smax.romanov@nginx.com case NXT_APR_GOT_RESPONSE: 41081123Smax.romanov@nginx.com dec_pending = 1; 41091123Smax.romanov@nginx.com got_response = 1; 41101123Smax.romanov@nginx.com inc_use = -1; 41111123Smax.romanov@nginx.com break; 41121131Smax.romanov@nginx.com case NXT_APR_UPGRADE: 41131131Smax.romanov@nginx.com dec_pending = 1; 41141131Smax.romanov@nginx.com got_response = 1; 41151131Smax.romanov@nginx.com break; 41161123Smax.romanov@nginx.com case NXT_APR_CLOSE: 41171123Smax.romanov@nginx.com inc_use = -1; 41181123Smax.romanov@nginx.com break; 41191123Smax.romanov@nginx.com } 41201123Smax.romanov@nginx.com 4121343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4122343Smax.romanov@nginx.com 41231123Smax.romanov@nginx.com port->app_pending_responses -= dec_pending; 4124343Smax.romanov@nginx.com port->app_responses += got_response; 4125343Smax.romanov@nginx.com 4126427Smax.romanov@nginx.com if (port->pair[1] != -1 4127426Smax.romanov@nginx.com && (app->max_pending_responses == 0 4128428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 4129428Smax.romanov@nginx.com && (app->max_requests == 0 4130428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 4131428Smax.romanov@nginx.com < app->max_requests)) 4132343Smax.romanov@nginx.com { 4133424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 4134424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 4135424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 4136424Smax.romanov@nginx.com 4137424Smax.romanov@nginx.com } else { 4138424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 4139424Smax.romanov@nginx.com } 4140424Smax.romanov@nginx.com 4141425Smax.romanov@nginx.com nxt_port_inc_use(port); 4142424Smax.romanov@nginx.com 4143424Smax.romanov@nginx.com } else { 4144424Smax.romanov@nginx.com if (port->app_pending_responses == 0 4145424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 4146424Smax.romanov@nginx.com { 4147424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 4148424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 4149424Smax.romanov@nginx.com } 4150424Smax.romanov@nginx.com } 4151141Smax.romanov@nginx.com } 4152141Smax.romanov@nginx.com 4153427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 4154426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 4155343Smax.romanov@nginx.com { 4156141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 4157141Smax.romanov@nginx.com nxt_queue_remove(lnk); 4158343Smax.romanov@nginx.com lnk->next = NULL; 4159141Smax.romanov@nginx.com 41601123Smax.romanov@nginx.com req_app_link = nxt_queue_link_data(lnk, nxt_request_app_link_t, 41611123Smax.romanov@nginx.com link_app_requests); 41621123Smax.romanov@nginx.com 41631123Smax.romanov@nginx.com req_app_link->app_port = nxt_router_pop_first_port(app); 41641123Smax.romanov@nginx.com 41651123Smax.romanov@nginx.com if (req_app_link->app_port->app_pending_responses > 1) { 41661123Smax.romanov@nginx.com nxt_request_app_link_pending(task, app, req_app_link); 4167425Smax.romanov@nginx.com } 4168425Smax.romanov@nginx.com } 4169425Smax.romanov@nginx.com 4170427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 41711123Smax.romanov@nginx.com if (dec_pending > 0 4172425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 4173425Smax.romanov@nginx.com { 4174425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4175425Smax.romanov@nginx.com nxt_queue_remove(lnk); 4176425Smax.romanov@nginx.com lnk->next = NULL; 4177425Smax.romanov@nginx.com 41781123Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 4179427Smax.romanov@nginx.com link_port_pending); 4180427Smax.romanov@nginx.com 4181427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4182427Smax.romanov@nginx.com 4183427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 4184427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 4185425Smax.romanov@nginx.com 4186425Smax.romanov@nginx.com } else { 4187427Smax.romanov@nginx.com pending_ra = NULL; 4188141Smax.romanov@nginx.com } 4189141Smax.romanov@nginx.com 4190427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 4191427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 4192427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 4193427Smax.romanov@nginx.com 41941123Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 41951123Smax.romanov@nginx.com link_app_pending); 4196427Smax.romanov@nginx.com 4197427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 4198427Smax.romanov@nginx.com 4199427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 4200427Smax.romanov@nginx.com &app->name, re_ra->stream); 4201427Smax.romanov@nginx.com 4202427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 4203427Smax.romanov@nginx.com re_ra->stream); 4204427Smax.romanov@nginx.com 4205427Smax.romanov@nginx.com if (cancelled) { 42061123Smax.romanov@nginx.com state.req_app_link = re_ra; 4207427Smax.romanov@nginx.com state.app = app; 4208427Smax.romanov@nginx.com 42091375Smax.romanov@nginx.com /* 42101375Smax.romanov@nginx.com * Need to increment use count "in advance" because 42111375Smax.romanov@nginx.com * nxt_router_port_select() will remove re_ra from lists 42121375Smax.romanov@nginx.com * and decrement use count. 42131375Smax.romanov@nginx.com */ 42141375Smax.romanov@nginx.com nxt_request_app_link_inc_use(re_ra); 42151375Smax.romanov@nginx.com 4216427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4217427Smax.romanov@nginx.com 4218427Smax.romanov@nginx.com goto re_ra_cancelled; 4219427Smax.romanov@nginx.com } 4220427Smax.romanov@nginx.com } 4221427Smax.romanov@nginx.com } 4222427Smax.romanov@nginx.com 4223427Smax.romanov@nginx.com re_ra = NULL; 4224427Smax.romanov@nginx.com 4225427Smax.romanov@nginx.com re_ra_cancelled: 4226427Smax.romanov@nginx.com 4227753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 4228753Smax.romanov@nginx.com && port->app_pending_responses == 0 4229753Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 4230367Smax.romanov@nginx.com 4231507Smax.romanov@nginx.com if (send_quit) { 4232507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 4233507Smax.romanov@nginx.com 4234507Smax.romanov@nginx.com port->app = NULL; 4235507Smax.romanov@nginx.com app->processes--; 4236507Smax.romanov@nginx.com 4237507Smax.romanov@nginx.com } else { 4238507Smax.romanov@nginx.com port_unchained = 0; 4239507Smax.romanov@nginx.com } 4240507Smax.romanov@nginx.com 4241507Smax.romanov@nginx.com adjust_idle_timer = 0; 4242507Smax.romanov@nginx.com 42431131Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0 42441131Smax.romanov@nginx.com && nxt_queue_is_empty(&port->active_websockets) 42451131Smax.romanov@nginx.com && port->idle_link.next == NULL) 42461131Smax.romanov@nginx.com { 4247507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 4248507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 4249507Smax.romanov@nginx.com { 4250507Smax.romanov@nginx.com adjust_idle_timer = 1; 4251507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 4252507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 4253507Smax.romanov@nginx.com } 4254507Smax.romanov@nginx.com 4255507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 4256507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 4257507Smax.romanov@nginx.com 4258507Smax.romanov@nginx.com } else { 4259507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 4260507Smax.romanov@nginx.com 4261507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 4262507Smax.romanov@nginx.com } 4263507Smax.romanov@nginx.com 4264507Smax.romanov@nginx.com app->idle_processes++; 4265507Smax.romanov@nginx.com } 4266507Smax.romanov@nginx.com 4267343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4268343Smax.romanov@nginx.com 4269507Smax.romanov@nginx.com if (adjust_idle_timer) { 4270507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4271507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4272507Smax.romanov@nginx.com } 4273507Smax.romanov@nginx.com 4274427Smax.romanov@nginx.com if (pending_ra != NULL) { 42751123Smax.romanov@nginx.com nxt_request_app_link_use(task, pending_ra, -1); 4276427Smax.romanov@nginx.com } 4277427Smax.romanov@nginx.com 4278427Smax.romanov@nginx.com if (re_ra != NULL) { 4279427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 42801294Smax.romanov@nginx.com /* 42811375Smax.romanov@nginx.com * Reference counter already incremented above, this will 42821375Smax.romanov@nginx.com * keep re_ra while nxt_router_app_process_request() 42831375Smax.romanov@nginx.com * task is in queue. Reference counter decreased in 42841375Smax.romanov@nginx.com * nxt_router_app_process_request() after processing. 42851294Smax.romanov@nginx.com */ 42861294Smax.romanov@nginx.com 4287427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4288427Smax.romanov@nginx.com nxt_router_app_process_request, 4289427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 42901375Smax.romanov@nginx.com 42911375Smax.romanov@nginx.com } else { 42921375Smax.romanov@nginx.com nxt_request_app_link_use(task, re_ra, -1); 4293427Smax.romanov@nginx.com } 4294425Smax.romanov@nginx.com } 4295425Smax.romanov@nginx.com 42961123Smax.romanov@nginx.com if (req_app_link != NULL) { 42971294Smax.romanov@nginx.com /* 42981350Smax.romanov@nginx.com * There should be call nxt_request_app_link_inc_use(req_app_link), 42991350Smax.romanov@nginx.com * because of one more link in the queue. But one link was 43001375Smax.romanov@nginx.com * recently removed from app->requests linked list. 43011375Smax.romanov@nginx.com * Corresponding decrement is in nxt_router_app_process_request(). 43021294Smax.romanov@nginx.com */ 4303425Smax.romanov@nginx.com 4304343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4305343Smax.romanov@nginx.com nxt_router_app_process_request, 43061123Smax.romanov@nginx.com &task->thread->engine->task, app, req_app_link); 4307343Smax.romanov@nginx.com 4308343Smax.romanov@nginx.com goto adjust_use; 4309343Smax.romanov@nginx.com } 4310343Smax.romanov@nginx.com 4311343Smax.romanov@nginx.com /* ? */ 4312163Smax.romanov@nginx.com if (port->pair[1] == -1) { 4313343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 4314343Smax.romanov@nginx.com &app->name, app, port, port->pid); 4315343Smax.romanov@nginx.com 4316343Smax.romanov@nginx.com goto adjust_use; 4317163Smax.romanov@nginx.com } 4318163Smax.romanov@nginx.com 4319367Smax.romanov@nginx.com if (send_quit) { 4320507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 4321167Smax.romanov@nginx.com &app->name, app); 4322163Smax.romanov@nginx.com 4323163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 4324163Smax.romanov@nginx.com -1, 0, 0, NULL); 4325163Smax.romanov@nginx.com 4326507Smax.romanov@nginx.com if (port_unchained) { 4327507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4328507Smax.romanov@nginx.com } 4329507Smax.romanov@nginx.com 4330343Smax.romanov@nginx.com goto adjust_use; 4331163Smax.romanov@nginx.com } 4332163Smax.romanov@nginx.com 4333167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4334167Smax.romanov@nginx.com &app->name, app); 4335141Smax.romanov@nginx.com 4336343Smax.romanov@nginx.com adjust_use: 4337343Smax.romanov@nginx.com 43381123Smax.romanov@nginx.com nxt_port_use(task, port, inc_use); 4339141Smax.romanov@nginx.com } 4340141Smax.romanov@nginx.com 4341141Smax.romanov@nginx.com 4342343Smax.romanov@nginx.com void 4343343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4344141Smax.romanov@nginx.com { 4345507Smax.romanov@nginx.com nxt_app_t *app; 4346507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4347507Smax.romanov@nginx.com nxt_port_t *idle_port; 4348507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4349141Smax.romanov@nginx.com 4350141Smax.romanov@nginx.com app = port->app; 4351343Smax.romanov@nginx.com 4352343Smax.romanov@nginx.com nxt_assert(app != NULL); 4353141Smax.romanov@nginx.com 4354141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4355141Smax.romanov@nginx.com 4356507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4357507Smax.romanov@nginx.com 4358507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4359507Smax.romanov@nginx.com app->idle_processes--; 4360507Smax.romanov@nginx.com 4361507Smax.romanov@nginx.com if (port->idle_start == 0 4362507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4363507Smax.romanov@nginx.com { 4364507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4365507Smax.romanov@nginx.com 4366507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4367507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4368507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4369507Smax.romanov@nginx.com 4370507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4371507Smax.romanov@nginx.com 4372507Smax.romanov@nginx.com idle_port->idle_start = 0; 4373507Smax.romanov@nginx.com } 4374343Smax.romanov@nginx.com } 4375343Smax.romanov@nginx.com 4376507Smax.romanov@nginx.com app->processes--; 4377507Smax.romanov@nginx.com 4378753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4379507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 4380507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 4381507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 4382507Smax.romanov@nginx.com 4383507Smax.romanov@nginx.com if (start_process) { 4384507Smax.romanov@nginx.com app->pending_processes++; 4385163Smax.romanov@nginx.com } 4386141Smax.romanov@nginx.com 4387141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4388163Smax.romanov@nginx.com 4389507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4390343Smax.romanov@nginx.com 4391343Smax.romanov@nginx.com if (unchain) { 4392343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4393163Smax.romanov@nginx.com } 4394163Smax.romanov@nginx.com 4395507Smax.romanov@nginx.com if (start_process) { 4396507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4397507Smax.romanov@nginx.com } 4398507Smax.romanov@nginx.com } 4399507Smax.romanov@nginx.com 4400507Smax.romanov@nginx.com 4401507Smax.romanov@nginx.com static void 4402507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4403507Smax.romanov@nginx.com { 4404507Smax.romanov@nginx.com nxt_app_t *app; 4405507Smax.romanov@nginx.com nxt_bool_t queued; 4406507Smax.romanov@nginx.com nxt_port_t *port; 4407507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4408507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4409507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4410507Smax.romanov@nginx.com 4411507Smax.romanov@nginx.com app = obj; 4412507Smax.romanov@nginx.com queued = (data == app); 4413507Smax.romanov@nginx.com 4414507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4415507Smax.romanov@nginx.com &app->name, queued); 4416507Smax.romanov@nginx.com 4417507Smax.romanov@nginx.com engine = task->thread->engine; 4418507Smax.romanov@nginx.com 4419507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 4420507Smax.romanov@nginx.com 4421811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 4422507Smax.romanov@nginx.com timeout = 0; 4423507Smax.romanov@nginx.com 4424507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4425507Smax.romanov@nginx.com 4426507Smax.romanov@nginx.com if (queued) { 4427507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 4428343Smax.romanov@nginx.com } 4429507Smax.romanov@nginx.com 4430507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 4431507Smax.romanov@nginx.com 4432551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4433507Smax.romanov@nginx.com 4434507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 4435507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 4436507Smax.romanov@nginx.com 4437507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 4438507Smax.romanov@nginx.com 4439507Smax.romanov@nginx.com if (timeout > threshold) { 4440507Smax.romanov@nginx.com break; 4441507Smax.romanov@nginx.com } 4442507Smax.romanov@nginx.com 4443507Smax.romanov@nginx.com nxt_queue_remove(lnk); 4444507Smax.romanov@nginx.com lnk->next = NULL; 4445507Smax.romanov@nginx.com 4446507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4447507Smax.romanov@nginx.com 4448507Smax.romanov@nginx.com app->idle_processes--; 4449507Smax.romanov@nginx.com app->processes--; 4450507Smax.romanov@nginx.com port->app = NULL; 4451507Smax.romanov@nginx.com 4452507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4453507Smax.romanov@nginx.com 4454507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4455507Smax.romanov@nginx.com &app->name, port->pid); 4456507Smax.romanov@nginx.com 4457507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4458507Smax.romanov@nginx.com 4459507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4460507Smax.romanov@nginx.com 4461507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4462507Smax.romanov@nginx.com } 4463507Smax.romanov@nginx.com 4464507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4465507Smax.romanov@nginx.com 4466507Smax.romanov@nginx.com if (timeout > threshold) { 4467753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4468507Smax.romanov@nginx.com 4469507Smax.romanov@nginx.com } else { 4470753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4471507Smax.romanov@nginx.com } 4472507Smax.romanov@nginx.com 4473507Smax.romanov@nginx.com if (queued) { 4474507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4475507Smax.romanov@nginx.com } 4476507Smax.romanov@nginx.com } 4477507Smax.romanov@nginx.com 4478507Smax.romanov@nginx.com 4479507Smax.romanov@nginx.com static void 4480507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4481507Smax.romanov@nginx.com { 4482753Smax.romanov@nginx.com nxt_timer_t *timer; 4483753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4484507Smax.romanov@nginx.com 4485507Smax.romanov@nginx.com timer = obj; 4486753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4487753Smax.romanov@nginx.com 4488753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4489753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4490753Smax.romanov@nginx.com } 4491753Smax.romanov@nginx.com } 4492753Smax.romanov@nginx.com 4493753Smax.romanov@nginx.com 4494753Smax.romanov@nginx.com static void 4495753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4496753Smax.romanov@nginx.com { 4497753Smax.romanov@nginx.com nxt_timer_t *timer; 4498753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4499753Smax.romanov@nginx.com 4500753Smax.romanov@nginx.com timer = obj; 4501753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4502753Smax.romanov@nginx.com 4503753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4504507Smax.romanov@nginx.com } 4505507Smax.romanov@nginx.com 4506507Smax.romanov@nginx.com 4507507Smax.romanov@nginx.com static void 4508753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4509507Smax.romanov@nginx.com { 4510753Smax.romanov@nginx.com nxt_app_t *app; 4511753Smax.romanov@nginx.com nxt_port_t *port; 4512753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4513753Smax.romanov@nginx.com 4514753Smax.romanov@nginx.com app_joint = obj; 4515753Smax.romanov@nginx.com app = app_joint->app; 4516753Smax.romanov@nginx.com 4517753Smax.romanov@nginx.com for ( ;; ) { 4518753Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 4519753Smax.romanov@nginx.com if (port == NULL) { 4520753Smax.romanov@nginx.com break; 4521753Smax.romanov@nginx.com } 4522753Smax.romanov@nginx.com 4523753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4524753Smax.romanov@nginx.com 4525753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4526753Smax.romanov@nginx.com 4527753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4528753Smax.romanov@nginx.com } 4529753Smax.romanov@nginx.com 4530753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 4531753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4532753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 4533753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4534753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4535753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4536753Smax.romanov@nginx.com 4537753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 4538753Smax.romanov@nginx.com nxt_free(app); 4539753Smax.romanov@nginx.com 4540753Smax.romanov@nginx.com app_joint->app = NULL; 4541753Smax.romanov@nginx.com 4542753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4543753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4544753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4545753Smax.romanov@nginx.com 4546753Smax.romanov@nginx.com } else { 4547753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4548753Smax.romanov@nginx.com } 4549141Smax.romanov@nginx.com } 4550141Smax.romanov@nginx.com 4551141Smax.romanov@nginx.com 4552427Smax.romanov@nginx.com static void 4553427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 4554141Smax.romanov@nginx.com { 45551294Smax.romanov@nginx.com int ra_use_delta; 45561123Smax.romanov@nginx.com nxt_app_t *app; 45571123Smax.romanov@nginx.com nxt_bool_t can_start_process; 45581123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 45591123Smax.romanov@nginx.com 45601123Smax.romanov@nginx.com req_app_link = state->req_app_link; 4561427Smax.romanov@nginx.com app = state->app; 4562427Smax.romanov@nginx.com 4563427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 45641294Smax.romanov@nginx.com ra_use_delta = -nxt_queue_chk_remove(&req_app_link->link_app_requests); 45651123Smax.romanov@nginx.com 45661123Smax.romanov@nginx.com if (nxt_queue_chk_remove(&req_app_link->link_port_pending)) 4567425Smax.romanov@nginx.com { 45681123Smax.romanov@nginx.com nxt_assert(req_app_link->link_app_pending.next != NULL); 45691123Smax.romanov@nginx.com 45701123Smax.romanov@nginx.com nxt_queue_remove(&req_app_link->link_app_pending); 45711123Smax.romanov@nginx.com req_app_link->link_app_pending.next = NULL; 45721123Smax.romanov@nginx.com 45731294Smax.romanov@nginx.com ra_use_delta--; 45741123Smax.romanov@nginx.com } 45751123Smax.romanov@nginx.com 45761123Smax.romanov@nginx.com state->failed_port = req_app_link->app_port; 45771123Smax.romanov@nginx.com 45781123Smax.romanov@nginx.com if (req_app_link->app_port != NULL) { 4579427Smax.romanov@nginx.com state->failed_port_use_delta--; 4580427Smax.romanov@nginx.com 4581427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 4582427Smax.romanov@nginx.com 4583427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 4584427Smax.romanov@nginx.com state->failed_port_use_delta--; 4585427Smax.romanov@nginx.com } 4586427Smax.romanov@nginx.com 45871123Smax.romanov@nginx.com req_app_link->app_port = NULL; 4588427Smax.romanov@nginx.com } 4589427Smax.romanov@nginx.com 4590507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 4591507Smax.romanov@nginx.com 4592427Smax.romanov@nginx.com state->port = NULL; 4593507Smax.romanov@nginx.com state->start_process = 0; 4594427Smax.romanov@nginx.com 4595427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 4596507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 4597427Smax.romanov@nginx.com { 45981123Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, req_app_link, 45991123Smax.romanov@nginx.com req_app_link->req_rpc_data); 46001123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4601427Smax.romanov@nginx.com goto fail; 4602427Smax.romanov@nginx.com } 4603427Smax.romanov@nginx.com 4604427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 46051123Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, 46061123Smax.romanov@nginx.com &req_app_link->link_app_requests); 4607427Smax.romanov@nginx.com 4608427Smax.romanov@nginx.com } else { 46091123Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, 46101123Smax.romanov@nginx.com &req_app_link->link_app_requests); 4611427Smax.romanov@nginx.com } 4612427Smax.romanov@nginx.com 46131294Smax.romanov@nginx.com ra_use_delta++; 46141123Smax.romanov@nginx.com 46151123Smax.romanov@nginx.com nxt_debug(task, "req_app_link stream #%uD enqueue to app->requests", 46161123Smax.romanov@nginx.com req_app_link->stream); 4617427Smax.romanov@nginx.com 4618507Smax.romanov@nginx.com if (can_start_process) { 4619507Smax.romanov@nginx.com app->pending_processes++; 4620507Smax.romanov@nginx.com state->start_process = 1; 4621425Smax.romanov@nginx.com } 4622425Smax.romanov@nginx.com 4623425Smax.romanov@nginx.com } else { 4624427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 4625427Smax.romanov@nginx.com 4626427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 46271123Smax.romanov@nginx.com req_app_link = nxt_request_app_link_alloc(task, req_app_link, 46281123Smax.romanov@nginx.com req_app_link->req_rpc_data); 46291123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4630427Smax.romanov@nginx.com goto fail; 4631351Smax.romanov@nginx.com } 4632427Smax.romanov@nginx.com 46331123Smax.romanov@nginx.com req_app_link->app_port = state->port; 46341123Smax.romanov@nginx.com 46351123Smax.romanov@nginx.com nxt_request_app_link_pending(task, app, req_app_link); 4636425Smax.romanov@nginx.com } 4637507Smax.romanov@nginx.com 4638507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 4639507Smax.romanov@nginx.com app->pending_processes++; 4640507Smax.romanov@nginx.com state->start_process = 1; 4641507Smax.romanov@nginx.com } 4642343Smax.romanov@nginx.com } 4643343Smax.romanov@nginx.com 46441294Smax.romanov@nginx.com nxt_request_app_link_chk_use(req_app_link, ra_use_delta); 46451294Smax.romanov@nginx.com 4646427Smax.romanov@nginx.com fail: 4647427Smax.romanov@nginx.com 46481123Smax.romanov@nginx.com state->shared_ra = req_app_link; 4649427Smax.romanov@nginx.com } 4650427Smax.romanov@nginx.com 4651427Smax.romanov@nginx.com 4652427Smax.romanov@nginx.com static nxt_int_t 4653427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 4654427Smax.romanov@nginx.com { 46551123Smax.romanov@nginx.com nxt_int_t res; 46561123Smax.romanov@nginx.com nxt_app_t *app; 46571123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link; 46581123Smax.romanov@nginx.com 46591123Smax.romanov@nginx.com req_app_link = state->shared_ra; 4660427Smax.romanov@nginx.com app = state->app; 4661427Smax.romanov@nginx.com 4662427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 4663427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 4664425Smax.romanov@nginx.com } 4665425Smax.romanov@nginx.com 46661123Smax.romanov@nginx.com if (nxt_slow_path(req_app_link == NULL)) { 4667427Smax.romanov@nginx.com if (state->port != NULL) { 4668427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 4669425Smax.romanov@nginx.com } 4670425Smax.romanov@nginx.com 46711446Smax.romanov@nginx.com nxt_request_app_link_error(task, app, state->req_app_link, 4672427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 4673427Smax.romanov@nginx.com 4674351Smax.romanov@nginx.com return NXT_ERROR; 4675351Smax.romanov@nginx.com } 4676351Smax.romanov@nginx.com 4677427Smax.romanov@nginx.com if (state->port != NULL) { 4678343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 4679163Smax.romanov@nginx.com 46801123Smax.romanov@nginx.com req_app_link->app_port = state->port; 4681343Smax.romanov@nginx.com 4682507Smax.romanov@nginx.com if (state->start_process) { 4683507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4684507Smax.romanov@nginx.com } 4685507Smax.romanov@nginx.com 4686141Smax.romanov@nginx.com return NXT_OK; 4687141Smax.romanov@nginx.com } 4688141Smax.romanov@nginx.com 4689507Smax.romanov@nginx.com if (!state->start_process) { 4690507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 4691343Smax.romanov@nginx.com &app->name, app); 4692343Smax.romanov@nginx.com 4693343Smax.romanov@nginx.com return NXT_AGAIN; 4694343Smax.romanov@nginx.com } 4695343Smax.romanov@nginx.com 4696507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 4697343Smax.romanov@nginx.com 4698343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 46991446Smax.romanov@nginx.com nxt_request_app_link_error(task, app, req_app_link, 47001123Smax.romanov@nginx.com "Failed to start app process"); 4701343Smax.romanov@nginx.com 4702141Smax.romanov@nginx.com return NXT_ERROR; 4703141Smax.romanov@nginx.com } 4704141Smax.romanov@nginx.com 4705141Smax.romanov@nginx.com return NXT_AGAIN; 470688Smax.romanov@nginx.com } 470788Smax.romanov@nginx.com 470888Smax.romanov@nginx.com 4709427Smax.romanov@nginx.com static nxt_int_t 47101123Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 47111123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 4712427Smax.romanov@nginx.com { 4713427Smax.romanov@nginx.com nxt_port_select_state_t state; 4714427Smax.romanov@nginx.com 47151123Smax.romanov@nginx.com state.req_app_link = req_app_link; 4716427Smax.romanov@nginx.com state.app = app; 4717427Smax.romanov@nginx.com 4718427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4719427Smax.romanov@nginx.com 4720427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4721427Smax.romanov@nginx.com 4722427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4723427Smax.romanov@nginx.com 4724427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 4725427Smax.romanov@nginx.com } 4726427Smax.romanov@nginx.com 4727427Smax.romanov@nginx.com 4728431Sigor@sysoev.ru void 47291007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, 4730964Sigor@sysoev.ru nxt_app_t *app) 473153Sigor@sysoev.ru { 47321123Smax.romanov@nginx.com nxt_int_t res; 47331123Smax.romanov@nginx.com nxt_port_t *port; 47341123Smax.romanov@nginx.com nxt_event_engine_t *engine; 47351123Smax.romanov@nginx.com nxt_request_app_link_t ra_local, *req_app_link; 47361123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 4737431Sigor@sysoev.ru 473888Smax.romanov@nginx.com engine = task->thread->engine; 473988Smax.romanov@nginx.com 47401123Smax.romanov@nginx.com req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port, 4741318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4742318Smax.romanov@nginx.com nxt_router_response_error_handler, 47431123Smax.romanov@nginx.com sizeof(nxt_request_rpc_data_t)); 47441123Smax.romanov@nginx.com if (nxt_slow_path(req_rpc_data == NULL)) { 4745431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4746141Smax.romanov@nginx.com return; 474788Smax.romanov@nginx.com } 474888Smax.romanov@nginx.com 47491402Smax.romanov@nginx.com /* 47501402Smax.romanov@nginx.com * At this point we have request req_rpc_data allocated and registered 47511402Smax.romanov@nginx.com * in port handlers. Need to fixup request memory pool. Counterpart 47521402Smax.romanov@nginx.com * release will be called via following call chain: 47531402Smax.romanov@nginx.com * nxt_request_rpc_data_unlink() -> 47541402Smax.romanov@nginx.com * nxt_router_http_request_done() -> 47551402Smax.romanov@nginx.com * nxt_router_http_request_release() 47561402Smax.romanov@nginx.com */ 47571402Smax.romanov@nginx.com nxt_mp_retain(r->mem_pool); 47581402Smax.romanov@nginx.com 47591402Smax.romanov@nginx.com r->timer.task = &engine->task; 47601402Smax.romanov@nginx.com r->timer.work_queue = &engine->fast_work_queue; 47611402Smax.romanov@nginx.com r->timer.log = engine->task.log; 47621402Smax.romanov@nginx.com r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 47631402Smax.romanov@nginx.com 47641123Smax.romanov@nginx.com req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data); 47651123Smax.romanov@nginx.com req_rpc_data->app = app; 4766425Smax.romanov@nginx.com 4767425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4768425Smax.romanov@nginx.com 47691123Smax.romanov@nginx.com req_rpc_data->request = r; 47701131Smax.romanov@nginx.com r->req_rpc_data = req_rpc_data; 47711123Smax.romanov@nginx.com 47721123Smax.romanov@nginx.com req_app_link = &ra_local; 47731123Smax.romanov@nginx.com nxt_request_app_link_init(task, req_app_link, req_rpc_data); 47741123Smax.romanov@nginx.com 47751123Smax.romanov@nginx.com res = nxt_router_app_port(task, app, req_app_link); 47761123Smax.romanov@nginx.com req_app_link = req_rpc_data->req_app_link; 47771294Smax.romanov@nginx.com 47781294Smax.romanov@nginx.com if (res == NXT_OK) { 47791294Smax.romanov@nginx.com port = req_app_link->app_port; 47801294Smax.romanov@nginx.com 47811294Smax.romanov@nginx.com nxt_assert(port != NULL); 47821294Smax.romanov@nginx.com 47831294Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, req_rpc_data, port->pid); 47841294Smax.romanov@nginx.com 47851294Smax.romanov@nginx.com nxt_router_app_prepare_request(task, req_app_link); 47861294Smax.romanov@nginx.com } 47871294Smax.romanov@nginx.com 47881294Smax.romanov@nginx.com nxt_request_app_link_use(task, req_app_link, -1); 4789167Smax.romanov@nginx.com } 4790167Smax.romanov@nginx.com 4791167Smax.romanov@nginx.com 4792167Smax.romanov@nginx.com static void 4793423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4794423Smax.romanov@nginx.com { 4795423Smax.romanov@nginx.com } 4796423Smax.romanov@nginx.com 4797423Smax.romanov@nginx.com 4798423Smax.romanov@nginx.com static void 47991123Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, 48001123Smax.romanov@nginx.com nxt_request_app_link_t *req_app_link) 4801167Smax.romanov@nginx.com { 48021414Smax.romanov@nginx.com nxt_buf_t *buf; 48031123Smax.romanov@nginx.com nxt_int_t res; 48041123Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 48051123Smax.romanov@nginx.com nxt_apr_action_t apr_action; 48061123Smax.romanov@nginx.com 48071123Smax.romanov@nginx.com nxt_assert(req_app_link->app_port != NULL); 48081123Smax.romanov@nginx.com 48091123Smax.romanov@nginx.com port = req_app_link->app_port; 48101123Smax.romanov@nginx.com reply_port = req_app_link->reply_port; 48111123Smax.romanov@nginx.com 48121123Smax.romanov@nginx.com apr_action = NXT_APR_REQUEST_FAILED; 4813343Smax.romanov@nginx.com 48141452Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port); 48151446Smax.romanov@nginx.com 4816141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 4817141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 4818122Smax.romanov@nginx.com 4819122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 48201446Smax.romanov@nginx.com nxt_request_app_link_error(task, port->app, req_app_link, 4821345Smax.romanov@nginx.com "Failed to send reply port to application"); 48221446Smax.romanov@nginx.com 4823343Smax.romanov@nginx.com goto release_port; 4824122Smax.romanov@nginx.com } 48251452Smax.romanov@nginx.com 48261452Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 482788Smax.romanov@nginx.com } 482888Smax.romanov@nginx.com 48291123Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, req_app_link->request, port, 4830743Smax.romanov@nginx.com nxt_app_msg_prefix[port->app->type]); 4831743Smax.romanov@nginx.com 4832743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 48331446Smax.romanov@nginx.com nxt_request_app_link_error(task, port->app, req_app_link, 4834345Smax.romanov@nginx.com "Failed to prepare message for application"); 4835343Smax.romanov@nginx.com goto release_port; 4836122Smax.romanov@nginx.com } 483788Smax.romanov@nginx.com 4838507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4839743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4840743Smax.romanov@nginx.com port->socket.fd); 484188Smax.romanov@nginx.com 48421123Smax.romanov@nginx.com apr_action = NXT_APR_NEW_PORT; 48431123Smax.romanov@nginx.com 48441123Smax.romanov@nginx.com req_app_link->msg_info.buf = buf; 48451123Smax.romanov@nginx.com req_app_link->msg_info.completion_handler = buf->completion_handler; 4846743Smax.romanov@nginx.com 4847743Smax.romanov@nginx.com for (; buf; buf = buf->next) { 4848743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 4849423Smax.romanov@nginx.com } 4850423Smax.romanov@nginx.com 48511123Smax.romanov@nginx.com buf = req_app_link->msg_info.buf; 48521123Smax.romanov@nginx.com 48531123Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, 48541123Smax.romanov@nginx.com &req_app_link->msg_info.tracking, 48551123Smax.romanov@nginx.com req_app_link->stream); 4856423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 48571446Smax.romanov@nginx.com nxt_request_app_link_error(task, port->app, req_app_link, 48581123Smax.romanov@nginx.com "Failed to get tracking area"); 4859423Smax.romanov@nginx.com goto release_port; 4860423Smax.romanov@nginx.com } 4861423Smax.romanov@nginx.com 48621414Smax.romanov@nginx.com if (req_app_link->body_fd != -1) { 48631414Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: send body fd %d", req_app_link->stream, 48641414Smax.romanov@nginx.com req_app_link->body_fd); 48651414Smax.romanov@nginx.com 48661414Smax.romanov@nginx.com lseek(req_app_link->body_fd, 0, SEEK_SET); 48671414Smax.romanov@nginx.com } 48681414Smax.romanov@nginx.com 48691414Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_REQ_HEADERS, 48701414Smax.romanov@nginx.com req_app_link->body_fd, 48711403Smax.romanov@nginx.com req_app_link->stream, reply_port->id, buf, 48721123Smax.romanov@nginx.com &req_app_link->msg_info.tracking); 4873122Smax.romanov@nginx.com 4874122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 48751446Smax.romanov@nginx.com nxt_request_app_link_error(task, port->app, req_app_link, 48761123Smax.romanov@nginx.com "Failed to send message to application"); 4877343Smax.romanov@nginx.com goto release_port; 4878122Smax.romanov@nginx.com } 4879343Smax.romanov@nginx.com 4880343Smax.romanov@nginx.com release_port: 4881343Smax.romanov@nginx.com 48821123Smax.romanov@nginx.com nxt_router_app_port_release(task, port, apr_action); 48831123Smax.romanov@nginx.com 48841123Smax.romanov@nginx.com nxt_request_app_link_update_peer(task, req_app_link); 488553Sigor@sysoev.ru } 488653Sigor@sysoev.ru 488753Sigor@sysoev.ru 4888743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4889743Smax.romanov@nginx.com nxt_list_part_t *part; 4890743Smax.romanov@nginx.com nxt_http_field_t *field; 4891743Smax.romanov@nginx.com }; 4892743Smax.romanov@nginx.com 4893743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4894743Smax.romanov@nginx.com 4895743Smax.romanov@nginx.com 4896743Smax.romanov@nginx.com static nxt_http_field_t * 4897743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4898216Sigor@sysoev.ru { 4899743Smax.romanov@nginx.com if (part == NULL) { 4900743Smax.romanov@nginx.com return NULL; 4901216Sigor@sysoev.ru } 4902216Sigor@sysoev.ru 4903743Smax.romanov@nginx.com while (part->nelts == 0) { 4904743Smax.romanov@nginx.com part = part->next; 4905743Smax.romanov@nginx.com if (part == NULL) { 4906743Smax.romanov@nginx.com return NULL; 4907743Smax.romanov@nginx.com } 4908216Sigor@sysoev.ru } 4909216Sigor@sysoev.ru 4910743Smax.romanov@nginx.com i->part = part; 4911743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4912743Smax.romanov@nginx.com 4913743Smax.romanov@nginx.com return i->field; 4914743Smax.romanov@nginx.com } 4915743Smax.romanov@nginx.com 4916743Smax.romanov@nginx.com 4917743Smax.romanov@nginx.com static nxt_http_field_t * 4918743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4919743Smax.romanov@nginx.com { 4920743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4921743Smax.romanov@nginx.com } 4922743Smax.romanov@nginx.com 4923743Smax.romanov@nginx.com 4924743Smax.romanov@nginx.com static nxt_http_field_t * 4925743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4926743Smax.romanov@nginx.com { 4927743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4928743Smax.romanov@nginx.com 4929743Smax.romanov@nginx.com end += i->part->nelts; 4930743Smax.romanov@nginx.com i->field++; 4931743Smax.romanov@nginx.com 4932743Smax.romanov@nginx.com if (i->field < end) { 4933743Smax.romanov@nginx.com return i->field; 4934216Sigor@sysoev.ru } 4935216Sigor@sysoev.ru 4936743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4937216Sigor@sysoev.ru } 4938216Sigor@sysoev.ru 4939216Sigor@sysoev.ru 4940743Smax.romanov@nginx.com static nxt_buf_t * 49411007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, 4942743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix) 4943216Sigor@sysoev.ru { 49441007Salexander.borisov@nginx.com void *target_pos, *query_pos; 49451007Salexander.borisov@nginx.com u_char *pos, *end, *p, c; 49461007Salexander.borisov@nginx.com size_t fields_count, req_size, size, free_size; 49471007Salexander.borisov@nginx.com size_t copy_size; 49481007Salexander.borisov@nginx.com nxt_off_t content_length; 49491007Salexander.borisov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 49501007Salexander.borisov@nginx.com nxt_http_field_t *field, *dup; 49511007Salexander.borisov@nginx.com nxt_unit_field_t *dst_field; 49521007Salexander.borisov@nginx.com nxt_fields_iter_t iter, dup_iter; 49531007Salexander.borisov@nginx.com nxt_unit_request_t *req; 4954216Sigor@sysoev.ru 4955743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 49561007Salexander.borisov@nginx.com + r->method->length + 1 49571007Salexander.borisov@nginx.com + r->version.length + 1 49581007Salexander.borisov@nginx.com + r->remote->length + 1 49591007Salexander.borisov@nginx.com + r->local->length + 1 49601007Salexander.borisov@nginx.com + r->server_name.length + 1 49611007Salexander.borisov@nginx.com + r->target.length + 1 49621007Salexander.borisov@nginx.com + (r->path->start != r->target.start ? r->path->length + 1 : 0); 49631007Salexander.borisov@nginx.com 49641007Salexander.borisov@nginx.com content_length = r->content_length_n < 0 ? 0 : r->content_length_n; 4965743Smax.romanov@nginx.com fields_count = 0; 4966743Smax.romanov@nginx.com 49671007Salexander.borisov@nginx.com nxt_list_each(field, r->fields) { 4968743Smax.romanov@nginx.com fields_count++; 4969743Smax.romanov@nginx.com 4970743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4971743Smax.romanov@nginx.com + field->value_length + 1; 4972743Smax.romanov@nginx.com } nxt_list_loop; 4973743Smax.romanov@nginx.com 4974743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4975743Smax.romanov@nginx.com 4976743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4977743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4978743Smax.romanov@nginx.com (int) req_size); 4979743Smax.romanov@nginx.com 4980743Smax.romanov@nginx.com return NULL; 4981743Smax.romanov@nginx.com } 4982743Smax.romanov@nginx.com 4983743Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, port, 49841007Salexander.borisov@nginx.com nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); 4985743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4986743Smax.romanov@nginx.com return NULL; 4987743Smax.romanov@nginx.com } 4988743Smax.romanov@nginx.com 4989743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4990743Smax.romanov@nginx.com out->mem.free += req_size; 4991743Smax.romanov@nginx.com 49921007Salexander.borisov@nginx.com req->content_length = content_length; 4993743Smax.romanov@nginx.com 4994743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4995743Smax.romanov@nginx.com 4996743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4997743Smax.romanov@nginx.com 49981007Salexander.borisov@nginx.com req->method_length = r->method->length; 4999743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 50001007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 5001743Smax.romanov@nginx.com *p++ = '\0'; 5002743Smax.romanov@nginx.com 50031007Salexander.borisov@nginx.com req->version_length = r->version.length; 5004743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 50051007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 5006743Smax.romanov@nginx.com *p++ = '\0'; 5007743Smax.romanov@nginx.com 50081007Salexander.borisov@nginx.com req->remote_length = r->remote->address_length; 5009743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 50101007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), 50111007Salexander.borisov@nginx.com r->remote->address_length); 5012743Smax.romanov@nginx.com *p++ = '\0'; 5013743Smax.romanov@nginx.com 50141007Salexander.borisov@nginx.com req->local_length = r->local->address_length; 5015743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 50161007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); 5017743Smax.romanov@nginx.com *p++ = '\0'; 5018743Smax.romanov@nginx.com 50191011Smax.romanov@nginx.com req->tls = (r->tls != NULL); 50201131Smax.romanov@nginx.com req->websocket_handshake = r->websocket_handshake; 50211011Smax.romanov@nginx.com 50221007Salexander.borisov@nginx.com req->server_name_length = r->server_name.length; 5023967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 50241007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->server_name.start, r->server_name.length); 5025967Svbart@nginx.com *p++ = '\0'; 5026967Svbart@nginx.com 5027743Smax.romanov@nginx.com target_pos = p; 50281007Salexander.borisov@nginx.com req->target_length = (uint32_t) r->target.length; 5029743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 50301007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 5031743Smax.romanov@nginx.com *p++ = '\0'; 5032743Smax.romanov@nginx.com 50331007Salexander.borisov@nginx.com req->path_length = (uint32_t) r->path->length; 50341007Salexander.borisov@nginx.com if (r->path->start == r->target.start) { 5035743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 5036277Sigor@sysoev.ru 5037216Sigor@sysoev.ru } else { 5038743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 50391007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 5040743Smax.romanov@nginx.com *p++ = '\0'; 5041305Smax.romanov@nginx.com } 5042216Sigor@sysoev.ru 50431007Salexander.borisov@nginx.com req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0; 50441007Salexander.borisov@nginx.com if (r->args != NULL && r->args->start != NULL) { 5045743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 50461007Salexander.borisov@nginx.com r->args->start - r->target.start); 5047743Smax.romanov@nginx.com 5048743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 5049277Sigor@sysoev.ru 5050216Sigor@sysoev.ru } else { 5051743Smax.romanov@nginx.com req->query.offset = 0; 5052216Sigor@sysoev.ru } 5053216Sigor@sysoev.ru 5054743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 5055743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 5056743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 5057743Smax.romanov@nginx.com 5058743Smax.romanov@nginx.com dst_field = req->fields; 5059743Smax.romanov@nginx.com 50601007Salexander.borisov@nginx.com for (field = nxt_fields_first(r->fields, &iter); 5061743Smax.romanov@nginx.com field != NULL; 5062743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 5063743Smax.romanov@nginx.com { 5064743Smax.romanov@nginx.com if (field->skip) { 5065743Smax.romanov@nginx.com continue; 5066743Smax.romanov@nginx.com } 5067743Smax.romanov@nginx.com 5068743Smax.romanov@nginx.com dst_field->hash = field->hash; 5069743Smax.romanov@nginx.com dst_field->skip = 0; 5070743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 5071743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 5072743Smax.romanov@nginx.com 50731007Salexander.borisov@nginx.com if (field == r->content_length) { 5074743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 5075743Smax.romanov@nginx.com 50761007Salexander.borisov@nginx.com } else if (field == r->content_type) { 5077743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 5078743Smax.romanov@nginx.com 50791007Salexander.borisov@nginx.com } else if (field == r->cookie) { 5080743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 5081743Smax.romanov@nginx.com } 5082743Smax.romanov@nginx.com 5083743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 5084743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 5085743Smax.romanov@nginx.com (int) field->name_length, field->name, 5086743Smax.romanov@nginx.com (int) field->value_length, field->value); 5087743Smax.romanov@nginx.com 5088743Smax.romanov@nginx.com if (prefix->length != 0) { 5089743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 5090743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 5091743Smax.romanov@nginx.com 5092743Smax.romanov@nginx.com end = field->name + field->name_length; 5093743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 5094743Smax.romanov@nginx.com c = *pos; 5095743Smax.romanov@nginx.com 5096743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 5097743Smax.romanov@nginx.com *p++ = (c & ~0x20); 5098743Smax.romanov@nginx.com continue; 5099743Smax.romanov@nginx.com } 5100743Smax.romanov@nginx.com 5101743Smax.romanov@nginx.com if (c == '-') { 5102743Smax.romanov@nginx.com *p++ = '_'; 5103743Smax.romanov@nginx.com continue; 5104743Smax.romanov@nginx.com } 5105743Smax.romanov@nginx.com 5106743Smax.romanov@nginx.com *p++ = c; 5107743Smax.romanov@nginx.com } 5108743Smax.romanov@nginx.com 5109743Smax.romanov@nginx.com } else { 5110743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 5111743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 5112743Smax.romanov@nginx.com } 5113743Smax.romanov@nginx.com 5114743Smax.romanov@nginx.com *p++ = '\0'; 5115743Smax.romanov@nginx.com 5116743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 5117743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 5118743Smax.romanov@nginx.com 5119743Smax.romanov@nginx.com if (prefix->length != 0) { 5120743Smax.romanov@nginx.com dup_iter = iter; 5121743Smax.romanov@nginx.com 5122743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 5123743Smax.romanov@nginx.com dup != NULL; 5124743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 5125743Smax.romanov@nginx.com { 5126743Smax.romanov@nginx.com if (dup->name_length != field->name_length 5127743Smax.romanov@nginx.com || dup->skip 5128743Smax.romanov@nginx.com || dup->hash != field->hash 5129743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 5130743Smax.romanov@nginx.com { 5131743Smax.romanov@nginx.com continue; 5132743Smax.romanov@nginx.com } 5133743Smax.romanov@nginx.com 5134743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 5135743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 5136743Smax.romanov@nginx.com 5137743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 5138743Smax.romanov@nginx.com 5139743Smax.romanov@nginx.com dup->skip = 1; 5140743Smax.romanov@nginx.com } 5141743Smax.romanov@nginx.com } 5142743Smax.romanov@nginx.com 5143743Smax.romanov@nginx.com *p++ = '\0'; 5144743Smax.romanov@nginx.com 5145743Smax.romanov@nginx.com dst_field++; 5146743Smax.romanov@nginx.com } 5147743Smax.romanov@nginx.com 51481007Salexander.borisov@nginx.com req->fields_count = (uint32_t) (dst_field - req->fields); 5149743Smax.romanov@nginx.com 5150743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 5151743Smax.romanov@nginx.com 5152743Smax.romanov@nginx.com buf = out; 5153743Smax.romanov@nginx.com tail = &buf->next; 5154216Sigor@sysoev.ru 51551007Salexander.borisov@nginx.com for (b = r->body; b != NULL; b = b->next) { 5156743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 5157743Smax.romanov@nginx.com pos = b->mem.pos; 5158743Smax.romanov@nginx.com 5159743Smax.romanov@nginx.com while (size > 0) { 5160743Smax.romanov@nginx.com if (buf == NULL) { 5161743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 5162743Smax.romanov@nginx.com 5163743Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, port, free_size); 5164743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 5165743Smax.romanov@nginx.com while (out != NULL) { 5166743Smax.romanov@nginx.com buf = out->next; 51671269Sigor@sysoev.ru out->next = NULL; 5168743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 5169743Smax.romanov@nginx.com out = buf; 5170743Smax.romanov@nginx.com } 5171743Smax.romanov@nginx.com return NULL; 5172743Smax.romanov@nginx.com } 5173743Smax.romanov@nginx.com 5174743Smax.romanov@nginx.com *tail = buf; 5175743Smax.romanov@nginx.com tail = &buf->next; 5176743Smax.romanov@nginx.com 5177743Smax.romanov@nginx.com } else { 5178743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5179743Smax.romanov@nginx.com if (free_size < size 5180743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 5181743Smax.romanov@nginx.com == NXT_OK) 5182743Smax.romanov@nginx.com { 5183743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 5184743Smax.romanov@nginx.com } 5185743Smax.romanov@nginx.com } 5186743Smax.romanov@nginx.com 5187743Smax.romanov@nginx.com if (free_size > 0) { 5188743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 5189743Smax.romanov@nginx.com 5190743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 5191743Smax.romanov@nginx.com 5192743Smax.romanov@nginx.com size -= copy_size; 5193743Smax.romanov@nginx.com pos += copy_size; 5194743Smax.romanov@nginx.com 5195743Smax.romanov@nginx.com if (size == 0) { 5196743Smax.romanov@nginx.com break; 5197743Smax.romanov@nginx.com } 5198743Smax.romanov@nginx.com } 5199743Smax.romanov@nginx.com 5200743Smax.romanov@nginx.com buf = NULL; 5201743Smax.romanov@nginx.com } 5202216Sigor@sysoev.ru } 5203216Sigor@sysoev.ru 5204743Smax.romanov@nginx.com return out; 5205584Salexander.borisov@nginx.com } 5206584Salexander.borisov@nginx.com 5207584Salexander.borisov@nginx.com 520853Sigor@sysoev.ru static void 5209318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 5210318Smax.romanov@nginx.com { 5211615Smax.romanov@nginx.com nxt_app_t *app; 5212615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 5213615Smax.romanov@nginx.com nxt_port_t *port; 5214615Smax.romanov@nginx.com nxt_timer_t *timer; 5215615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 52161007Salexander.borisov@nginx.com nxt_http_request_t *r; 52171123Smax.romanov@nginx.com nxt_request_app_link_t *pending_ra; 52181123Smax.romanov@nginx.com nxt_request_rpc_data_t *req_rpc_data; 5219615Smax.romanov@nginx.com nxt_port_select_state_t state; 5220318Smax.romanov@nginx.com 5221318Smax.romanov@nginx.com timer = obj; 5222318Smax.romanov@nginx.com 5223318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 5224318Smax.romanov@nginx.com 52251007Salexander.borisov@nginx.com r = nxt_timer_data(timer, nxt_http_request_t, timer); 52261123Smax.romanov@nginx.com req_rpc_data = r->timer_data; 52271123Smax.romanov@nginx.com app = req_rpc_data->app; 5228615Smax.romanov@nginx.com 5229615Smax.romanov@nginx.com if (app == NULL) { 5230615Smax.romanov@nginx.com goto generate_error; 5231615Smax.romanov@nginx.com } 5232615Smax.romanov@nginx.com 5233615Smax.romanov@nginx.com port = NULL; 5234615Smax.romanov@nginx.com pending_ra = NULL; 5235615Smax.romanov@nginx.com 52361123Smax.romanov@nginx.com if (req_rpc_data->app_port != NULL) { 52371123Smax.romanov@nginx.com port = req_rpc_data->app_port; 52381123Smax.romanov@nginx.com req_rpc_data->app_port = NULL; 52391123Smax.romanov@nginx.com } 52401123Smax.romanov@nginx.com 52411123Smax.romanov@nginx.com if (port == NULL && req_rpc_data->req_app_link != NULL 52421123Smax.romanov@nginx.com && req_rpc_data->req_app_link->app_port != NULL) 52431123Smax.romanov@nginx.com { 52441123Smax.romanov@nginx.com port = req_rpc_data->req_app_link->app_port; 52451123Smax.romanov@nginx.com req_rpc_data->req_app_link->app_port = NULL; 5246615Smax.romanov@nginx.com } 5247615Smax.romanov@nginx.com 5248615Smax.romanov@nginx.com if (port == NULL) { 5249615Smax.romanov@nginx.com goto generate_error; 5250431Sigor@sysoev.ru } 5251615Smax.romanov@nginx.com 5252615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 5253615Smax.romanov@nginx.com 5254615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 5255615Smax.romanov@nginx.com 5256615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 5257615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 5258615Smax.romanov@nginx.com 52591123Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_request_app_link_t, 5260615Smax.romanov@nginx.com link_port_pending); 5261615Smax.romanov@nginx.com 5262615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 5263615Smax.romanov@nginx.com 5264615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 5265615Smax.romanov@nginx.com &app->name, pending_ra->stream); 5266615Smax.romanov@nginx.com 5267615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 5268615Smax.romanov@nginx.com pending_ra->stream); 5269615Smax.romanov@nginx.com 5270615Smax.romanov@nginx.com if (cancelled) { 52711123Smax.romanov@nginx.com state.req_app_link = pending_ra; 5272615Smax.romanov@nginx.com state.app = app; 5273615Smax.romanov@nginx.com 52741375Smax.romanov@nginx.com /* 52751375Smax.romanov@nginx.com * Need to increment use count "in advance" because 52761375Smax.romanov@nginx.com * nxt_router_port_select() will remove pending_ra from lists 52771375Smax.romanov@nginx.com * and decrement use count. 52781375Smax.romanov@nginx.com */ 52791375Smax.romanov@nginx.com nxt_request_app_link_inc_use(pending_ra); 52801375Smax.romanov@nginx.com 5281615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 5282615Smax.romanov@nginx.com 5283615Smax.romanov@nginx.com } else { 5284615Smax.romanov@nginx.com pending_ra = NULL; 5285615Smax.romanov@nginx.com } 5286615Smax.romanov@nginx.com } 5287615Smax.romanov@nginx.com 5288615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 5289615Smax.romanov@nginx.com 52901294Smax.romanov@nginx.com if (pending_ra != NULL) { 52911294Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 52921375Smax.romanov@nginx.com /* 52931375Smax.romanov@nginx.com * Reference counter already incremented above, this will 52941375Smax.romanov@nginx.com * keep pending_ra while nxt_router_app_process_request() 52951375Smax.romanov@nginx.com * task is in queue. Reference counter decreased in 52961375Smax.romanov@nginx.com * nxt_router_app_process_request() after processing. 52971375Smax.romanov@nginx.com */ 52981375Smax.romanov@nginx.com 52991375Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 53001375Smax.romanov@nginx.com nxt_router_app_process_request, 53011375Smax.romanov@nginx.com &task->thread->engine->task, app, pending_ra); 53021375Smax.romanov@nginx.com 53031375Smax.romanov@nginx.com } else { 53041375Smax.romanov@nginx.com nxt_request_app_link_use(task, pending_ra, -1); 53051294Smax.romanov@nginx.com } 5306615Smax.romanov@nginx.com } 5307615Smax.romanov@nginx.com 5308615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 5309615Smax.romanov@nginx.com 5310615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 5311615Smax.romanov@nginx.com 5312615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 5313615Smax.romanov@nginx.com 5314615Smax.romanov@nginx.com generate_error: 5315615Smax.romanov@nginx.com 53161007Salexander.borisov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 5317615Smax.romanov@nginx.com 53181123Smax.romanov@nginx.com nxt_request_rpc_data_unlink(task, req_rpc_data); 5319318Smax.romanov@nginx.com } 53201007Salexander.borisov@nginx.com 53211007Salexander.borisov@nginx.com 53221007Salexander.borisov@nginx.com static nxt_int_t 53231007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r) 53241007Salexander.borisov@nginx.com { 53251007Salexander.borisov@nginx.com r->timer.handler = nxt_router_http_request_release; 53261007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 0); 53271007Salexander.borisov@nginx.com 53281007Salexander.borisov@nginx.com return NXT_OK; 53291007Salexander.borisov@nginx.com } 53301007Salexander.borisov@nginx.com 53311007Salexander.borisov@nginx.com 53321007Salexander.borisov@nginx.com static void 53331007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) 53341007Salexander.borisov@nginx.com { 53351007Salexander.borisov@nginx.com nxt_http_request_t *r; 53361007Salexander.borisov@nginx.com 53371007Salexander.borisov@nginx.com nxt_debug(task, "http app release"); 53381007Salexander.borisov@nginx.com 53391007Salexander.borisov@nginx.com r = nxt_timer_data(obj, nxt_http_request_t, timer); 53401007Salexander.borisov@nginx.com 53411007Salexander.borisov@nginx.com nxt_mp_release(r->mem_pool); 53421007Salexander.borisov@nginx.com } 53431321Smax.romanov@nginx.com 53441321Smax.romanov@nginx.com 53451321Smax.romanov@nginx.com static void 53461321Smax.romanov@nginx.com nxt_router_oosm_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 53471321Smax.romanov@nginx.com { 53481321Smax.romanov@nginx.com size_t mi; 53491321Smax.romanov@nginx.com uint32_t i; 53501321Smax.romanov@nginx.com nxt_bool_t ack; 53511321Smax.romanov@nginx.com nxt_process_t *process; 53521321Smax.romanov@nginx.com nxt_free_map_t *m; 53531321Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 53541321Smax.romanov@nginx.com 53551321Smax.romanov@nginx.com nxt_debug(task, "oosm in %PI", msg->port_msg.pid); 53561321Smax.romanov@nginx.com 53571321Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, 53581321Smax.romanov@nginx.com msg->port_msg.pid); 53591321Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 53601321Smax.romanov@nginx.com return; 53611321Smax.romanov@nginx.com } 53621321Smax.romanov@nginx.com 53631321Smax.romanov@nginx.com ack = 0; 53641321Smax.romanov@nginx.com 53651321Smax.romanov@nginx.com /* 53661321Smax.romanov@nginx.com * To mitigate possible racing condition (when OOSM message received 53671321Smax.romanov@nginx.com * after some of the memory was already freed), need to try to find 53681321Smax.romanov@nginx.com * first free segment in shared memory and send ACK if found. 53691321Smax.romanov@nginx.com */ 53701321Smax.romanov@nginx.com 53711321Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 53721321Smax.romanov@nginx.com 53731321Smax.romanov@nginx.com for (i = 0; i < process->incoming.size; i++) { 53741321Smax.romanov@nginx.com hdr = process->incoming.elts[i].mmap_handler->hdr; 53751321Smax.romanov@nginx.com m = hdr->free_map; 53761321Smax.romanov@nginx.com 53771321Smax.romanov@nginx.com for (mi = 0; mi < MAX_FREE_IDX; mi++) { 53781321Smax.romanov@nginx.com if (m[mi] != 0) { 53791321Smax.romanov@nginx.com ack = 1; 53801321Smax.romanov@nginx.com 53811321Smax.romanov@nginx.com nxt_debug(task, "oosm: already free #%uD %uz = 0x%08xA", 53821321Smax.romanov@nginx.com i, mi, m[mi]); 53831321Smax.romanov@nginx.com 53841321Smax.romanov@nginx.com break; 53851321Smax.romanov@nginx.com } 53861321Smax.romanov@nginx.com } 53871321Smax.romanov@nginx.com } 53881321Smax.romanov@nginx.com 53891321Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 53901321Smax.romanov@nginx.com 53911321Smax.romanov@nginx.com if (ack) { 53921321Smax.romanov@nginx.com (void) nxt_port_socket_write(task, msg->port, NXT_PORT_MSG_SHM_ACK, 53931321Smax.romanov@nginx.com -1, 0, 0, NULL); 53941321Smax.romanov@nginx.com } 53951321Smax.romanov@nginx.com } 5396