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> 10431Sigor@sysoev.ru #include <nxt_http.h> 11743Smax.romanov@nginx.com #include <nxt_port_memory_int.h> 12743Smax.romanov@nginx.com #include <nxt_unit_request.h> 13743Smax.romanov@nginx.com #include <nxt_unit_response.h> 1420Sigor@sysoev.ru 1520Sigor@sysoev.ru 16115Sigor@sysoev.ru typedef struct { 17318Smax.romanov@nginx.com nxt_str_t type; 18507Smax.romanov@nginx.com uint32_t processes; 19507Smax.romanov@nginx.com uint32_t max_processes; 20507Smax.romanov@nginx.com uint32_t spare_processes; 21318Smax.romanov@nginx.com nxt_msec_t timeout; 22427Smax.romanov@nginx.com nxt_msec_t res_timeout; 23507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 24318Smax.romanov@nginx.com uint32_t requests; 25318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 26507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 27133Sigor@sysoev.ru } nxt_router_app_conf_t; 28133Sigor@sysoev.ru 29133Sigor@sysoev.ru 30133Sigor@sysoev.ru typedef struct { 31133Sigor@sysoev.ru nxt_str_t application; 32115Sigor@sysoev.ru } nxt_router_listener_conf_t; 33115Sigor@sysoev.ru 34115Sigor@sysoev.ru 35423Smax.romanov@nginx.com typedef struct nxt_msg_info_s { 36423Smax.romanov@nginx.com nxt_buf_t *buf; 37423Smax.romanov@nginx.com nxt_port_mmap_tracking_t tracking; 38423Smax.romanov@nginx.com nxt_work_handler_t completion_handler; 39423Smax.romanov@nginx.com } nxt_msg_info_t; 40423Smax.romanov@nginx.com 41423Smax.romanov@nginx.com 42167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t; 43141Smax.romanov@nginx.com 44141Smax.romanov@nginx.com 45318Smax.romanov@nginx.com typedef struct { 46431Sigor@sysoev.ru uint32_t stream; 47431Sigor@sysoev.ru nxt_app_t *app; 48431Sigor@sysoev.ru nxt_port_t *app_port; 49431Sigor@sysoev.ru nxt_app_parse_ctx_t *ap; 50431Sigor@sysoev.ru nxt_msg_info_t msg_info; 51431Sigor@sysoev.ru nxt_req_app_link_t *ra; 52431Sigor@sysoev.ru 53431Sigor@sysoev.ru nxt_queue_link_t link; /* for nxt_conn_t.requests */ 54318Smax.romanov@nginx.com } nxt_req_conn_link_t; 55318Smax.romanov@nginx.com 56318Smax.romanov@nginx.com 57167Smax.romanov@nginx.com struct nxt_req_app_link_s { 58318Smax.romanov@nginx.com uint32_t stream; 59425Smax.romanov@nginx.com nxt_atomic_t use_count; 60167Smax.romanov@nginx.com nxt_port_t *app_port; 61167Smax.romanov@nginx.com nxt_port_t *reply_port; 62167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 63423Smax.romanov@nginx.com nxt_msg_info_t msg_info; 64167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 65167Smax.romanov@nginx.com 66427Smax.romanov@nginx.com nxt_nsec_t res_time; 67427Smax.romanov@nginx.com 68425Smax.romanov@nginx.com nxt_queue_link_t link_app_requests; /* for nxt_app_t.requests */ 69425Smax.romanov@nginx.com nxt_queue_link_t link_port_pending; /* for nxt_port_t.pending_requests */ 70427Smax.romanov@nginx.com nxt_queue_link_t link_app_pending; /* for nxt_app_t.pending */ 71167Smax.romanov@nginx.com 72167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 73167Smax.romanov@nginx.com nxt_work_t work; 74345Smax.romanov@nginx.com 75345Smax.romanov@nginx.com int err_code; 76345Smax.romanov@nginx.com const char *err_str; 77167Smax.romanov@nginx.com }; 78167Smax.romanov@nginx.com 79167Smax.romanov@nginx.com 80198Sigor@sysoev.ru typedef struct { 81198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 82198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 83198Sigor@sysoev.ru } nxt_socket_rpc_t; 84198Sigor@sysoev.ru 85198Sigor@sysoev.ru 86507Smax.romanov@nginx.com typedef struct { 87507Smax.romanov@nginx.com nxt_app_t *app; 88507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 89507Smax.romanov@nginx.com } nxt_app_rpc_t; 90507Smax.romanov@nginx.com 91507Smax.romanov@nginx.com 92427Smax.romanov@nginx.com struct nxt_port_select_state_s { 93427Smax.romanov@nginx.com nxt_app_t *app; 94427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 95427Smax.romanov@nginx.com 96427Smax.romanov@nginx.com nxt_port_t *failed_port; 97427Smax.romanov@nginx.com int failed_port_use_delta; 98427Smax.romanov@nginx.com 99507Smax.romanov@nginx.com uint8_t start_process; /* 1 bit */ 100427Smax.romanov@nginx.com nxt_req_app_link_t *shared_ra; 101427Smax.romanov@nginx.com nxt_port_t *port; 102427Smax.romanov@nginx.com }; 103427Smax.romanov@nginx.com 104427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t; 105427Smax.romanov@nginx.com 106662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 107662Smax.romanov@nginx.com nxt_port_t *controller_port); 108662Smax.romanov@nginx.com 109427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task, 110427Smax.romanov@nginx.com nxt_port_select_state_t *state); 111427Smax.romanov@nginx.com 112427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task, 113427Smax.romanov@nginx.com nxt_port_select_state_t *state); 114427Smax.romanov@nginx.com 115507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 116343Smax.romanov@nginx.com 117425Smax.romanov@nginx.com nxt_inline void 118425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra) 119425Smax.romanov@nginx.com { 120425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, 1); 121425Smax.romanov@nginx.com } 122425Smax.romanov@nginx.com 123425Smax.romanov@nginx.com nxt_inline void 124425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra) 125425Smax.romanov@nginx.com { 126538Svbart@nginx.com #if (NXT_DEBUG) 127425Smax.romanov@nginx.com int c; 128425Smax.romanov@nginx.com 129425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, -1); 130425Smax.romanov@nginx.com 131425Smax.romanov@nginx.com nxt_assert(c > 1); 132538Svbart@nginx.com #else 133538Svbart@nginx.com (void) nxt_atomic_fetch_add(&ra->use_count, -1); 134538Svbart@nginx.com #endif 135425Smax.romanov@nginx.com } 136425Smax.romanov@nginx.com 137425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i); 138425Smax.romanov@nginx.com 139139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 140198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 141198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 142139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 143139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 144139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 145139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 146193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 14753Sigor@sysoev.ru 148115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 149115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 150133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 151133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 152133Sigor@sysoev.ru nxt_str_t *name); 153198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 154198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 155198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 156198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 157198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 158198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 159507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 160507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 161507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 162507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 163507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 164507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 165359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 166359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 167359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 168359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 16953Sigor@sysoev.ru 17053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 17153Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 17253Sigor@sysoev.ru const nxt_event_interface_t *interface); 173115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 174115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 175115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 176115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 177115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 178115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 179154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 180154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 181154Sigor@sysoev.ru nxt_work_handler_t handler); 182313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 183313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 184139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 185139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 18653Sigor@sysoev.ru 18753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 18853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 18953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 19053Sigor@sysoev.ru nxt_event_engine_t *engine); 191343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 192133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 19353Sigor@sysoev.ru 194315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 195315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 196315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 197315Sigor@sysoev.ru nxt_work_t *jobs); 19853Sigor@sysoev.ru 19953Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 20053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 20153Sigor@sysoev.ru void *data); 20253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 20353Sigor@sysoev.ru void *data); 20453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 20553Sigor@sysoev.ru void *data); 206313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 207313Sigor@sysoev.ru void *data); 20853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 20953Sigor@sysoev.ru void *data); 21053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 21153Sigor@sysoev.ru void *data); 212359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 213359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 21453Sigor@sysoev.ru 215630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 216630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 217630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 218630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 219630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 220630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 221630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 222630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 223630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 224630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 225630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 226630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 227651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 228651Svbart@nginx.com void *data); 229631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 230631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 231631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 232631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 233630Svbart@nginx.com 234343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 235343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 236343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 237343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 238343Smax.romanov@nginx.com 239753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 240343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 241343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 242427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 243427Smax.romanov@nginx.com nxt_req_app_link_t *ra); 244141Smax.romanov@nginx.com 245425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 246343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 247743Smax.romanov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 248743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix); 249510Salexander.borisov@nginx.com 250318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 251507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 252507Smax.romanov@nginx.com void *data); 253507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 254507Smax.romanov@nginx.com void *data); 255753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 256507Smax.romanov@nginx.com void *data); 257753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 258431Sigor@sysoev.ru 259431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 260431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 261141Smax.romanov@nginx.com 262753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 263753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 264753Smax.romanov@nginx.com 265119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 26620Sigor@sysoev.ru 267743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 268743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 269743Smax.romanov@nginx.com 270743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 271743Smax.romanov@nginx.com &http_prefix, 272743Smax.romanov@nginx.com &http_prefix, 273743Smax.romanov@nginx.com &empty_prefix, 274743Smax.romanov@nginx.com &http_prefix, 275743Smax.romanov@nginx.com &http_prefix, 276216Sigor@sysoev.ru }; 277216Sigor@sysoev.ru 278216Sigor@sysoev.ru 279662Smax.romanov@nginx.com nxt_port_handlers_t nxt_router_process_port_handlers = { 280662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 281662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 282662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 283662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 284662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 285662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 286662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 287662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 288662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 289662Smax.romanov@nginx.com }; 290662Smax.romanov@nginx.com 291662Smax.romanov@nginx.com 29220Sigor@sysoev.ru nxt_int_t 293141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 29420Sigor@sysoev.ru { 295141Smax.romanov@nginx.com nxt_int_t ret; 296662Smax.romanov@nginx.com nxt_port_t *controller_port; 297141Smax.romanov@nginx.com nxt_router_t *router; 298141Smax.romanov@nginx.com nxt_runtime_t *rt; 299141Smax.romanov@nginx.com 300141Smax.romanov@nginx.com rt = task->thread->runtime; 30153Sigor@sysoev.ru 302*771Sigor@sysoev.ru #if (NXT_TLS) 303*771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 304*771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 305*771Sigor@sysoev.ru return NXT_ERROR; 306*771Sigor@sysoev.ru } 307*771Sigor@sysoev.ru 308*771Sigor@sysoev.ru ret = rt->tls->library_init(task); 309*771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 310*771Sigor@sysoev.ru return ret; 311*771Sigor@sysoev.ru } 312*771Sigor@sysoev.ru #endif 313*771Sigor@sysoev.ru 314431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 31588Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 31688Smax.romanov@nginx.com return ret; 31788Smax.romanov@nginx.com } 31888Smax.romanov@nginx.com 31953Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 32053Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 32153Sigor@sysoev.ru return NXT_ERROR; 32253Sigor@sysoev.ru } 32353Sigor@sysoev.ru 32453Sigor@sysoev.ru nxt_queue_init(&router->engines); 32553Sigor@sysoev.ru nxt_queue_init(&router->sockets); 326133Sigor@sysoev.ru nxt_queue_init(&router->apps); 32753Sigor@sysoev.ru 328119Smax.romanov@nginx.com nxt_router = router; 329119Smax.romanov@nginx.com 330662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 331662Smax.romanov@nginx.com if (controller_port != NULL) { 332662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 333662Smax.romanov@nginx.com } 334662Smax.romanov@nginx.com 335115Sigor@sysoev.ru return NXT_OK; 336115Sigor@sysoev.ru } 337115Sigor@sysoev.ru 338115Sigor@sysoev.ru 339343Smax.romanov@nginx.com static void 340662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 341662Smax.romanov@nginx.com { 342662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 343662Smax.romanov@nginx.com -1, 0, 0, NULL); 344662Smax.romanov@nginx.com } 345662Smax.romanov@nginx.com 346662Smax.romanov@nginx.com 347662Smax.romanov@nginx.com static void 348507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 349507Smax.romanov@nginx.com void *data) 350167Smax.romanov@nginx.com { 351343Smax.romanov@nginx.com size_t size; 352343Smax.romanov@nginx.com uint32_t stream; 353430Sigor@sysoev.ru nxt_mp_t *mp; 354648Svbart@nginx.com nxt_int_t ret; 355343Smax.romanov@nginx.com nxt_app_t *app; 356343Smax.romanov@nginx.com nxt_buf_t *b; 357343Smax.romanov@nginx.com nxt_port_t *main_port; 358343Smax.romanov@nginx.com nxt_runtime_t *rt; 359343Smax.romanov@nginx.com 360343Smax.romanov@nginx.com app = data; 361167Smax.romanov@nginx.com 362167Smax.romanov@nginx.com rt = task->thread->runtime; 363240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 364167Smax.romanov@nginx.com 365507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 366343Smax.romanov@nginx.com 367343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 368343Smax.romanov@nginx.com 369343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 370343Smax.romanov@nginx.com 371343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 372343Smax.romanov@nginx.com goto failed; 373167Smax.romanov@nginx.com } 374167Smax.romanov@nginx.com 375343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 376343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 377343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 378343Smax.romanov@nginx.com 379753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 380753Smax.romanov@nginx.com 381343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 382343Smax.romanov@nginx.com nxt_router_app_port_ready, 383343Smax.romanov@nginx.com nxt_router_app_port_error, 384753Smax.romanov@nginx.com -1, app->joint); 385343Smax.romanov@nginx.com 386343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 387753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 388753Smax.romanov@nginx.com 389343Smax.romanov@nginx.com goto failed; 390343Smax.romanov@nginx.com } 391343Smax.romanov@nginx.com 392648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 393648Svbart@nginx.com stream, port->id, b); 394648Svbart@nginx.com 395648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 396648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 397753Smax.romanov@nginx.com 398753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 399753Smax.romanov@nginx.com 400648Svbart@nginx.com goto failed; 401648Svbart@nginx.com } 402343Smax.romanov@nginx.com 403753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 404753Smax.romanov@nginx.com 405343Smax.romanov@nginx.com return; 406343Smax.romanov@nginx.com 407343Smax.romanov@nginx.com failed: 408343Smax.romanov@nginx.com 409648Svbart@nginx.com if (b != NULL) { 410648Svbart@nginx.com mp = b->data; 411648Svbart@nginx.com nxt_mp_free(mp, b); 412648Svbart@nginx.com nxt_mp_release(mp); 413648Svbart@nginx.com } 414648Svbart@nginx.com 415343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 416343Smax.romanov@nginx.com 417507Smax.romanov@nginx.com app->pending_processes--; 418343Smax.romanov@nginx.com 419343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 420343Smax.romanov@nginx.com 421343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 422167Smax.romanov@nginx.com } 423167Smax.romanov@nginx.com 424167Smax.romanov@nginx.com 425753Smax.romanov@nginx.com static void 426753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 427753Smax.romanov@nginx.com { 428753Smax.romanov@nginx.com app_joint->use_count += i; 429753Smax.romanov@nginx.com 430753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 431753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 432753Smax.romanov@nginx.com 433753Smax.romanov@nginx.com nxt_free(app_joint); 434753Smax.romanov@nginx.com } 435753Smax.romanov@nginx.com } 436753Smax.romanov@nginx.com 437753Smax.romanov@nginx.com 438343Smax.romanov@nginx.com static nxt_int_t 439507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 440141Smax.romanov@nginx.com { 441343Smax.romanov@nginx.com nxt_int_t res; 442343Smax.romanov@nginx.com nxt_port_t *router_port; 443343Smax.romanov@nginx.com nxt_runtime_t *rt; 444343Smax.romanov@nginx.com 445343Smax.romanov@nginx.com rt = task->thread->runtime; 446343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 447343Smax.romanov@nginx.com 448343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 449343Smax.romanov@nginx.com 450507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 451343Smax.romanov@nginx.com app); 452343Smax.romanov@nginx.com 453343Smax.romanov@nginx.com if (res == NXT_OK) { 454343Smax.romanov@nginx.com return res; 455318Smax.romanov@nginx.com } 456318Smax.romanov@nginx.com 457343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 458343Smax.romanov@nginx.com 459507Smax.romanov@nginx.com app->pending_processes--; 460343Smax.romanov@nginx.com 461343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 462343Smax.romanov@nginx.com 463343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 464343Smax.romanov@nginx.com 465343Smax.romanov@nginx.com return NXT_ERROR; 466318Smax.romanov@nginx.com } 467318Smax.romanov@nginx.com 468318Smax.romanov@nginx.com 469351Smax.romanov@nginx.com nxt_inline void 470351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 471351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 472167Smax.romanov@nginx.com { 473318Smax.romanov@nginx.com nxt_event_engine_t *engine; 474351Smax.romanov@nginx.com 475318Smax.romanov@nginx.com engine = task->thread->engine; 476167Smax.romanov@nginx.com 477167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 478167Smax.romanov@nginx.com 479318Smax.romanov@nginx.com ra->stream = rc->stream; 480425Smax.romanov@nginx.com ra->use_count = 1; 481167Smax.romanov@nginx.com ra->rc = rc; 482318Smax.romanov@nginx.com rc->ra = ra; 483318Smax.romanov@nginx.com ra->reply_port = engine->port; 484351Smax.romanov@nginx.com ra->ap = rc->ap; 485167Smax.romanov@nginx.com 486167Smax.romanov@nginx.com ra->work.handler = NULL; 487318Smax.romanov@nginx.com ra->work.task = &engine->task; 488167Smax.romanov@nginx.com ra->work.obj = ra; 489318Smax.romanov@nginx.com ra->work.data = engine; 490351Smax.romanov@nginx.com } 491351Smax.romanov@nginx.com 492351Smax.romanov@nginx.com 493351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 494351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 495351Smax.romanov@nginx.com { 496351Smax.romanov@nginx.com nxt_mp_t *mp; 497351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 498351Smax.romanov@nginx.com 499425Smax.romanov@nginx.com if (ra_src->mem_pool != NULL) { 500425Smax.romanov@nginx.com return ra_src; 501425Smax.romanov@nginx.com } 502425Smax.romanov@nginx.com 503351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 504351Smax.romanov@nginx.com 505430Sigor@sysoev.ru ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); 506351Smax.romanov@nginx.com 507351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 508351Smax.romanov@nginx.com 509351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 510351Smax.romanov@nginx.com ra_src->rc = NULL; 511351Smax.romanov@nginx.com 512351Smax.romanov@nginx.com return NULL; 513351Smax.romanov@nginx.com } 514351Smax.romanov@nginx.com 515430Sigor@sysoev.ru nxt_mp_retain(mp); 516430Sigor@sysoev.ru 517351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 518351Smax.romanov@nginx.com 519351Smax.romanov@nginx.com ra->mem_pool = mp; 520167Smax.romanov@nginx.com 521167Smax.romanov@nginx.com return ra; 522167Smax.romanov@nginx.com } 523167Smax.romanov@nginx.com 524167Smax.romanov@nginx.com 525423Smax.romanov@nginx.com nxt_inline nxt_bool_t 526423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 527423Smax.romanov@nginx.com uint32_t stream) 528423Smax.romanov@nginx.com { 529423Smax.romanov@nginx.com nxt_buf_t *b, *next; 530423Smax.romanov@nginx.com nxt_bool_t cancelled; 531423Smax.romanov@nginx.com 532423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 533423Smax.romanov@nginx.com return 0; 534423Smax.romanov@nginx.com } 535423Smax.romanov@nginx.com 536423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 537423Smax.romanov@nginx.com stream); 538423Smax.romanov@nginx.com 539423Smax.romanov@nginx.com if (cancelled) { 540423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 541423Smax.romanov@nginx.com } 542423Smax.romanov@nginx.com 543423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 544423Smax.romanov@nginx.com next = b->next; 545423Smax.romanov@nginx.com 546423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 547423Smax.romanov@nginx.com 548423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 549423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 550423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 551423Smax.romanov@nginx.com } 552423Smax.romanov@nginx.com } 553423Smax.romanov@nginx.com 554423Smax.romanov@nginx.com msg_info->buf = NULL; 555423Smax.romanov@nginx.com 556423Smax.romanov@nginx.com return cancelled; 557423Smax.romanov@nginx.com } 558423Smax.romanov@nginx.com 559423Smax.romanov@nginx.com 560167Smax.romanov@nginx.com static void 561425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra); 562425Smax.romanov@nginx.com 563425Smax.romanov@nginx.com 564425Smax.romanov@nginx.com static void 565425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data) 566167Smax.romanov@nginx.com { 567425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 568425Smax.romanov@nginx.com 569425Smax.romanov@nginx.com ra = obj; 570425Smax.romanov@nginx.com 571425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 572425Smax.romanov@nginx.com 573425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 574425Smax.romanov@nginx.com } 575425Smax.romanov@nginx.com 576425Smax.romanov@nginx.com 577425Smax.romanov@nginx.com static void 578425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra) 579425Smax.romanov@nginx.com { 580343Smax.romanov@nginx.com nxt_event_engine_t *engine; 581343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 582318Smax.romanov@nginx.com 583425Smax.romanov@nginx.com engine = ra->work.data; 584318Smax.romanov@nginx.com 585343Smax.romanov@nginx.com if (task->thread->engine != engine) { 586425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 587425Smax.romanov@nginx.com 588425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_update_peer_handler; 589318Smax.romanov@nginx.com ra->work.task = &engine->task; 590318Smax.romanov@nginx.com ra->work.next = NULL; 591318Smax.romanov@nginx.com 592425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post update peer to %p", 593318Smax.romanov@nginx.com ra->stream, engine); 594318Smax.romanov@nginx.com 595318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 596318Smax.romanov@nginx.com 597318Smax.romanov@nginx.com return; 598318Smax.romanov@nginx.com } 599318Smax.romanov@nginx.com 600425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD update peer", ra->stream); 601425Smax.romanov@nginx.com 602425Smax.romanov@nginx.com rc = ra->rc; 603425Smax.romanov@nginx.com 604425Smax.romanov@nginx.com if (rc != NULL && ra->app_port != NULL) { 605425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid); 606425Smax.romanov@nginx.com } 607425Smax.romanov@nginx.com 608425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 609425Smax.romanov@nginx.com } 610425Smax.romanov@nginx.com 611425Smax.romanov@nginx.com 612425Smax.romanov@nginx.com static void 613425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) 614425Smax.romanov@nginx.com { 615431Sigor@sysoev.ru nxt_mp_t *mp; 616431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 617425Smax.romanov@nginx.com 618425Smax.romanov@nginx.com nxt_assert(task->thread->engine == ra->work.data); 619425Smax.romanov@nginx.com nxt_assert(ra->use_count == 0); 620425Smax.romanov@nginx.com 621343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 622343Smax.romanov@nginx.com 623343Smax.romanov@nginx.com rc = ra->rc; 624343Smax.romanov@nginx.com 625343Smax.romanov@nginx.com if (rc != NULL) { 626423Smax.romanov@nginx.com if (nxt_slow_path(ra->err_code != 0)) { 627431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, ra->err_code); 628423Smax.romanov@nginx.com 629423Smax.romanov@nginx.com } else { 630423Smax.romanov@nginx.com rc->app_port = ra->app_port; 631423Smax.romanov@nginx.com rc->msg_info = ra->msg_info; 632423Smax.romanov@nginx.com 633425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 634431Sigor@sysoev.ru rc->ap->timer.handler = nxt_router_app_timeout; 635615Smax.romanov@nginx.com rc->ap->timer_data = rc; 636431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &rc->ap->timer, 637425Smax.romanov@nginx.com rc->app->timeout); 638425Smax.romanov@nginx.com } 639425Smax.romanov@nginx.com 640423Smax.romanov@nginx.com ra->app_port = NULL; 641423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 642423Smax.romanov@nginx.com } 643343Smax.romanov@nginx.com 644343Smax.romanov@nginx.com rc->ra = NULL; 645343Smax.romanov@nginx.com ra->rc = NULL; 646343Smax.romanov@nginx.com } 647343Smax.romanov@nginx.com 648343Smax.romanov@nginx.com if (ra->app_port != NULL) { 649343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 650343Smax.romanov@nginx.com 651343Smax.romanov@nginx.com ra->app_port = NULL; 652167Smax.romanov@nginx.com } 653167Smax.romanov@nginx.com 654423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 655423Smax.romanov@nginx.com 656430Sigor@sysoev.ru mp = ra->mem_pool; 657430Sigor@sysoev.ru 658430Sigor@sysoev.ru if (mp != NULL) { 659430Sigor@sysoev.ru nxt_mp_free(mp, ra); 660430Sigor@sysoev.ru nxt_mp_release(mp); 661351Smax.romanov@nginx.com } 662167Smax.romanov@nginx.com } 663167Smax.romanov@nginx.com 664167Smax.romanov@nginx.com 665425Smax.romanov@nginx.com static void 666425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 667425Smax.romanov@nginx.com { 668425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 669425Smax.romanov@nginx.com 670425Smax.romanov@nginx.com ra = obj; 671425Smax.romanov@nginx.com 672425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 673425Smax.romanov@nginx.com 674425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 675425Smax.romanov@nginx.com 676425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 677425Smax.romanov@nginx.com } 678425Smax.romanov@nginx.com 679425Smax.romanov@nginx.com 680425Smax.romanov@nginx.com static void 681425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 682425Smax.romanov@nginx.com { 683425Smax.romanov@nginx.com int c; 684425Smax.romanov@nginx.com nxt_event_engine_t *engine; 685425Smax.romanov@nginx.com 686425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 687425Smax.romanov@nginx.com 688425Smax.romanov@nginx.com if (i < 0 && c == -i) { 689425Smax.romanov@nginx.com engine = ra->work.data; 690425Smax.romanov@nginx.com 691425Smax.romanov@nginx.com if (task->thread->engine == engine) { 692425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 693425Smax.romanov@nginx.com 694425Smax.romanov@nginx.com return; 695425Smax.romanov@nginx.com } 696425Smax.romanov@nginx.com 697425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 698425Smax.romanov@nginx.com 699425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 700425Smax.romanov@nginx.com ra->work.task = &engine->task; 701425Smax.romanov@nginx.com ra->work.next = NULL; 702425Smax.romanov@nginx.com 703425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 704425Smax.romanov@nginx.com ra->stream, engine); 705425Smax.romanov@nginx.com 706425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 707425Smax.romanov@nginx.com } 708425Smax.romanov@nginx.com } 709425Smax.romanov@nginx.com 710425Smax.romanov@nginx.com 711423Smax.romanov@nginx.com nxt_inline void 712521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str) 713345Smax.romanov@nginx.com { 714423Smax.romanov@nginx.com ra->app_port = NULL; 715423Smax.romanov@nginx.com ra->err_code = code; 716423Smax.romanov@nginx.com ra->err_str = str; 717345Smax.romanov@nginx.com } 718345Smax.romanov@nginx.com 719345Smax.romanov@nginx.com 720427Smax.romanov@nginx.com nxt_inline void 721427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 722427Smax.romanov@nginx.com { 723427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 724427Smax.romanov@nginx.com &ra->link_port_pending); 725427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 726427Smax.romanov@nginx.com 727427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 728427Smax.romanov@nginx.com 729427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 730427Smax.romanov@nginx.com 731427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 732427Smax.romanov@nginx.com } 733427Smax.romanov@nginx.com 734427Smax.romanov@nginx.com 735425Smax.romanov@nginx.com nxt_inline nxt_bool_t 736425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 737425Smax.romanov@nginx.com { 738425Smax.romanov@nginx.com if (lnk->next != NULL) { 739425Smax.romanov@nginx.com nxt_queue_remove(lnk); 740425Smax.romanov@nginx.com 741425Smax.romanov@nginx.com lnk->next = NULL; 742425Smax.romanov@nginx.com 743425Smax.romanov@nginx.com return 1; 744425Smax.romanov@nginx.com } 745425Smax.romanov@nginx.com 746425Smax.romanov@nginx.com return 0; 747425Smax.romanov@nginx.com } 748425Smax.romanov@nginx.com 749425Smax.romanov@nginx.com 750343Smax.romanov@nginx.com nxt_inline void 751343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 752343Smax.romanov@nginx.com { 753425Smax.romanov@nginx.com int ra_use_delta; 754343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 755343Smax.romanov@nginx.com 756343Smax.romanov@nginx.com if (rc->app_port != NULL) { 757343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 758343Smax.romanov@nginx.com 759343Smax.romanov@nginx.com rc->app_port = NULL; 760343Smax.romanov@nginx.com } 761343Smax.romanov@nginx.com 762423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 763423Smax.romanov@nginx.com 764343Smax.romanov@nginx.com ra = rc->ra; 765343Smax.romanov@nginx.com 766343Smax.romanov@nginx.com if (ra != NULL) { 767343Smax.romanov@nginx.com rc->ra = NULL; 768343Smax.romanov@nginx.com ra->rc = NULL; 769343Smax.romanov@nginx.com 770425Smax.romanov@nginx.com ra_use_delta = 0; 771425Smax.romanov@nginx.com 772343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 773343Smax.romanov@nginx.com 774425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 775427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 776427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 777425Smax.romanov@nginx.com { 778425Smax.romanov@nginx.com ra = NULL; 779343Smax.romanov@nginx.com 780343Smax.romanov@nginx.com } else { 781425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 782425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 783427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 784343Smax.romanov@nginx.com } 785343Smax.romanov@nginx.com 786343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 787425Smax.romanov@nginx.com 788425Smax.romanov@nginx.com if (ra != NULL) { 789425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 790425Smax.romanov@nginx.com } 791343Smax.romanov@nginx.com } 792343Smax.romanov@nginx.com 793343Smax.romanov@nginx.com if (rc->app != NULL) { 794343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 795343Smax.romanov@nginx.com 796343Smax.romanov@nginx.com rc->app = NULL; 797343Smax.romanov@nginx.com } 798343Smax.romanov@nginx.com 799346Smax.romanov@nginx.com if (rc->ap != NULL) { 800615Smax.romanov@nginx.com rc->ap->timer_data = NULL; 801615Smax.romanov@nginx.com 802346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 803346Smax.romanov@nginx.com 804346Smax.romanov@nginx.com rc->ap = NULL; 805346Smax.romanov@nginx.com } 806343Smax.romanov@nginx.com } 807343Smax.romanov@nginx.com 808343Smax.romanov@nginx.com 809141Smax.romanov@nginx.com void 810141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 811141Smax.romanov@nginx.com { 812141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 813141Smax.romanov@nginx.com 814670Smax.romanov@nginx.com if (msg->u.new_port != NULL 815670Smax.romanov@nginx.com && msg->u.new_port->type == NXT_PROCESS_CONTROLLER) 816670Smax.romanov@nginx.com { 817662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 818662Smax.romanov@nginx.com } 819662Smax.romanov@nginx.com 820192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 821141Smax.romanov@nginx.com return; 822141Smax.romanov@nginx.com } 823141Smax.romanov@nginx.com 824426Smax.romanov@nginx.com if (msg->u.new_port == NULL 825426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 826347Smax.romanov@nginx.com { 827192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 828141Smax.romanov@nginx.com } 829192Smax.romanov@nginx.com 830192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 831141Smax.romanov@nginx.com } 832141Smax.romanov@nginx.com 833141Smax.romanov@nginx.com 834139Sigor@sysoev.ru void 835139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 836115Sigor@sysoev.ru { 837198Sigor@sysoev.ru nxt_int_t ret; 838139Sigor@sysoev.ru nxt_buf_t *b; 839139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 840139Sigor@sysoev.ru 841139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 842139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 843139Sigor@sysoev.ru return; 84453Sigor@sysoev.ru } 84553Sigor@sysoev.ru 846494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 847423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 848493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 849423Smax.romanov@nginx.com 850591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 851139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 852139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 853198Sigor@sysoev.ru msg->port_msg.pid, 854198Sigor@sysoev.ru msg->port_msg.reply_port); 855198Sigor@sysoev.ru 856591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 857591Sigor@sysoev.ru msg->buf, msg->size); 858551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 859551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 860551Smax.romanov@nginx.com 861551Smax.romanov@nginx.com return; 862551Smax.romanov@nginx.com } 863551Smax.romanov@nginx.com 864198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 865198Sigor@sysoev.ru 866198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 867198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 868198Sigor@sysoev.ru 869198Sigor@sysoev.ru } else { 870198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 871139Sigor@sysoev.ru } 87253Sigor@sysoev.ru } 87353Sigor@sysoev.ru 87453Sigor@sysoev.ru 875347Smax.romanov@nginx.com static void 876507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 877507Smax.romanov@nginx.com void *data) 878347Smax.romanov@nginx.com { 879347Smax.romanov@nginx.com union { 880347Smax.romanov@nginx.com nxt_pid_t removed_pid; 881347Smax.romanov@nginx.com void *data; 882347Smax.romanov@nginx.com } u; 883347Smax.romanov@nginx.com 884347Smax.romanov@nginx.com u.data = data; 885347Smax.romanov@nginx.com 886347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 887347Smax.romanov@nginx.com } 888347Smax.romanov@nginx.com 889347Smax.romanov@nginx.com 890192Smax.romanov@nginx.com void 891192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 892192Smax.romanov@nginx.com { 893347Smax.romanov@nginx.com nxt_event_engine_t *engine; 894318Smax.romanov@nginx.com 895192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 896192Smax.romanov@nginx.com 897192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 898192Smax.romanov@nginx.com return; 899192Smax.romanov@nginx.com } 900192Smax.romanov@nginx.com 901318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 902318Smax.romanov@nginx.com { 903507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 904347Smax.romanov@nginx.com msg->u.data); 905318Smax.romanov@nginx.com } 906318Smax.romanov@nginx.com nxt_queue_loop; 907318Smax.romanov@nginx.com 908192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 909192Smax.romanov@nginx.com 910192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 911192Smax.romanov@nginx.com } 912192Smax.romanov@nginx.com 913192Smax.romanov@nginx.com 91453Sigor@sysoev.ru static nxt_router_temp_conf_t * 915139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 91653Sigor@sysoev.ru { 91765Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 91853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 91953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 92053Sigor@sysoev.ru 92165Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 92253Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 92353Sigor@sysoev.ru return NULL; 92453Sigor@sysoev.ru } 92553Sigor@sysoev.ru 92665Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 92753Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 92853Sigor@sysoev.ru goto fail; 92953Sigor@sysoev.ru } 93053Sigor@sysoev.ru 93153Sigor@sysoev.ru rtcf->mem_pool = mp; 93253Sigor@sysoev.ru 93365Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 93453Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 93553Sigor@sysoev.ru goto fail; 93653Sigor@sysoev.ru } 93753Sigor@sysoev.ru 93865Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 93953Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 94053Sigor@sysoev.ru goto temp_fail; 94153Sigor@sysoev.ru } 94253Sigor@sysoev.ru 94353Sigor@sysoev.ru tmcf->mem_pool = tmp; 944591Sigor@sysoev.ru tmcf->router_conf = rtcf; 945139Sigor@sysoev.ru tmcf->count = 1; 946139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 94753Sigor@sysoev.ru 94853Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 94953Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 95053Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 95153Sigor@sysoev.ru goto temp_fail; 95253Sigor@sysoev.ru } 95353Sigor@sysoev.ru 95453Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 95553Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 95653Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 95753Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 95853Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 959416Smax.romanov@nginx.com 960133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 961133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 96253Sigor@sysoev.ru 96353Sigor@sysoev.ru return tmcf; 96453Sigor@sysoev.ru 96553Sigor@sysoev.ru temp_fail: 96653Sigor@sysoev.ru 96765Sigor@sysoev.ru nxt_mp_destroy(tmp); 96853Sigor@sysoev.ru 96953Sigor@sysoev.ru fail: 97053Sigor@sysoev.ru 97165Sigor@sysoev.ru nxt_mp_destroy(mp); 97253Sigor@sysoev.ru 97353Sigor@sysoev.ru return NULL; 97453Sigor@sysoev.ru } 97553Sigor@sysoev.ru 97653Sigor@sysoev.ru 977507Smax.romanov@nginx.com nxt_inline nxt_bool_t 978507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 979507Smax.romanov@nginx.com { 980507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 981507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 982507Smax.romanov@nginx.com } 983507Smax.romanov@nginx.com 984507Smax.romanov@nginx.com 985507Smax.romanov@nginx.com nxt_inline nxt_bool_t 986507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 987507Smax.romanov@nginx.com { 988507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 989507Smax.romanov@nginx.com < app->spare_processes; 990507Smax.romanov@nginx.com } 991507Smax.romanov@nginx.com 992507Smax.romanov@nginx.com 993198Sigor@sysoev.ru static void 994198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 995139Sigor@sysoev.ru { 996139Sigor@sysoev.ru nxt_int_t ret; 997507Smax.romanov@nginx.com nxt_app_t *app; 998139Sigor@sysoev.ru nxt_router_t *router; 999139Sigor@sysoev.ru nxt_runtime_t *rt; 1000198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1001198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1002630Svbart@nginx.com nxt_router_conf_t *rtcf; 1003198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1004139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1005139Sigor@sysoev.ru 1006198Sigor@sysoev.ru tmcf = obj; 1007198Sigor@sysoev.ru 1008198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 1009198Sigor@sysoev.ru 1010198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 1011198Sigor@sysoev.ru nxt_queue_remove(qlk); 1012198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 1013198Sigor@sysoev.ru 1014198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1015198Sigor@sysoev.ru 1016198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1017198Sigor@sysoev.ru 1018198Sigor@sysoev.ru return; 1019139Sigor@sysoev.ru } 1020139Sigor@sysoev.ru 1021507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1022507Smax.romanov@nginx.com 1023507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1024507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1025507Smax.romanov@nginx.com return; 1026507Smax.romanov@nginx.com } 1027507Smax.romanov@nginx.com 1028507Smax.romanov@nginx.com } nxt_queue_loop; 1029507Smax.romanov@nginx.com 1030630Svbart@nginx.com rtcf = tmcf->router_conf; 1031630Svbart@nginx.com 1032630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1033630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1034630Svbart@nginx.com return; 1035630Svbart@nginx.com } 1036630Svbart@nginx.com 1037139Sigor@sysoev.ru rt = task->thread->runtime; 1038139Sigor@sysoev.ru 1039139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1040139Sigor@sysoev.ru 1041630Svbart@nginx.com router = rtcf->router; 1042198Sigor@sysoev.ru 1043139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1044139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1045198Sigor@sysoev.ru goto fail; 1046139Sigor@sysoev.ru } 1047139Sigor@sysoev.ru 1048139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1049139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1050198Sigor@sysoev.ru goto fail; 1051139Sigor@sysoev.ru } 1052139Sigor@sysoev.ru 1053343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1054139Sigor@sysoev.ru 1055315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1056139Sigor@sysoev.ru 1057139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 1058139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 1059139Sigor@sysoev.ru 1060630Svbart@nginx.com router->access_log = rtcf->access_log; 1061630Svbart@nginx.com 1062198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1063198Sigor@sysoev.ru 1064198Sigor@sysoev.ru return; 1065198Sigor@sysoev.ru 1066198Sigor@sysoev.ru fail: 1067198Sigor@sysoev.ru 1068198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1069198Sigor@sysoev.ru 1070198Sigor@sysoev.ru return; 1071139Sigor@sysoev.ru } 1072139Sigor@sysoev.ru 1073139Sigor@sysoev.ru 1074139Sigor@sysoev.ru static void 1075139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1076139Sigor@sysoev.ru { 1077153Sigor@sysoev.ru nxt_joint_job_t *job; 1078153Sigor@sysoev.ru 1079153Sigor@sysoev.ru job = obj; 1080153Sigor@sysoev.ru 1081198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1082139Sigor@sysoev.ru } 1083139Sigor@sysoev.ru 1084139Sigor@sysoev.ru 1085139Sigor@sysoev.ru static void 1086198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1087139Sigor@sysoev.ru { 1088139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 1089139Sigor@sysoev.ru 1090139Sigor@sysoev.ru if (--tmcf->count == 0) { 1091193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 1092139Sigor@sysoev.ru } 1093139Sigor@sysoev.ru } 1094139Sigor@sysoev.ru 1095139Sigor@sysoev.ru 1096139Sigor@sysoev.ru static void 1097139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1098139Sigor@sysoev.ru { 1099507Smax.romanov@nginx.com nxt_app_t *app; 1100568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1101148Sigor@sysoev.ru nxt_socket_t s; 1102149Sigor@sysoev.ru nxt_router_t *router; 1103148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1104148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1105630Svbart@nginx.com nxt_router_conf_t *rtcf; 1106148Sigor@sysoev.ru 1107564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1108198Sigor@sysoev.ru 1109148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1110148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1111148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1112148Sigor@sysoev.ru { 1113148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1114359Sigor@sysoev.ru s = skcf->listen->socket; 1115148Sigor@sysoev.ru 1116148Sigor@sysoev.ru if (s != -1) { 1117148Sigor@sysoev.ru nxt_socket_close(task, s); 1118148Sigor@sysoev.ru } 1119148Sigor@sysoev.ru 1120359Sigor@sysoev.ru nxt_free(skcf->listen); 1121148Sigor@sysoev.ru } 1122148Sigor@sysoev.ru 1123568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1124568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1125568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1126568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1127568Smax.romanov@nginx.com 1128568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1129568Smax.romanov@nginx.com 1130568Smax.romanov@nginx.com if (skcf->application != NULL) { 1131568Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, -1); 1132568Smax.romanov@nginx.com skcf->application = NULL; 1133568Smax.romanov@nginx.com } 1134568Smax.romanov@nginx.com 1135568Smax.romanov@nginx.com } nxt_queue_loop; 1136568Smax.romanov@nginx.com 1137507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1138507Smax.romanov@nginx.com 1139753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1140507Smax.romanov@nginx.com 1141507Smax.romanov@nginx.com } nxt_queue_loop; 1142507Smax.romanov@nginx.com 1143630Svbart@nginx.com rtcf = tmcf->router_conf; 1144630Svbart@nginx.com router = rtcf->router; 1145149Sigor@sysoev.ru 1146149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1147149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1148149Sigor@sysoev.ru 1149416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1150416Smax.romanov@nginx.com 1151148Sigor@sysoev.ru // TODO: new engines and threads 1152148Sigor@sysoev.ru 1153630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1154630Svbart@nginx.com 1155630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1156139Sigor@sysoev.ru 1157193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1158139Sigor@sysoev.ru } 1159139Sigor@sysoev.ru 1160139Sigor@sysoev.ru 1161139Sigor@sysoev.ru static void 1162139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1163193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1164139Sigor@sysoev.ru { 1165193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1166139Sigor@sysoev.ru } 1167139Sigor@sysoev.ru 1168139Sigor@sysoev.ru 1169115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1170115Sigor@sysoev.ru { 1171133Sigor@sysoev.ru nxt_string("listeners_threads"), 1172115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1173115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1174115Sigor@sysoev.ru }, 1175115Sigor@sysoev.ru }; 1176115Sigor@sysoev.ru 1177115Sigor@sysoev.ru 1178133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1179115Sigor@sysoev.ru { 1180133Sigor@sysoev.ru nxt_string("type"), 1181115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1182133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1183115Sigor@sysoev.ru }, 1184115Sigor@sysoev.ru 1185115Sigor@sysoev.ru { 1186507Smax.romanov@nginx.com nxt_string("limits"), 1187507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1188507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1189133Sigor@sysoev.ru }, 1190318Smax.romanov@nginx.com 1191318Smax.romanov@nginx.com { 1192507Smax.romanov@nginx.com nxt_string("processes"), 1193507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1194507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1195507Smax.romanov@nginx.com }, 1196507Smax.romanov@nginx.com 1197507Smax.romanov@nginx.com { 1198507Smax.romanov@nginx.com nxt_string("processes"), 1199318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1200507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1201318Smax.romanov@nginx.com }, 1202318Smax.romanov@nginx.com }; 1203318Smax.romanov@nginx.com 1204318Smax.romanov@nginx.com 1205318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1206318Smax.romanov@nginx.com { 1207318Smax.romanov@nginx.com nxt_string("timeout"), 1208318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1209318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1210318Smax.romanov@nginx.com }, 1211318Smax.romanov@nginx.com 1212318Smax.romanov@nginx.com { 1213427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1214427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1215427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1216427Smax.romanov@nginx.com }, 1217427Smax.romanov@nginx.com 1218427Smax.romanov@nginx.com { 1219318Smax.romanov@nginx.com nxt_string("requests"), 1220318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1221318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1222318Smax.romanov@nginx.com }, 1223133Sigor@sysoev.ru }; 1224133Sigor@sysoev.ru 1225133Sigor@sysoev.ru 1226507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1227507Smax.romanov@nginx.com { 1228507Smax.romanov@nginx.com nxt_string("spare"), 1229507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1230507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1231507Smax.romanov@nginx.com }, 1232507Smax.romanov@nginx.com 1233507Smax.romanov@nginx.com { 1234507Smax.romanov@nginx.com nxt_string("max"), 1235507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1236507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1237507Smax.romanov@nginx.com }, 1238507Smax.romanov@nginx.com 1239507Smax.romanov@nginx.com { 1240507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1241507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1242507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1243507Smax.romanov@nginx.com }, 1244507Smax.romanov@nginx.com }; 1245507Smax.romanov@nginx.com 1246507Smax.romanov@nginx.com 1247133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1248133Sigor@sysoev.ru { 1249133Sigor@sysoev.ru nxt_string("application"), 1250133Sigor@sysoev.ru NXT_CONF_MAP_STR, 1251133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1252115Sigor@sysoev.ru }, 1253115Sigor@sysoev.ru }; 1254115Sigor@sysoev.ru 1255115Sigor@sysoev.ru 1256115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1257115Sigor@sysoev.ru { 1258115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1259115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1260115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1261115Sigor@sysoev.ru }, 1262115Sigor@sysoev.ru 1263115Sigor@sysoev.ru { 1264115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1265115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1266115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1267115Sigor@sysoev.ru }, 1268115Sigor@sysoev.ru 1269115Sigor@sysoev.ru { 1270206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1271206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1272206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1273206Smax.romanov@nginx.com }, 1274206Smax.romanov@nginx.com 1275206Smax.romanov@nginx.com { 1276206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1277206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1278206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1279206Smax.romanov@nginx.com }, 1280206Smax.romanov@nginx.com 1281206Smax.romanov@nginx.com { 1282206Smax.romanov@nginx.com nxt_string("max_body_size"), 1283206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1284206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1285206Smax.romanov@nginx.com }, 1286206Smax.romanov@nginx.com 1287206Smax.romanov@nginx.com { 1288431Sigor@sysoev.ru nxt_string("idle_timeout"), 1289431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1290431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1291431Sigor@sysoev.ru }, 1292431Sigor@sysoev.ru 1293431Sigor@sysoev.ru { 1294115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1295115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1296115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1297115Sigor@sysoev.ru }, 1298206Smax.romanov@nginx.com 1299206Smax.romanov@nginx.com { 1300206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1301206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1302206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1303206Smax.romanov@nginx.com }, 1304431Sigor@sysoev.ru 1305431Sigor@sysoev.ru { 1306431Sigor@sysoev.ru nxt_string("send_timeout"), 1307431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1308431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1309431Sigor@sysoev.ru }, 1310115Sigor@sysoev.ru }; 1311115Sigor@sysoev.ru 1312115Sigor@sysoev.ru 131353Sigor@sysoev.ru static nxt_int_t 1314115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1315115Sigor@sysoev.ru u_char *start, u_char *end) 131653Sigor@sysoev.ru { 1317133Sigor@sysoev.ru u_char *p; 1318133Sigor@sysoev.ru size_t size; 1319115Sigor@sysoev.ru nxt_mp_t *mp; 1320115Sigor@sysoev.ru uint32_t next; 1321115Sigor@sysoev.ru nxt_int_t ret; 1322630Svbart@nginx.com nxt_str_t name, path; 1323133Sigor@sysoev.ru nxt_app_t *app, *prev; 1324359Sigor@sysoev.ru nxt_router_t *router; 1325753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 1326630Svbart@nginx.com nxt_conf_value_t *conf, *http, *value; 1327133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1328133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1329115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1330507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1331216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1332133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1333630Svbart@nginx.com nxt_router_access_log_t *access_log; 1334115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1335115Sigor@sysoev.ru 1336716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1337133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1338115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1339630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1340115Sigor@sysoev.ru 1341208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1342115Sigor@sysoev.ru if (conf == NULL) { 1343564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1344115Sigor@sysoev.ru return NXT_ERROR; 1345115Sigor@sysoev.ru } 1346115Sigor@sysoev.ru 1347591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1348213Svbart@nginx.com 1349213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1350591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1351115Sigor@sysoev.ru if (ret != NXT_OK) { 1352564Svbart@nginx.com nxt_alert(task, "root map error"); 1353115Sigor@sysoev.ru return NXT_ERROR; 1354115Sigor@sysoev.ru } 1355115Sigor@sysoev.ru 1356591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1357591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1358117Sigor@sysoev.ru } 1359117Sigor@sysoev.ru 1360133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1361133Sigor@sysoev.ru if (applications == NULL) { 1362564Svbart@nginx.com nxt_alert(task, "no \"applications\" block"); 1363115Sigor@sysoev.ru return NXT_ERROR; 1364115Sigor@sysoev.ru } 1365115Sigor@sysoev.ru 1366591Sigor@sysoev.ru router = tmcf->router_conf->router; 1367359Sigor@sysoev.ru 1368133Sigor@sysoev.ru next = 0; 1369133Sigor@sysoev.ru 1370133Sigor@sysoev.ru for ( ;; ) { 1371133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1372133Sigor@sysoev.ru if (application == NULL) { 1373133Sigor@sysoev.ru break; 1374133Sigor@sysoev.ru } 1375133Sigor@sysoev.ru 1376133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1377133Sigor@sysoev.ru 1378144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1379144Smax.romanov@nginx.com 1380144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1381133Sigor@sysoev.ru if (app == NULL) { 1382133Sigor@sysoev.ru goto fail; 1383133Sigor@sysoev.ru } 1384133Sigor@sysoev.ru 1385144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1386144Smax.romanov@nginx.com 1387144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1388144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1389133Sigor@sysoev.ru 1390133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1391133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1392133Sigor@sysoev.ru 1393144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1394144Smax.romanov@nginx.com 1395133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1396133Sigor@sysoev.ru 1397359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1398133Sigor@sysoev.ru 1399133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1400133Sigor@sysoev.ru nxt_free(app); 1401133Sigor@sysoev.ru 1402133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1403133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1404133Sigor@sysoev.ru continue; 1405133Sigor@sysoev.ru } 1406133Sigor@sysoev.ru 1407507Smax.romanov@nginx.com apcf.processes = 1; 1408507Smax.romanov@nginx.com apcf.max_processes = 1; 1409537Svbart@nginx.com apcf.spare_processes = 0; 1410318Smax.romanov@nginx.com apcf.timeout = 0; 1411427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1412507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1413318Smax.romanov@nginx.com apcf.requests = 0; 1414318Smax.romanov@nginx.com apcf.limits_value = NULL; 1415507Smax.romanov@nginx.com apcf.processes_value = NULL; 1416263Smax.romanov@nginx.com 1417753Smax.romanov@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 1418753Smax.romanov@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1419753Smax.romanov@nginx.com goto app_fail; 1420753Smax.romanov@nginx.com } 1421753Smax.romanov@nginx.com 1422753Smax.romanov@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 1423753Smax.romanov@nginx.com 1424213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1425136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1426133Sigor@sysoev.ru if (ret != NXT_OK) { 1427564Svbart@nginx.com nxt_alert(task, "application map error"); 1428133Sigor@sysoev.ru goto app_fail; 1429133Sigor@sysoev.ru } 1430115Sigor@sysoev.ru 1431318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1432318Smax.romanov@nginx.com 1433318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1434564Svbart@nginx.com nxt_alert(task, "application limits is not object"); 1435318Smax.romanov@nginx.com goto app_fail; 1436318Smax.romanov@nginx.com } 1437318Smax.romanov@nginx.com 1438318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1439318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1440318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1441318Smax.romanov@nginx.com &apcf); 1442318Smax.romanov@nginx.com if (ret != NXT_OK) { 1443564Svbart@nginx.com nxt_alert(task, "application limits map error"); 1444318Smax.romanov@nginx.com goto app_fail; 1445318Smax.romanov@nginx.com } 1446318Smax.romanov@nginx.com } 1447318Smax.romanov@nginx.com 1448507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1449507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1450507Smax.romanov@nginx.com { 1451507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1452507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1453507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1454507Smax.romanov@nginx.com &apcf); 1455507Smax.romanov@nginx.com if (ret != NXT_OK) { 1456564Svbart@nginx.com nxt_alert(task, "application processes map error"); 1457507Smax.romanov@nginx.com goto app_fail; 1458507Smax.romanov@nginx.com } 1459507Smax.romanov@nginx.com 1460507Smax.romanov@nginx.com } else { 1461507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1462507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1463507Smax.romanov@nginx.com } 1464507Smax.romanov@nginx.com 1465133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1466507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1467507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1468507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1469318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1470133Sigor@sysoev.ru 1471216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1472216Sigor@sysoev.ru 1473216Sigor@sysoev.ru if (lang == NULL) { 1474564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1475141Smax.romanov@nginx.com goto app_fail; 1476141Smax.romanov@nginx.com } 1477141Smax.romanov@nginx.com 1478216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1479216Sigor@sysoev.ru 1480133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1481133Sigor@sysoev.ru if (ret != NXT_OK) { 1482133Sigor@sysoev.ru goto app_fail; 1483133Sigor@sysoev.ru } 1484133Sigor@sysoev.ru 1485141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1486507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1487507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1488141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1489427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1490141Smax.romanov@nginx.com 1491144Smax.romanov@nginx.com app->name.length = name.length; 1492144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1493144Smax.romanov@nginx.com 1494356Svbart@nginx.com app->type = lang->type; 1495507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1496507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1497507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1498507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1499318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1500427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1501507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1502343Smax.romanov@nginx.com app->max_pending_responses = 2; 1503428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1504133Sigor@sysoev.ru 1505507Smax.romanov@nginx.com engine = task->thread->engine; 1506507Smax.romanov@nginx.com 1507507Smax.romanov@nginx.com app->engine = engine; 1508507Smax.romanov@nginx.com 1509507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1510507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1511507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1512507Smax.romanov@nginx.com 1513133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1514343Smax.romanov@nginx.com 1515343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1516753Smax.romanov@nginx.com 1517753Smax.romanov@nginx.com app->joint = app_joint; 1518753Smax.romanov@nginx.com 1519753Smax.romanov@nginx.com app_joint->use_count = 1; 1520753Smax.romanov@nginx.com app_joint->app = app; 1521753Smax.romanov@nginx.com 1522753Smax.romanov@nginx.com app_joint->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION; 1523753Smax.romanov@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 1524753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 1525753Smax.romanov@nginx.com app_joint->idle_timer.task = &engine->task; 1526753Smax.romanov@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 1527753Smax.romanov@nginx.com 1528753Smax.romanov@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 1529753Smax.romanov@nginx.com app_joint->free_app_work.task = &engine->task; 1530753Smax.romanov@nginx.com app_joint->free_app_work.obj = app_joint; 1531133Sigor@sysoev.ru } 1532133Sigor@sysoev.ru 1533133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1534133Sigor@sysoev.ru #if 0 1535133Sigor@sysoev.ru if (http == NULL) { 1536564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1537133Sigor@sysoev.ru return NXT_ERROR; 1538133Sigor@sysoev.ru } 1539133Sigor@sysoev.ru #endif 1540133Sigor@sysoev.ru 1541133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1542115Sigor@sysoev.ru if (listeners == NULL) { 1543564Svbart@nginx.com nxt_alert(task, "no \"listeners\" block"); 1544115Sigor@sysoev.ru return NXT_ERROR; 1545115Sigor@sysoev.ru } 154653Sigor@sysoev.ru 1547133Sigor@sysoev.ru next = 0; 154853Sigor@sysoev.ru 1549115Sigor@sysoev.ru for ( ;; ) { 1550115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1551115Sigor@sysoev.ru if (listener == NULL) { 1552115Sigor@sysoev.ru break; 1553115Sigor@sysoev.ru } 155453Sigor@sysoev.ru 1555359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1556115Sigor@sysoev.ru if (skcf == NULL) { 1557133Sigor@sysoev.ru goto fail; 1558115Sigor@sysoev.ru } 155953Sigor@sysoev.ru 1560770Smax.romanov@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 1561770Smax.romanov@nginx.com 1562213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1563136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1564115Sigor@sysoev.ru if (ret != NXT_OK) { 1565564Svbart@nginx.com nxt_alert(task, "listener map error"); 1566133Sigor@sysoev.ru goto fail; 1567115Sigor@sysoev.ru } 156853Sigor@sysoev.ru 1569133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1570133Sigor@sysoev.ru 1571133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1572133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1573133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1574206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1575206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1576715Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 1577715Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 1578715Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 1579715Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 1580715Svbart@nginx.com skcf->send_timeout = 30 * 1000; 158153Sigor@sysoev.ru 1582133Sigor@sysoev.ru if (http != NULL) { 1583213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1584136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1585133Sigor@sysoev.ru if (ret != NXT_OK) { 1586564Svbart@nginx.com nxt_alert(task, "http map error"); 1587133Sigor@sysoev.ru goto fail; 1588133Sigor@sysoev.ru } 1589115Sigor@sysoev.ru } 1590115Sigor@sysoev.ru 1591431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1592591Sigor@sysoev.ru skcf->router_conf = tmcf->router_conf; 1593160Sigor@sysoev.ru skcf->router_conf->count++; 1594770Smax.romanov@nginx.com 1595770Smax.romanov@nginx.com if (lscf.application.length > 0) { 1596770Smax.romanov@nginx.com skcf->application = nxt_router_listener_application(tmcf, 1597133Sigor@sysoev.ru &lscf.application); 1598770Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, 1); 1599770Smax.romanov@nginx.com } 1600115Sigor@sysoev.ru } 160153Sigor@sysoev.ru 1602630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1603630Svbart@nginx.com 1604630Svbart@nginx.com if (value != NULL) { 1605630Svbart@nginx.com nxt_conf_get_string(value, &path); 1606630Svbart@nginx.com 1607630Svbart@nginx.com access_log = router->access_log; 1608630Svbart@nginx.com 1609630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1610630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1611630Svbart@nginx.com access_log->count++; 1612630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1613630Svbart@nginx.com 1614630Svbart@nginx.com } else { 1615630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1616630Svbart@nginx.com + path.length); 1617630Svbart@nginx.com if (access_log == NULL) { 1618630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1619630Svbart@nginx.com goto fail; 1620630Svbart@nginx.com } 1621630Svbart@nginx.com 1622630Svbart@nginx.com access_log->fd = -1; 1623630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1624630Svbart@nginx.com access_log->count = 1; 1625630Svbart@nginx.com 1626630Svbart@nginx.com access_log->path.length = path.length; 1627630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1628630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1629630Svbart@nginx.com 1630630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1631630Svbart@nginx.com } 1632630Svbart@nginx.com 1633630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1634630Svbart@nginx.com } 1635630Svbart@nginx.com 1636359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1637359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1638198Sigor@sysoev.ru 163953Sigor@sysoev.ru return NXT_OK; 1640133Sigor@sysoev.ru 1641133Sigor@sysoev.ru app_fail: 1642133Sigor@sysoev.ru 1643133Sigor@sysoev.ru nxt_free(app); 1644133Sigor@sysoev.ru 1645133Sigor@sysoev.ru fail: 1646133Sigor@sysoev.ru 1647141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1648141Smax.romanov@nginx.com 1649141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1650133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1651133Sigor@sysoev.ru nxt_free(app); 1652141Smax.romanov@nginx.com 1653141Smax.romanov@nginx.com } nxt_queue_loop; 1654133Sigor@sysoev.ru 1655133Sigor@sysoev.ru return NXT_ERROR; 1656133Sigor@sysoev.ru } 1657133Sigor@sysoev.ru 1658133Sigor@sysoev.ru 1659133Sigor@sysoev.ru static nxt_app_t * 1660133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1661133Sigor@sysoev.ru { 1662141Smax.romanov@nginx.com nxt_app_t *app; 1663141Smax.romanov@nginx.com 1664141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1665133Sigor@sysoev.ru 1666133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1667133Sigor@sysoev.ru return app; 1668133Sigor@sysoev.ru } 1669141Smax.romanov@nginx.com 1670141Smax.romanov@nginx.com } nxt_queue_loop; 1671133Sigor@sysoev.ru 1672133Sigor@sysoev.ru return NULL; 1673133Sigor@sysoev.ru } 1674133Sigor@sysoev.ru 1675133Sigor@sysoev.ru 1676133Sigor@sysoev.ru static nxt_app_t * 1677133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1678133Sigor@sysoev.ru { 1679133Sigor@sysoev.ru nxt_app_t *app; 1680133Sigor@sysoev.ru 1681133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1682133Sigor@sysoev.ru 1683133Sigor@sysoev.ru if (app == NULL) { 1684134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1685133Sigor@sysoev.ru } 1686133Sigor@sysoev.ru 1687133Sigor@sysoev.ru return app; 168853Sigor@sysoev.ru } 168953Sigor@sysoev.ru 169053Sigor@sysoev.ru 169153Sigor@sysoev.ru static nxt_socket_conf_t * 1692359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1693359Sigor@sysoev.ru nxt_str_t *name) 169453Sigor@sysoev.ru { 1695359Sigor@sysoev.ru size_t size; 1696359Sigor@sysoev.ru nxt_int_t ret; 1697359Sigor@sysoev.ru nxt_bool_t wildcard; 1698359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1699359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1700359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1701359Sigor@sysoev.ru 1702359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1703359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1704564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1705359Sigor@sysoev.ru return NULL; 1706359Sigor@sysoev.ru } 1707359Sigor@sysoev.ru 1708359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1709359Sigor@sysoev.ru 1710359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1711493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1712359Sigor@sysoev.ru 1713591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1714163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 171553Sigor@sysoev.ru return NULL; 171653Sigor@sysoev.ru } 171753Sigor@sysoev.ru 1718359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1719359Sigor@sysoev.ru 1720359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1721359Sigor@sysoev.ru 1722359Sigor@sysoev.ru if (ret != NXT_OK) { 1723359Sigor@sysoev.ru 1724359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1725359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1726359Sigor@sysoev.ru return NULL; 1727359Sigor@sysoev.ru } 1728359Sigor@sysoev.ru 1729359Sigor@sysoev.ru skcf->listen = ls; 1730359Sigor@sysoev.ru 1731359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1732359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1733359Sigor@sysoev.ru 1734359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1735359Sigor@sysoev.ru 1736359Sigor@sysoev.ru ls->socket = -1; 1737359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1738359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1739359Sigor@sysoev.ru ls->read_after_accept = 1; 1740359Sigor@sysoev.ru } 1741359Sigor@sysoev.ru 1742359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1743359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1744359Sigor@sysoev.ru case AF_UNIX: 1745359Sigor@sysoev.ru wildcard = 0; 1746359Sigor@sysoev.ru break; 1747359Sigor@sysoev.ru #endif 1748359Sigor@sysoev.ru #if (NXT_INET6) 1749359Sigor@sysoev.ru case AF_INET6: 1750359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1751359Sigor@sysoev.ru break; 1752359Sigor@sysoev.ru #endif 1753359Sigor@sysoev.ru case AF_INET: 1754359Sigor@sysoev.ru default: 1755359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1756359Sigor@sysoev.ru break; 1757359Sigor@sysoev.ru } 1758359Sigor@sysoev.ru 1759359Sigor@sysoev.ru if (!wildcard) { 1760591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1761359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1762359Sigor@sysoev.ru return NULL; 1763359Sigor@sysoev.ru } 1764359Sigor@sysoev.ru 1765359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1766359Sigor@sysoev.ru } 1767163Smax.romanov@nginx.com 1768163Smax.romanov@nginx.com return skcf; 176953Sigor@sysoev.ru } 177053Sigor@sysoev.ru 177153Sigor@sysoev.ru 1772359Sigor@sysoev.ru static nxt_int_t 1773359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1774359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 177553Sigor@sysoev.ru { 1776359Sigor@sysoev.ru nxt_router_t *router; 1777359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1778359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1779359Sigor@sysoev.ru 1780591Sigor@sysoev.ru router = tmcf->router_conf->router; 1781359Sigor@sysoev.ru 1782359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1783359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1784359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 178553Sigor@sysoev.ru { 1786359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1787359Sigor@sysoev.ru 1788359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1789359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1790359Sigor@sysoev.ru 1791359Sigor@sysoev.ru nxt_queue_remove(qlk); 1792359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1793359Sigor@sysoev.ru 1794359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1795359Sigor@sysoev.ru 1796359Sigor@sysoev.ru return NXT_OK; 179753Sigor@sysoev.ru } 179853Sigor@sysoev.ru } 179953Sigor@sysoev.ru 1800359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1801359Sigor@sysoev.ru 1802359Sigor@sysoev.ru return NXT_DECLINED; 180353Sigor@sysoev.ru } 180453Sigor@sysoev.ru 180553Sigor@sysoev.ru 1806198Sigor@sysoev.ru static void 1807198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1808198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1809198Sigor@sysoev.ru { 1810358Sigor@sysoev.ru size_t size; 1811198Sigor@sysoev.ru uint32_t stream; 1812648Svbart@nginx.com nxt_int_t ret; 1813198Sigor@sysoev.ru nxt_buf_t *b; 1814198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1815198Sigor@sysoev.ru nxt_runtime_t *rt; 1816198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1817198Sigor@sysoev.ru 1818198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1819198Sigor@sysoev.ru if (rpc == NULL) { 1820198Sigor@sysoev.ru goto fail; 1821198Sigor@sysoev.ru } 1822198Sigor@sysoev.ru 1823198Sigor@sysoev.ru rpc->socket_conf = skcf; 1824198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1825198Sigor@sysoev.ru 1826359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1827358Sigor@sysoev.ru 1828358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1829198Sigor@sysoev.ru if (b == NULL) { 1830198Sigor@sysoev.ru goto fail; 1831198Sigor@sysoev.ru } 1832198Sigor@sysoev.ru 1833359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1834198Sigor@sysoev.ru 1835198Sigor@sysoev.ru rt = task->thread->runtime; 1836240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1837198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1838198Sigor@sysoev.ru 1839198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1840198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1841198Sigor@sysoev.ru nxt_router_listen_socket_error, 1842198Sigor@sysoev.ru main_port->pid, rpc); 1843645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 1844198Sigor@sysoev.ru goto fail; 1845198Sigor@sysoev.ru } 1846198Sigor@sysoev.ru 1847648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1848648Svbart@nginx.com stream, router_port->id, b); 1849648Svbart@nginx.com 1850648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1851648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 1852648Svbart@nginx.com goto fail; 1853648Svbart@nginx.com } 1854198Sigor@sysoev.ru 1855198Sigor@sysoev.ru return; 1856198Sigor@sysoev.ru 1857198Sigor@sysoev.ru fail: 1858198Sigor@sysoev.ru 1859198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1860198Sigor@sysoev.ru } 1861198Sigor@sysoev.ru 1862198Sigor@sysoev.ru 1863198Sigor@sysoev.ru static void 1864198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1865198Sigor@sysoev.ru void *data) 186653Sigor@sysoev.ru { 1867359Sigor@sysoev.ru nxt_int_t ret; 1868359Sigor@sysoev.ru nxt_socket_t s; 1869359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 187053Sigor@sysoev.ru 1871198Sigor@sysoev.ru rpc = data; 1872198Sigor@sysoev.ru 1873198Sigor@sysoev.ru s = msg->fd; 1874198Sigor@sysoev.ru 1875198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1876198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1877198Sigor@sysoev.ru goto fail; 187853Sigor@sysoev.ru } 187953Sigor@sysoev.ru 1880359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1881198Sigor@sysoev.ru 1882198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1883198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1884198Sigor@sysoev.ru goto fail; 1885198Sigor@sysoev.ru } 1886198Sigor@sysoev.ru 1887359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1888198Sigor@sysoev.ru 1889198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1890198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1891198Sigor@sysoev.ru 1892198Sigor@sysoev.ru return; 1893148Sigor@sysoev.ru 1894148Sigor@sysoev.ru fail: 1895148Sigor@sysoev.ru 1896148Sigor@sysoev.ru nxt_socket_close(task, s); 1897148Sigor@sysoev.ru 1898198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1899198Sigor@sysoev.ru } 1900198Sigor@sysoev.ru 1901198Sigor@sysoev.ru 1902198Sigor@sysoev.ru static void 1903198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1904198Sigor@sysoev.ru void *data) 1905198Sigor@sysoev.ru { 1906198Sigor@sysoev.ru u_char *p; 1907198Sigor@sysoev.ru size_t size; 1908198Sigor@sysoev.ru uint8_t error; 1909198Sigor@sysoev.ru nxt_buf_t *in, *out; 1910198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1911198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1912198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1913198Sigor@sysoev.ru 1914198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1915198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1916198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1917198Sigor@sysoev.ru nxt_string("ListenerPort"), 1918198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1919198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1920198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1921198Sigor@sysoev.ru nxt_string("ListenerPath"), 1922198Sigor@sysoev.ru }; 1923198Sigor@sysoev.ru 1924198Sigor@sysoev.ru rpc = data; 1925359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 1926352Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1927352Smax.romanov@nginx.com 1928352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 1929352Smax.romanov@nginx.com 1930551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 1931551Smax.romanov@nginx.com return; 1932551Smax.romanov@nginx.com } 1933352Smax.romanov@nginx.com 1934198Sigor@sysoev.ru p = in->mem.pos; 1935198Sigor@sysoev.ru 1936198Sigor@sysoev.ru error = *p++; 1937198Sigor@sysoev.ru 1938703Svbart@nginx.com size = nxt_length("listen socket error: ") 1939703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 1940198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1941198Sigor@sysoev.ru 1942198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1943198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1944198Sigor@sysoev.ru return; 1945198Sigor@sysoev.ru } 1946198Sigor@sysoev.ru 1947198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1948198Sigor@sysoev.ru "listen socket error: " 1949198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1950493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 1951198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1952198Sigor@sysoev.ru 1953198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1954198Sigor@sysoev.ru 1955198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 195653Sigor@sysoev.ru } 195753Sigor@sysoev.ru 195853Sigor@sysoev.ru 1959507Smax.romanov@nginx.com static void 1960507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 1961507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 1962507Smax.romanov@nginx.com { 1963507Smax.romanov@nginx.com size_t size; 1964507Smax.romanov@nginx.com uint32_t stream; 1965648Svbart@nginx.com nxt_int_t ret; 1966507Smax.romanov@nginx.com nxt_buf_t *b; 1967507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 1968507Smax.romanov@nginx.com nxt_runtime_t *rt; 1969507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1970507Smax.romanov@nginx.com 1971507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 1972507Smax.romanov@nginx.com if (rpc == NULL) { 1973507Smax.romanov@nginx.com goto fail; 1974507Smax.romanov@nginx.com } 1975507Smax.romanov@nginx.com 1976507Smax.romanov@nginx.com rpc->app = app; 1977507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 1978507Smax.romanov@nginx.com 1979507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 1980507Smax.romanov@nginx.com 1981507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 1982507Smax.romanov@nginx.com 1983507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1984507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1985507Smax.romanov@nginx.com goto fail; 1986507Smax.romanov@nginx.com } 1987507Smax.romanov@nginx.com 1988507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 1989507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 1990507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1991507Smax.romanov@nginx.com 1992507Smax.romanov@nginx.com rt = task->thread->runtime; 1993507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1994507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1995507Smax.romanov@nginx.com 1996507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 1997507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 1998507Smax.romanov@nginx.com nxt_router_app_prefork_error, 1999507Smax.romanov@nginx.com -1, rpc); 2000507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2001507Smax.romanov@nginx.com goto fail; 2002507Smax.romanov@nginx.com } 2003507Smax.romanov@nginx.com 2004648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2005648Svbart@nginx.com stream, router_port->id, b); 2006648Svbart@nginx.com 2007648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2008648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2009648Svbart@nginx.com goto fail; 2010648Svbart@nginx.com } 2011648Svbart@nginx.com 2012507Smax.romanov@nginx.com app->pending_processes++; 2013507Smax.romanov@nginx.com 2014507Smax.romanov@nginx.com return; 2015507Smax.romanov@nginx.com 2016507Smax.romanov@nginx.com fail: 2017507Smax.romanov@nginx.com 2018507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2019507Smax.romanov@nginx.com } 2020507Smax.romanov@nginx.com 2021507Smax.romanov@nginx.com 2022507Smax.romanov@nginx.com static void 2023507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2024507Smax.romanov@nginx.com void *data) 2025507Smax.romanov@nginx.com { 2026507Smax.romanov@nginx.com nxt_app_t *app; 2027507Smax.romanov@nginx.com nxt_port_t *port; 2028507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2029507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2030507Smax.romanov@nginx.com 2031507Smax.romanov@nginx.com rpc = data; 2032507Smax.romanov@nginx.com app = rpc->app; 2033507Smax.romanov@nginx.com 2034507Smax.romanov@nginx.com port = msg->u.new_port; 2035507Smax.romanov@nginx.com port->app = app; 2036507Smax.romanov@nginx.com 2037507Smax.romanov@nginx.com app->pending_processes--; 2038507Smax.romanov@nginx.com app->processes++; 2039507Smax.romanov@nginx.com app->idle_processes++; 2040507Smax.romanov@nginx.com 2041507Smax.romanov@nginx.com engine = task->thread->engine; 2042507Smax.romanov@nginx.com 2043507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2044507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 2045507Smax.romanov@nginx.com 2046507Smax.romanov@nginx.com port->idle_start = 0; 2047507Smax.romanov@nginx.com 2048507Smax.romanov@nginx.com nxt_port_inc_use(port); 2049507Smax.romanov@nginx.com 2050507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2051507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2052507Smax.romanov@nginx.com } 2053507Smax.romanov@nginx.com 2054507Smax.romanov@nginx.com 2055507Smax.romanov@nginx.com static void 2056507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2057507Smax.romanov@nginx.com void *data) 2058507Smax.romanov@nginx.com { 2059507Smax.romanov@nginx.com nxt_app_t *app; 2060507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2061507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2062507Smax.romanov@nginx.com 2063507Smax.romanov@nginx.com rpc = data; 2064507Smax.romanov@nginx.com app = rpc->app; 2065507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2066507Smax.romanov@nginx.com 2067507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2068507Smax.romanov@nginx.com &app->name); 2069507Smax.romanov@nginx.com 2070507Smax.romanov@nginx.com app->pending_processes--; 2071507Smax.romanov@nginx.com 2072507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2073507Smax.romanov@nginx.com } 2074507Smax.romanov@nginx.com 2075507Smax.romanov@nginx.com 207653Sigor@sysoev.ru static nxt_int_t 207753Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 207853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 207953Sigor@sysoev.ru { 208053Sigor@sysoev.ru nxt_int_t ret; 208153Sigor@sysoev.ru nxt_uint_t n, threads; 208253Sigor@sysoev.ru nxt_queue_link_t *qlk; 208353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 208453Sigor@sysoev.ru 2085591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 208653Sigor@sysoev.ru 208753Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 208853Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 208953Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 209053Sigor@sysoev.ru return NXT_ERROR; 209153Sigor@sysoev.ru } 209253Sigor@sysoev.ru 209353Sigor@sysoev.ru n = 0; 209453Sigor@sysoev.ru 209553Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 209653Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 209753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 209853Sigor@sysoev.ru { 209953Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 210053Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 210153Sigor@sysoev.ru return NXT_ERROR; 210253Sigor@sysoev.ru } 210353Sigor@sysoev.ru 2104115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 210553Sigor@sysoev.ru 210653Sigor@sysoev.ru if (n < threads) { 2107315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2108115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 210953Sigor@sysoev.ru 211053Sigor@sysoev.ru } else { 2111315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2112115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 211353Sigor@sysoev.ru } 211453Sigor@sysoev.ru 211553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 211653Sigor@sysoev.ru return ret; 211753Sigor@sysoev.ru } 211853Sigor@sysoev.ru 211953Sigor@sysoev.ru n++; 212053Sigor@sysoev.ru } 212153Sigor@sysoev.ru 212253Sigor@sysoev.ru tmcf->new_threads = n; 212353Sigor@sysoev.ru 212453Sigor@sysoev.ru while (n < threads) { 212553Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 212653Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 212753Sigor@sysoev.ru return NXT_ERROR; 212853Sigor@sysoev.ru } 212953Sigor@sysoev.ru 2130315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2131315Sigor@sysoev.ru 213253Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 213353Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 213453Sigor@sysoev.ru return NXT_ERROR; 213553Sigor@sysoev.ru } 213653Sigor@sysoev.ru 2137115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 213853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 213953Sigor@sysoev.ru return ret; 214053Sigor@sysoev.ru } 214153Sigor@sysoev.ru 214253Sigor@sysoev.ru n++; 214353Sigor@sysoev.ru } 214453Sigor@sysoev.ru 214553Sigor@sysoev.ru return NXT_OK; 214653Sigor@sysoev.ru } 214753Sigor@sysoev.ru 214853Sigor@sysoev.ru 214953Sigor@sysoev.ru static nxt_int_t 2150115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2151115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 215253Sigor@sysoev.ru { 2153359Sigor@sysoev.ru nxt_int_t ret; 215453Sigor@sysoev.ru 2155154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2156154Sigor@sysoev.ru nxt_router_listen_socket_create); 2157115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2158115Sigor@sysoev.ru return ret; 2159115Sigor@sysoev.ru } 2160115Sigor@sysoev.ru 2161154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2162154Sigor@sysoev.ru nxt_router_listen_socket_create); 216353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 216453Sigor@sysoev.ru return ret; 216553Sigor@sysoev.ru } 216653Sigor@sysoev.ru 2167115Sigor@sysoev.ru return ret; 216853Sigor@sysoev.ru } 216953Sigor@sysoev.ru 217053Sigor@sysoev.ru 217153Sigor@sysoev.ru static nxt_int_t 2172115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2173115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 217453Sigor@sysoev.ru { 2175359Sigor@sysoev.ru nxt_int_t ret; 217653Sigor@sysoev.ru 2177154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2178154Sigor@sysoev.ru nxt_router_listen_socket_create); 217953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 218053Sigor@sysoev.ru return ret; 218153Sigor@sysoev.ru } 218253Sigor@sysoev.ru 2183154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2184154Sigor@sysoev.ru nxt_router_listen_socket_update); 218553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 218653Sigor@sysoev.ru return ret; 218753Sigor@sysoev.ru } 218853Sigor@sysoev.ru 2189139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2190115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2191115Sigor@sysoev.ru return ret; 2192115Sigor@sysoev.ru } 2193115Sigor@sysoev.ru 2194115Sigor@sysoev.ru return ret; 219553Sigor@sysoev.ru } 219653Sigor@sysoev.ru 219753Sigor@sysoev.ru 219853Sigor@sysoev.ru static nxt_int_t 2199115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2200115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 220153Sigor@sysoev.ru { 220253Sigor@sysoev.ru nxt_int_t ret; 220353Sigor@sysoev.ru 2204313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2205313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2206313Sigor@sysoev.ru return ret; 2207313Sigor@sysoev.ru } 2208313Sigor@sysoev.ru 2209139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 221053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 221153Sigor@sysoev.ru return ret; 221253Sigor@sysoev.ru } 221353Sigor@sysoev.ru 2214139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 221553Sigor@sysoev.ru } 221653Sigor@sysoev.ru 221753Sigor@sysoev.ru 221853Sigor@sysoev.ru static nxt_int_t 2219154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2220154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 222153Sigor@sysoev.ru nxt_work_handler_t handler) 222253Sigor@sysoev.ru { 2223153Sigor@sysoev.ru nxt_joint_job_t *job; 222453Sigor@sysoev.ru nxt_queue_link_t *qlk; 2225155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 222653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 222753Sigor@sysoev.ru 222853Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 222953Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 223053Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 223153Sigor@sysoev.ru { 2232154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2233153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2234139Sigor@sysoev.ru return NXT_ERROR; 2235139Sigor@sysoev.ru } 2236139Sigor@sysoev.ru 2237154Sigor@sysoev.ru job->work.next = recf->jobs; 2238154Sigor@sysoev.ru recf->jobs = &job->work; 2239154Sigor@sysoev.ru 2240153Sigor@sysoev.ru job->task = tmcf->engine->task; 2241153Sigor@sysoev.ru job->work.handler = handler; 2242153Sigor@sysoev.ru job->work.task = &job->task; 2243153Sigor@sysoev.ru job->work.obj = job; 2244153Sigor@sysoev.ru job->tmcf = tmcf; 224553Sigor@sysoev.ru 2246154Sigor@sysoev.ru tmcf->count++; 2247154Sigor@sysoev.ru 2248591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2249154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 225053Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 225153Sigor@sysoev.ru return NXT_ERROR; 225253Sigor@sysoev.ru } 225353Sigor@sysoev.ru 2254153Sigor@sysoev.ru job->work.data = joint; 225553Sigor@sysoev.ru 225653Sigor@sysoev.ru joint->count = 1; 2257155Sigor@sysoev.ru 2258155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2259155Sigor@sysoev.ru skcf->count++; 2260155Sigor@sysoev.ru joint->socket_conf = skcf; 2261155Sigor@sysoev.ru 226288Smax.romanov@nginx.com joint->engine = recf->engine; 226353Sigor@sysoev.ru } 226453Sigor@sysoev.ru 226520Sigor@sysoev.ru return NXT_OK; 226620Sigor@sysoev.ru } 226720Sigor@sysoev.ru 226820Sigor@sysoev.ru 226920Sigor@sysoev.ru static nxt_int_t 2270313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2271313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2272313Sigor@sysoev.ru { 2273313Sigor@sysoev.ru nxt_joint_job_t *job; 2274313Sigor@sysoev.ru 2275313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2276313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2277313Sigor@sysoev.ru return NXT_ERROR; 2278313Sigor@sysoev.ru } 2279313Sigor@sysoev.ru 2280313Sigor@sysoev.ru job->work.next = recf->jobs; 2281313Sigor@sysoev.ru recf->jobs = &job->work; 2282313Sigor@sysoev.ru 2283313Sigor@sysoev.ru job->task = tmcf->engine->task; 2284313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2285313Sigor@sysoev.ru job->work.task = &job->task; 2286313Sigor@sysoev.ru job->work.obj = NULL; 2287313Sigor@sysoev.ru job->work.data = NULL; 2288313Sigor@sysoev.ru job->tmcf = NULL; 2289313Sigor@sysoev.ru 2290313Sigor@sysoev.ru return NXT_OK; 2291313Sigor@sysoev.ru } 2292313Sigor@sysoev.ru 2293313Sigor@sysoev.ru 2294313Sigor@sysoev.ru static nxt_int_t 2295139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2296139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 229720Sigor@sysoev.ru { 2298153Sigor@sysoev.ru nxt_joint_job_t *job; 229953Sigor@sysoev.ru nxt_queue_link_t *qlk; 230020Sigor@sysoev.ru 230153Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 230253Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 230353Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 230453Sigor@sysoev.ru { 2305154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2306153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2307139Sigor@sysoev.ru return NXT_ERROR; 2308139Sigor@sysoev.ru } 2309139Sigor@sysoev.ru 2310154Sigor@sysoev.ru job->work.next = recf->jobs; 2311154Sigor@sysoev.ru recf->jobs = &job->work; 2312154Sigor@sysoev.ru 2313153Sigor@sysoev.ru job->task = tmcf->engine->task; 2314153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2315153Sigor@sysoev.ru job->work.task = &job->task; 2316153Sigor@sysoev.ru job->work.obj = job; 2317153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2318153Sigor@sysoev.ru job->tmcf = tmcf; 2319154Sigor@sysoev.ru 2320154Sigor@sysoev.ru tmcf->count++; 232120Sigor@sysoev.ru } 232220Sigor@sysoev.ru 232353Sigor@sysoev.ru return NXT_OK; 232453Sigor@sysoev.ru } 232520Sigor@sysoev.ru 232620Sigor@sysoev.ru 232753Sigor@sysoev.ru static nxt_int_t 232853Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 232953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 233053Sigor@sysoev.ru { 233153Sigor@sysoev.ru nxt_int_t ret; 233253Sigor@sysoev.ru nxt_uint_t i, threads; 233353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 233420Sigor@sysoev.ru 233553Sigor@sysoev.ru recf = tmcf->engines->elts; 2336591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 233720Sigor@sysoev.ru 233853Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 233953Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 234053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 234153Sigor@sysoev.ru return ret; 234253Sigor@sysoev.ru } 234320Sigor@sysoev.ru } 234420Sigor@sysoev.ru 234520Sigor@sysoev.ru return NXT_OK; 234620Sigor@sysoev.ru } 234753Sigor@sysoev.ru 234853Sigor@sysoev.ru 234953Sigor@sysoev.ru static nxt_int_t 235053Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 235153Sigor@sysoev.ru nxt_event_engine_t *engine) 235253Sigor@sysoev.ru { 235353Sigor@sysoev.ru nxt_int_t ret; 235453Sigor@sysoev.ru nxt_thread_link_t *link; 235553Sigor@sysoev.ru nxt_thread_handle_t handle; 235653Sigor@sysoev.ru 235753Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 235853Sigor@sysoev.ru 235953Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 236053Sigor@sysoev.ru return NXT_ERROR; 236153Sigor@sysoev.ru } 236253Sigor@sysoev.ru 236353Sigor@sysoev.ru link->start = nxt_router_thread_start; 236453Sigor@sysoev.ru link->engine = engine; 236553Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 236653Sigor@sysoev.ru link->work.task = task; 236753Sigor@sysoev.ru link->work.data = link; 236853Sigor@sysoev.ru 236953Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 237053Sigor@sysoev.ru 237153Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 237253Sigor@sysoev.ru 237353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 237453Sigor@sysoev.ru nxt_queue_remove(&engine->link); 237553Sigor@sysoev.ru } 237653Sigor@sysoev.ru 237753Sigor@sysoev.ru return ret; 237853Sigor@sysoev.ru } 237953Sigor@sysoev.ru 238053Sigor@sysoev.ru 238153Sigor@sysoev.ru static void 2382343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2383343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2384133Sigor@sysoev.ru { 2385507Smax.romanov@nginx.com nxt_app_t *app; 2386141Smax.romanov@nginx.com 2387141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2388133Sigor@sysoev.ru 2389753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2390343Smax.romanov@nginx.com 2391141Smax.romanov@nginx.com } nxt_queue_loop; 2392133Sigor@sysoev.ru 2393133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2394133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2395133Sigor@sysoev.ru } 2396133Sigor@sysoev.ru 2397133Sigor@sysoev.ru 2398133Sigor@sysoev.ru static void 2399315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 240053Sigor@sysoev.ru { 240153Sigor@sysoev.ru nxt_uint_t n; 2402315Sigor@sysoev.ru nxt_event_engine_t *engine; 240353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 240453Sigor@sysoev.ru 240553Sigor@sysoev.ru recf = tmcf->engines->elts; 240653Sigor@sysoev.ru 240753Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2408315Sigor@sysoev.ru engine = recf->engine; 2409315Sigor@sysoev.ru 2410315Sigor@sysoev.ru switch (recf->action) { 2411315Sigor@sysoev.ru 2412315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2413315Sigor@sysoev.ru break; 2414315Sigor@sysoev.ru 2415315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2416315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2417315Sigor@sysoev.ru break; 2418315Sigor@sysoev.ru 2419315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2420315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2421315Sigor@sysoev.ru break; 2422315Sigor@sysoev.ru } 2423315Sigor@sysoev.ru 2424316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2425316Sigor@sysoev.ru 242653Sigor@sysoev.ru recf++; 242753Sigor@sysoev.ru } 242853Sigor@sysoev.ru } 242953Sigor@sysoev.ru 243053Sigor@sysoev.ru 243153Sigor@sysoev.ru static void 2432315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 243353Sigor@sysoev.ru { 2434154Sigor@sysoev.ru nxt_work_t *work, *next; 2435154Sigor@sysoev.ru 2436315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2437154Sigor@sysoev.ru next = work->next; 2438154Sigor@sysoev.ru work->next = NULL; 2439154Sigor@sysoev.ru 2440315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 244153Sigor@sysoev.ru } 244253Sigor@sysoev.ru } 244353Sigor@sysoev.ru 244453Sigor@sysoev.ru 2445320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2446616Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2447616Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2448616Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 244988Smax.romanov@nginx.com }; 245088Smax.romanov@nginx.com 245188Smax.romanov@nginx.com 245288Smax.romanov@nginx.com static void 245353Sigor@sysoev.ru nxt_router_thread_start(void *data) 245453Sigor@sysoev.ru { 2455141Smax.romanov@nginx.com nxt_int_t ret; 2456141Smax.romanov@nginx.com nxt_port_t *port; 245788Smax.romanov@nginx.com nxt_task_t *task; 245853Sigor@sysoev.ru nxt_thread_t *thread; 245953Sigor@sysoev.ru nxt_thread_link_t *link; 246053Sigor@sysoev.ru nxt_event_engine_t *engine; 246153Sigor@sysoev.ru 246253Sigor@sysoev.ru link = data; 246353Sigor@sysoev.ru engine = link->engine; 246488Smax.romanov@nginx.com task = &engine->task; 246553Sigor@sysoev.ru 246653Sigor@sysoev.ru thread = nxt_thread(); 246753Sigor@sysoev.ru 2468165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2469165Smax.romanov@nginx.com 247053Sigor@sysoev.ru /* STUB */ 247153Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 247253Sigor@sysoev.ru 247353Sigor@sysoev.ru engine->task.thread = thread; 247453Sigor@sysoev.ru engine->task.log = thread->log; 247553Sigor@sysoev.ru thread->engine = engine; 247663Sigor@sysoev.ru thread->task = &engine->task; 2477326Svbart@nginx.com #if 0 247853Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2479326Svbart@nginx.com #endif 248053Sigor@sysoev.ru 248163Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2482337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2483337Sigor@sysoev.ru return; 2484337Sigor@sysoev.ru } 248553Sigor@sysoev.ru 2486197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2487197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2488141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2489141Smax.romanov@nginx.com return; 2490141Smax.romanov@nginx.com } 2491141Smax.romanov@nginx.com 2492141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2493141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2494343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2495141Smax.romanov@nginx.com return; 2496141Smax.romanov@nginx.com } 2497141Smax.romanov@nginx.com 2498141Smax.romanov@nginx.com engine->port = port; 2499141Smax.romanov@nginx.com 2500320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2501141Smax.romanov@nginx.com 250253Sigor@sysoev.ru nxt_event_engine_start(engine); 250353Sigor@sysoev.ru } 250453Sigor@sysoev.ru 250553Sigor@sysoev.ru 250653Sigor@sysoev.ru static void 250753Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 250853Sigor@sysoev.ru { 2509153Sigor@sysoev.ru nxt_joint_job_t *job; 2510359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2511359Sigor@sysoev.ru nxt_listen_event_t *lev; 251253Sigor@sysoev.ru nxt_listen_socket_t *ls; 2513359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 251453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 251553Sigor@sysoev.ru 2516153Sigor@sysoev.ru job = obj; 251753Sigor@sysoev.ru joint = data; 251853Sigor@sysoev.ru 2519159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2520159Sigor@sysoev.ru 2521359Sigor@sysoev.ru skcf = joint->socket_conf; 2522359Sigor@sysoev.ru ls = skcf->listen; 2523359Sigor@sysoev.ru 2524359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2525359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2526359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 252753Sigor@sysoev.ru return; 252853Sigor@sysoev.ru } 252953Sigor@sysoev.ru 2530359Sigor@sysoev.ru lev->socket.data = joint; 2531359Sigor@sysoev.ru 2532359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2533359Sigor@sysoev.ru 2534359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2535359Sigor@sysoev.ru ls->count++; 2536359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2537139Sigor@sysoev.ru 2538153Sigor@sysoev.ru job->work.next = NULL; 2539153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2540153Sigor@sysoev.ru 2541153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 254253Sigor@sysoev.ru } 254353Sigor@sysoev.ru 254453Sigor@sysoev.ru 254553Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 254653Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 254753Sigor@sysoev.ru nxt_socket_conf_t *skcf) 254853Sigor@sysoev.ru { 2549115Sigor@sysoev.ru nxt_socket_t fd; 2550115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2551359Sigor@sysoev.ru nxt_listen_event_t *lev; 2552359Sigor@sysoev.ru 2553359Sigor@sysoev.ru fd = skcf->listen->socket; 255453Sigor@sysoev.ru 2555115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2556115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2557115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 255853Sigor@sysoev.ru { 2559359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2560359Sigor@sysoev.ru 2561359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2562359Sigor@sysoev.ru return lev; 256353Sigor@sysoev.ru } 256453Sigor@sysoev.ru } 256553Sigor@sysoev.ru 256653Sigor@sysoev.ru return NULL; 256753Sigor@sysoev.ru } 256853Sigor@sysoev.ru 256953Sigor@sysoev.ru 257053Sigor@sysoev.ru static void 257153Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 257253Sigor@sysoev.ru { 2573153Sigor@sysoev.ru nxt_joint_job_t *job; 257453Sigor@sysoev.ru nxt_event_engine_t *engine; 2575359Sigor@sysoev.ru nxt_listen_event_t *lev; 257653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 257753Sigor@sysoev.ru 2578153Sigor@sysoev.ru job = obj; 257953Sigor@sysoev.ru joint = data; 258053Sigor@sysoev.ru 2581139Sigor@sysoev.ru engine = task->thread->engine; 2582139Sigor@sysoev.ru 2583159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2584159Sigor@sysoev.ru 2585359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2586359Sigor@sysoev.ru joint->socket_conf); 2587359Sigor@sysoev.ru 2588359Sigor@sysoev.ru old = lev->socket.data; 2589359Sigor@sysoev.ru lev->socket.data = joint; 2590359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 259153Sigor@sysoev.ru 2592153Sigor@sysoev.ru job->work.next = NULL; 2593153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2594153Sigor@sysoev.ru 2595153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2596139Sigor@sysoev.ru 2597181Smax.romanov@nginx.com /* 2598181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2599181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2600181Smax.romanov@nginx.com */ 2601181Smax.romanov@nginx.com 2602181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 260353Sigor@sysoev.ru } 260453Sigor@sysoev.ru 260553Sigor@sysoev.ru 260653Sigor@sysoev.ru static void 260753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 260853Sigor@sysoev.ru { 2609153Sigor@sysoev.ru nxt_joint_job_t *job; 2610153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2611359Sigor@sysoev.ru nxt_listen_event_t *lev; 2612153Sigor@sysoev.ru nxt_event_engine_t *engine; 2613153Sigor@sysoev.ru 2614153Sigor@sysoev.ru job = obj; 261553Sigor@sysoev.ru skcf = data; 261653Sigor@sysoev.ru 2617139Sigor@sysoev.ru engine = task->thread->engine; 2618139Sigor@sysoev.ru 2619359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2620359Sigor@sysoev.ru 2621359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 262253Sigor@sysoev.ru 2623163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2624359Sigor@sysoev.ru lev->socket.fd); 2625359Sigor@sysoev.ru 2626359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2627359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2628359Sigor@sysoev.ru 2629359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2630139Sigor@sysoev.ru 2631153Sigor@sysoev.ru job->work.next = NULL; 2632153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2633153Sigor@sysoev.ru 2634153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 263553Sigor@sysoev.ru } 263653Sigor@sysoev.ru 263753Sigor@sysoev.ru 263853Sigor@sysoev.ru static void 2639313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2640313Sigor@sysoev.ru { 2641313Sigor@sysoev.ru nxt_event_engine_t *engine; 2642313Sigor@sysoev.ru 2643313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2644313Sigor@sysoev.ru 2645313Sigor@sysoev.ru engine = task->thread->engine; 2646313Sigor@sysoev.ru 2647313Sigor@sysoev.ru engine->shutdown = 1; 2648313Sigor@sysoev.ru 2649313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2650313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2651313Sigor@sysoev.ru } 2652313Sigor@sysoev.ru } 2653313Sigor@sysoev.ru 2654313Sigor@sysoev.ru 2655313Sigor@sysoev.ru static void 265653Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 265753Sigor@sysoev.ru { 265853Sigor@sysoev.ru nxt_timer_t *timer; 2659359Sigor@sysoev.ru nxt_listen_event_t *lev; 266053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 266153Sigor@sysoev.ru 266253Sigor@sysoev.ru timer = obj; 2663359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 266453Sigor@sysoev.ru 2665163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2666359Sigor@sysoev.ru lev->socket.fd); 2667359Sigor@sysoev.ru 2668359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2669359Sigor@sysoev.ru 2670683Sigor@sysoev.ru joint = lev->socket.data; 2671683Sigor@sysoev.ru lev->socket.data = NULL; 2672683Sigor@sysoev.ru 2673359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2674123Smax.romanov@nginx.com task = &task->thread->engine->task; 2675123Smax.romanov@nginx.com 2676359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2677359Sigor@sysoev.ru 2678683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 267953Sigor@sysoev.ru } 268053Sigor@sysoev.ru 268153Sigor@sysoev.ru 268253Sigor@sysoev.ru static void 2683359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 268453Sigor@sysoev.ru { 2685359Sigor@sysoev.ru nxt_listen_socket_t *ls; 268653Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 268753Sigor@sysoev.ru 2688359Sigor@sysoev.ru ls = skcf->listen; 2689118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 269053Sigor@sysoev.ru 269153Sigor@sysoev.ru nxt_thread_spin_lock(lock); 269253Sigor@sysoev.ru 2693359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2694359Sigor@sysoev.ru task->thread->engine, ls->count); 2695359Sigor@sysoev.ru 2696359Sigor@sysoev.ru if (--ls->count != 0) { 2697359Sigor@sysoev.ru ls = NULL; 269853Sigor@sysoev.ru } 269953Sigor@sysoev.ru 270053Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 270153Sigor@sysoev.ru 2702359Sigor@sysoev.ru if (ls != NULL) { 2703359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2704359Sigor@sysoev.ru nxt_free(ls); 270553Sigor@sysoev.ru } 270653Sigor@sysoev.ru } 270753Sigor@sysoev.ru 270853Sigor@sysoev.ru 2709683Sigor@sysoev.ru void 2710683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 2711683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 2712683Sigor@sysoev.ru { 2713683Sigor@sysoev.ru nxt_event_engine_t *engine; 2714683Sigor@sysoev.ru 2715683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 2716683Sigor@sysoev.ru 2717683Sigor@sysoev.ru if (--lev->count == 0) { 2718683Sigor@sysoev.ru nxt_free(lev); 2719683Sigor@sysoev.ru } 2720683Sigor@sysoev.ru 2721683Sigor@sysoev.ru if (joint != NULL) { 2722683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 2723683Sigor@sysoev.ru } 2724683Sigor@sysoev.ru 2725683Sigor@sysoev.ru engine = task->thread->engine; 2726683Sigor@sysoev.ru 2727683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 2728683Sigor@sysoev.ru nxt_thread_exit(task->thread); 2729683Sigor@sysoev.ru } 2730683Sigor@sysoev.ru } 2731683Sigor@sysoev.ru 2732683Sigor@sysoev.ru 2733683Sigor@sysoev.ru void 273453Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 273553Sigor@sysoev.ru { 2736567Smax.romanov@nginx.com nxt_app_t *app; 273753Sigor@sysoev.ru nxt_socket_conf_t *skcf; 273853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 273953Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 274053Sigor@sysoev.ru 2741163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 274253Sigor@sysoev.ru 274353Sigor@sysoev.ru if (--joint->count != 0) { 274453Sigor@sysoev.ru return; 274553Sigor@sysoev.ru } 274653Sigor@sysoev.ru 274753Sigor@sysoev.ru nxt_queue_remove(&joint->link); 274853Sigor@sysoev.ru 2749530Sigor@sysoev.ru /* 2750530Sigor@sysoev.ru * The joint content can not be safely used after the critical 2751530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 2752530Sigor@sysoev.ru * be already destroyed by another thread. 2753530Sigor@sysoev.ru */ 275453Sigor@sysoev.ru skcf = joint->socket_conf; 2755567Smax.romanov@nginx.com app = skcf->application; 275653Sigor@sysoev.ru rtcf = skcf->router_conf; 275753Sigor@sysoev.ru lock = &rtcf->router->lock; 275853Sigor@sysoev.ru 275953Sigor@sysoev.ru nxt_thread_spin_lock(lock); 276053Sigor@sysoev.ru 2761163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2762163Smax.romanov@nginx.com rtcf, rtcf->count); 2763163Smax.romanov@nginx.com 276453Sigor@sysoev.ru if (--skcf->count != 0) { 276553Sigor@sysoev.ru rtcf = NULL; 2766567Smax.romanov@nginx.com app = NULL; 276753Sigor@sysoev.ru 276853Sigor@sysoev.ru } else { 276953Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 277053Sigor@sysoev.ru 277153Sigor@sysoev.ru if (--rtcf->count != 0) { 277253Sigor@sysoev.ru rtcf = NULL; 277353Sigor@sysoev.ru } 277453Sigor@sysoev.ru } 277553Sigor@sysoev.ru 277653Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 277753Sigor@sysoev.ru 2778567Smax.romanov@nginx.com if (app != NULL) { 2779567Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2780567Smax.romanov@nginx.com } 2781567Smax.romanov@nginx.com 2782141Smax.romanov@nginx.com /* TODO remove engine->port */ 2783141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2784141Smax.romanov@nginx.com 278553Sigor@sysoev.ru if (rtcf != NULL) { 2786115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2787131Smax.romanov@nginx.com 2788*771Sigor@sysoev.ru #if (NXT_TLS) 2789*771Sigor@sysoev.ru if (skcf->tls != NULL) { 2790*771Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 2791*771Sigor@sysoev.ru } 2792*771Sigor@sysoev.ru #endif 2793*771Sigor@sysoev.ru 2794630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 2795630Svbart@nginx.com 2796131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2797131Smax.romanov@nginx.com 279865Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 279953Sigor@sysoev.ru } 280053Sigor@sysoev.ru } 280153Sigor@sysoev.ru 280253Sigor@sysoev.ru 280353Sigor@sysoev.ru static void 2804630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 2805630Svbart@nginx.com nxt_router_access_log_t *access_log) 2806630Svbart@nginx.com { 2807630Svbart@nginx.com size_t size; 2808630Svbart@nginx.com u_char *buf, *p; 2809630Svbart@nginx.com nxt_off_t bytes; 2810630Svbart@nginx.com 2811630Svbart@nginx.com static nxt_time_string_t date_cache = { 2812630Svbart@nginx.com (nxt_atomic_uint_t) -1, 2813630Svbart@nginx.com nxt_router_access_log_date, 2814630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 2815703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 2816630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 2817630Svbart@nginx.com NXT_THREAD_TIME_SEC, 2818630Svbart@nginx.com }; 2819630Svbart@nginx.com 2820630Svbart@nginx.com size = r->remote->address_length 2821630Svbart@nginx.com + 6 /* ' - - [' */ 2822630Svbart@nginx.com + date_cache.size 2823630Svbart@nginx.com + 3 /* '] "' */ 2824630Svbart@nginx.com + r->method->length 2825630Svbart@nginx.com + 1 /* space */ 2826630Svbart@nginx.com + r->target.length 2827630Svbart@nginx.com + 1 /* space */ 2828630Svbart@nginx.com + r->version.length 2829630Svbart@nginx.com + 2 /* '" ' */ 2830630Svbart@nginx.com + 3 /* status */ 2831630Svbart@nginx.com + 1 /* space */ 2832630Svbart@nginx.com + NXT_OFF_T_LEN 2833630Svbart@nginx.com + 2 /* ' "' */ 2834630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 2835630Svbart@nginx.com + 3 /* '" "' */ 2836630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 2837630Svbart@nginx.com + 2 /* '"\n' */ 2838630Svbart@nginx.com ; 2839630Svbart@nginx.com 2840630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 2841630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 2842630Svbart@nginx.com return; 2843630Svbart@nginx.com } 2844630Svbart@nginx.com 2845630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 2846630Svbart@nginx.com r->remote->address_length); 2847630Svbart@nginx.com 2848630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 2849630Svbart@nginx.com 2850630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 2851630Svbart@nginx.com 2852630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 2853630Svbart@nginx.com 2854630Svbart@nginx.com if (r->method->length != 0) { 2855630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 2856630Svbart@nginx.com 2857630Svbart@nginx.com if (r->target.length != 0) { 2858630Svbart@nginx.com *p++ = ' '; 2859630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 2860630Svbart@nginx.com 2861630Svbart@nginx.com if (r->version.length != 0) { 2862630Svbart@nginx.com *p++ = ' '; 2863630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 2864630Svbart@nginx.com } 2865630Svbart@nginx.com } 2866630Svbart@nginx.com 2867630Svbart@nginx.com } else { 2868630Svbart@nginx.com *p++ = '-'; 2869630Svbart@nginx.com } 2870630Svbart@nginx.com 2871630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 2872630Svbart@nginx.com 2873630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 2874630Svbart@nginx.com 2875630Svbart@nginx.com *p++ = ' '; 2876630Svbart@nginx.com 2877630Svbart@nginx.com bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto); 2878630Svbart@nginx.com 2879630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 2880630Svbart@nginx.com 2881630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 2882630Svbart@nginx.com 2883630Svbart@nginx.com if (r->referer != NULL) { 2884630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 2885630Svbart@nginx.com 2886630Svbart@nginx.com } else { 2887630Svbart@nginx.com *p++ = '-'; 2888630Svbart@nginx.com } 2889630Svbart@nginx.com 2890630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 2891630Svbart@nginx.com 2892630Svbart@nginx.com if (r->user_agent != NULL) { 2893630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 2894630Svbart@nginx.com 2895630Svbart@nginx.com } else { 2896630Svbart@nginx.com *p++ = '-'; 2897630Svbart@nginx.com } 2898630Svbart@nginx.com 2899630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 2900630Svbart@nginx.com 2901630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 2902630Svbart@nginx.com } 2903630Svbart@nginx.com 2904630Svbart@nginx.com 2905630Svbart@nginx.com static u_char * 2906630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 2907630Svbart@nginx.com size_t size, const char *format) 2908630Svbart@nginx.com { 2909630Svbart@nginx.com u_char sign; 2910630Svbart@nginx.com time_t gmtoff; 2911630Svbart@nginx.com 2912630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2913630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 2914630Svbart@nginx.com 2915630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 2916630Svbart@nginx.com 2917630Svbart@nginx.com if (gmtoff < 0) { 2918630Svbart@nginx.com gmtoff = -gmtoff; 2919630Svbart@nginx.com sign = '-'; 2920630Svbart@nginx.com 2921630Svbart@nginx.com } else { 2922630Svbart@nginx.com sign = '+'; 2923630Svbart@nginx.com } 2924630Svbart@nginx.com 2925630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 2926630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 2927630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 2928630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 2929630Svbart@nginx.com } 2930630Svbart@nginx.com 2931630Svbart@nginx.com 2932630Svbart@nginx.com static void 2933630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 2934630Svbart@nginx.com { 2935630Svbart@nginx.com uint32_t stream; 2936648Svbart@nginx.com nxt_int_t ret; 2937630Svbart@nginx.com nxt_buf_t *b; 2938630Svbart@nginx.com nxt_port_t *main_port, *router_port; 2939630Svbart@nginx.com nxt_runtime_t *rt; 2940630Svbart@nginx.com nxt_router_access_log_t *access_log; 2941630Svbart@nginx.com 2942630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 2943630Svbart@nginx.com 2944630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 2945630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 2946630Svbart@nginx.com goto fail; 2947630Svbart@nginx.com } 2948630Svbart@nginx.com 2949630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 2950630Svbart@nginx.com *b->mem.free++ = '\0'; 2951630Svbart@nginx.com 2952630Svbart@nginx.com rt = task->thread->runtime; 2953630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2954630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2955630Svbart@nginx.com 2956630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2957630Svbart@nginx.com nxt_router_access_log_ready, 2958630Svbart@nginx.com nxt_router_access_log_error, 2959630Svbart@nginx.com -1, tmcf); 2960630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 2961630Svbart@nginx.com goto fail; 2962630Svbart@nginx.com } 2963630Svbart@nginx.com 2964648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 2965648Svbart@nginx.com stream, router_port->id, b); 2966648Svbart@nginx.com 2967648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2968648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2969648Svbart@nginx.com goto fail; 2970648Svbart@nginx.com } 2971630Svbart@nginx.com 2972630Svbart@nginx.com return; 2973630Svbart@nginx.com 2974630Svbart@nginx.com fail: 2975630Svbart@nginx.com 2976630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2977630Svbart@nginx.com } 2978630Svbart@nginx.com 2979630Svbart@nginx.com 2980630Svbart@nginx.com static void 2981630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2982630Svbart@nginx.com void *data) 2983630Svbart@nginx.com { 2984630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2985630Svbart@nginx.com nxt_router_access_log_t *access_log; 2986630Svbart@nginx.com 2987630Svbart@nginx.com tmcf = data; 2988630Svbart@nginx.com 2989630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 2990630Svbart@nginx.com 2991630Svbart@nginx.com access_log->fd = msg->fd; 2992630Svbart@nginx.com 2993630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2994630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2995630Svbart@nginx.com } 2996630Svbart@nginx.com 2997630Svbart@nginx.com 2998630Svbart@nginx.com static void 2999630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3000630Svbart@nginx.com void *data) 3001630Svbart@nginx.com { 3002630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3003630Svbart@nginx.com 3004630Svbart@nginx.com tmcf = data; 3005630Svbart@nginx.com 3006630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3007630Svbart@nginx.com } 3008630Svbart@nginx.com 3009630Svbart@nginx.com 3010630Svbart@nginx.com static void 3011630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3012630Svbart@nginx.com nxt_router_access_log_t *access_log) 3013630Svbart@nginx.com { 3014630Svbart@nginx.com if (access_log == NULL) { 3015630Svbart@nginx.com return; 3016630Svbart@nginx.com } 3017630Svbart@nginx.com 3018630Svbart@nginx.com nxt_thread_spin_lock(lock); 3019630Svbart@nginx.com 3020630Svbart@nginx.com if (--access_log->count != 0) { 3021630Svbart@nginx.com access_log = NULL; 3022630Svbart@nginx.com } 3023630Svbart@nginx.com 3024630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3025630Svbart@nginx.com 3026630Svbart@nginx.com if (access_log != NULL) { 3027630Svbart@nginx.com 3028630Svbart@nginx.com if (access_log->fd != -1) { 3029630Svbart@nginx.com nxt_fd_close(access_log->fd); 3030630Svbart@nginx.com } 3031630Svbart@nginx.com 3032630Svbart@nginx.com nxt_free(access_log); 3033630Svbart@nginx.com } 3034630Svbart@nginx.com } 3035630Svbart@nginx.com 3036630Svbart@nginx.com 3037631Svbart@nginx.com typedef struct { 3038631Svbart@nginx.com nxt_mp_t *mem_pool; 3039631Svbart@nginx.com nxt_router_access_log_t *access_log; 3040631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3041631Svbart@nginx.com 3042631Svbart@nginx.com 3043631Svbart@nginx.com void 3044631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3045631Svbart@nginx.com { 3046631Svbart@nginx.com nxt_mp_t *mp; 3047631Svbart@nginx.com uint32_t stream; 3048631Svbart@nginx.com nxt_int_t ret; 3049631Svbart@nginx.com nxt_buf_t *b; 3050631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3051631Svbart@nginx.com nxt_runtime_t *rt; 3052631Svbart@nginx.com nxt_router_access_log_t *access_log; 3053631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3054631Svbart@nginx.com 3055631Svbart@nginx.com access_log = nxt_router->access_log; 3056631Svbart@nginx.com 3057631Svbart@nginx.com if (access_log == NULL) { 3058631Svbart@nginx.com return; 3059631Svbart@nginx.com } 3060631Svbart@nginx.com 3061631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3062631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3063631Svbart@nginx.com return; 3064631Svbart@nginx.com } 3065631Svbart@nginx.com 3066631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3067631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3068631Svbart@nginx.com goto fail; 3069631Svbart@nginx.com } 3070631Svbart@nginx.com 3071631Svbart@nginx.com reopen->mem_pool = mp; 3072631Svbart@nginx.com reopen->access_log = access_log; 3073631Svbart@nginx.com 3074631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3075631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3076631Svbart@nginx.com goto fail; 3077631Svbart@nginx.com } 3078631Svbart@nginx.com 3079651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3080651Svbart@nginx.com 3081631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3082631Svbart@nginx.com *b->mem.free++ = '\0'; 3083631Svbart@nginx.com 3084631Svbart@nginx.com rt = task->thread->runtime; 3085631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3086631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3087631Svbart@nginx.com 3088631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3089631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3090631Svbart@nginx.com nxt_router_access_log_reopen_error, 3091631Svbart@nginx.com -1, reopen); 3092631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3093631Svbart@nginx.com goto fail; 3094631Svbart@nginx.com } 3095631Svbart@nginx.com 3096631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3097631Svbart@nginx.com stream, router_port->id, b); 3098631Svbart@nginx.com 3099631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3100631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3101631Svbart@nginx.com goto fail; 3102631Svbart@nginx.com } 3103631Svbart@nginx.com 3104651Svbart@nginx.com nxt_mp_retain(mp); 3105651Svbart@nginx.com 3106631Svbart@nginx.com return; 3107631Svbart@nginx.com 3108631Svbart@nginx.com fail: 3109631Svbart@nginx.com 3110631Svbart@nginx.com nxt_mp_destroy(mp); 3111631Svbart@nginx.com } 3112631Svbart@nginx.com 3113631Svbart@nginx.com 3114631Svbart@nginx.com static void 3115651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3116651Svbart@nginx.com { 3117651Svbart@nginx.com nxt_mp_t *mp; 3118651Svbart@nginx.com nxt_buf_t *b; 3119651Svbart@nginx.com 3120651Svbart@nginx.com b = obj; 3121651Svbart@nginx.com mp = b->data; 3122651Svbart@nginx.com 3123651Svbart@nginx.com nxt_mp_release(mp); 3124651Svbart@nginx.com } 3125651Svbart@nginx.com 3126651Svbart@nginx.com 3127651Svbart@nginx.com static void 3128631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3129631Svbart@nginx.com void *data) 3130631Svbart@nginx.com { 3131631Svbart@nginx.com nxt_router_access_log_t *access_log; 3132631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3133631Svbart@nginx.com 3134631Svbart@nginx.com reopen = data; 3135631Svbart@nginx.com 3136631Svbart@nginx.com access_log = reopen->access_log; 3137631Svbart@nginx.com 3138631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3139631Svbart@nginx.com 3140631Svbart@nginx.com if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) { 3141631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3142631Svbart@nginx.com msg->fd, access_log->fd, nxt_errno); 3143631Svbart@nginx.com } 3144631Svbart@nginx.com } 3145631Svbart@nginx.com 3146631Svbart@nginx.com nxt_fd_close(msg->fd); 3147651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3148631Svbart@nginx.com } 3149631Svbart@nginx.com 3150631Svbart@nginx.com 3151631Svbart@nginx.com static void 3152631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3153631Svbart@nginx.com void *data) 3154631Svbart@nginx.com { 3155631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3156631Svbart@nginx.com 3157631Svbart@nginx.com reopen = data; 3158631Svbart@nginx.com 3159651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3160631Svbart@nginx.com } 3161631Svbart@nginx.com 3162631Svbart@nginx.com 3163630Svbart@nginx.com static void 316453Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 316553Sigor@sysoev.ru { 3166141Smax.romanov@nginx.com nxt_port_t *port; 316753Sigor@sysoev.ru nxt_thread_link_t *link; 316853Sigor@sysoev.ru nxt_event_engine_t *engine; 316953Sigor@sysoev.ru nxt_thread_handle_t handle; 317053Sigor@sysoev.ru 317158Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 317253Sigor@sysoev.ru link = data; 317353Sigor@sysoev.ru 317453Sigor@sysoev.ru nxt_thread_wait(handle); 317553Sigor@sysoev.ru 317653Sigor@sysoev.ru engine = link->engine; 317753Sigor@sysoev.ru 317853Sigor@sysoev.ru nxt_queue_remove(&engine->link); 317953Sigor@sysoev.ru 3180141Smax.romanov@nginx.com port = engine->port; 3181141Smax.romanov@nginx.com 3182141Smax.romanov@nginx.com // TODO notify all apps 3183141Smax.romanov@nginx.com 3184343Smax.romanov@nginx.com port->engine = task->thread->engine; 3185163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3186343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3187163Smax.romanov@nginx.com 3188163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 318963Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 319053Sigor@sysoev.ru 319153Sigor@sysoev.ru nxt_event_engine_free(engine); 319253Sigor@sysoev.ru 319353Sigor@sysoev.ru nxt_free(link); 319453Sigor@sysoev.ru } 319553Sigor@sysoev.ru 319653Sigor@sysoev.ru 319753Sigor@sysoev.ru static void 3198318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3199318Smax.romanov@nginx.com void *data) 320088Smax.romanov@nginx.com { 320188Smax.romanov@nginx.com size_t dump_size; 3202431Sigor@sysoev.ru nxt_int_t ret; 3203608Sigor@sysoev.ru nxt_buf_t *b; 3204431Sigor@sysoev.ru nxt_http_request_t *r; 320588Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3206431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 3207743Smax.romanov@nginx.com nxt_unit_response_t *resp; 320888Smax.romanov@nginx.com 320988Smax.romanov@nginx.com b = msg->buf; 3210318Smax.romanov@nginx.com rc = data; 321188Smax.romanov@nginx.com 321288Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 321388Smax.romanov@nginx.com 321488Smax.romanov@nginx.com if (dump_size > 300) { 321588Smax.romanov@nginx.com dump_size = 300; 321688Smax.romanov@nginx.com } 321788Smax.romanov@nginx.com 3218494Spluknet@nginx.com nxt_debug(task, "%srouter app data (%uz): %*s", 321988Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 322088Smax.romanov@nginx.com b->mem.pos); 322188Smax.romanov@nginx.com 322288Smax.romanov@nginx.com if (msg->size == 0) { 322388Smax.romanov@nginx.com b = NULL; 322488Smax.romanov@nginx.com } 322588Smax.romanov@nginx.com 3226431Sigor@sysoev.ru ar = rc->ap; 3227570Smax.romanov@nginx.com if (nxt_slow_path(ar == NULL)) { 3228570Smax.romanov@nginx.com return; 3229570Smax.romanov@nginx.com } 3230425Smax.romanov@nginx.com 3231608Sigor@sysoev.ru if (ar->request->error) { 3232608Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3233608Sigor@sysoev.ru return; 3234608Sigor@sysoev.ru } 3235608Sigor@sysoev.ru 323688Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 323788Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 323888Smax.romanov@nginx.com 3239608Sigor@sysoev.ru nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request)); 3240167Smax.romanov@nginx.com 3241343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3242425Smax.romanov@nginx.com 3243425Smax.romanov@nginx.com } else { 3244615Smax.romanov@nginx.com if (rc->app != NULL && rc->app->timeout != 0) { 3245431Sigor@sysoev.ru ar->timer.handler = nxt_router_app_timeout; 3246615Smax.romanov@nginx.com ar->timer_data = rc; 3247431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); 3248425Smax.romanov@nginx.com } 324988Smax.romanov@nginx.com } 325088Smax.romanov@nginx.com 325188Smax.romanov@nginx.com if (b == NULL) { 325288Smax.romanov@nginx.com return; 325388Smax.romanov@nginx.com } 325488Smax.romanov@nginx.com 3255206Smax.romanov@nginx.com if (msg->buf == b) { 3256206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3257206Smax.romanov@nginx.com msg->buf = NULL; 3258206Smax.romanov@nginx.com } 3259194Smax.romanov@nginx.com 3260431Sigor@sysoev.ru r = ar->request; 3261431Sigor@sysoev.ru 3262431Sigor@sysoev.ru if (r->header_sent) { 3263431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3264431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3265277Sigor@sysoev.ru 326688Smax.romanov@nginx.com } else { 3267743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3268743Smax.romanov@nginx.com 3269743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3270743Smax.romanov@nginx.com goto fail; 3271743Smax.romanov@nginx.com } 3272743Smax.romanov@nginx.com 3273743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3274743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3275743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3276743Smax.romanov@nginx.com goto fail; 3277743Smax.romanov@nginx.com } 3278743Smax.romanov@nginx.com 3279743Smax.romanov@nginx.com nxt_unit_field_t *f; 3280743Smax.romanov@nginx.com nxt_http_field_t *field; 3281743Smax.romanov@nginx.com 3282743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 3283743Smax.romanov@nginx.com field = nxt_list_add(ar->resp_parser.fields); 3284743Smax.romanov@nginx.com 3285743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3286743Smax.romanov@nginx.com goto fail; 3287743Smax.romanov@nginx.com } 3288743Smax.romanov@nginx.com 3289743Smax.romanov@nginx.com field->hash = f->hash; 3290743Smax.romanov@nginx.com field->skip = f->skip; 3291743Smax.romanov@nginx.com 3292743Smax.romanov@nginx.com field->name_length = f->name_length; 3293743Smax.romanov@nginx.com field->value_length = f->value_length; 3294743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3295743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3296743Smax.romanov@nginx.com 3297743Smax.romanov@nginx.com nxt_debug(task, "header: %*s: %*s", 3298743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3299743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 3300743Smax.romanov@nginx.com } 3301743Smax.romanov@nginx.com r->status = resp->status; 3302743Smax.romanov@nginx.com 3303743Smax.romanov@nginx.com /* 3304431Sigor@sysoev.ru ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); 3305431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_DONE)) { 3306431Sigor@sysoev.ru goto fail; 3307431Sigor@sysoev.ru } 3308743Smax.romanov@nginx.com */ 3309431Sigor@sysoev.ru r->resp.fields = ar->resp_parser.fields; 3310431Sigor@sysoev.ru 3311431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 3312431Sigor@sysoev.ru &nxt_response_fields_hash, r); 3313431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3314431Sigor@sysoev.ru goto fail; 3315431Sigor@sysoev.ru } 3316431Sigor@sysoev.ru 3317743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3318743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3319743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3320743Smax.romanov@nginx.com 3321743Smax.romanov@nginx.com } else { 3322743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3323743Smax.romanov@nginx.com } 3324743Smax.romanov@nginx.com 3325435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 3326435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3327435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3328507Smax.romanov@nginx.com 3329520Smax.romanov@nginx.com b = b->next; 3330520Smax.romanov@nginx.com } 3331520Smax.romanov@nginx.com 3332520Smax.romanov@nginx.com if (b != NULL) { 3333431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3334431Sigor@sysoev.ru } 3335431Sigor@sysoev.ru 3336431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 3337431Sigor@sysoev.ru 3338431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 3339431Sigor@sysoev.ru } 3340431Sigor@sysoev.ru 3341431Sigor@sysoev.ru return; 3342431Sigor@sysoev.ru 3343431Sigor@sysoev.ru fail: 3344431Sigor@sysoev.ru 3345615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3346615Smax.romanov@nginx.com 3347431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3348431Sigor@sysoev.ru } 3349431Sigor@sysoev.ru 3350431Sigor@sysoev.ru 3351431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3352431Sigor@sysoev.ru nxt_aligned(64) = 3353431Sigor@sysoev.ru { 3354431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 3355431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 3356431Sigor@sysoev.ru }; 3357431Sigor@sysoev.ru 3358431Sigor@sysoev.ru 3359431Sigor@sysoev.ru static void 3360431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3361431Sigor@sysoev.ru { 3362431Sigor@sysoev.ru nxt_buf_t *out; 3363431Sigor@sysoev.ru nxt_http_request_t *r; 3364431Sigor@sysoev.ru 3365431Sigor@sysoev.ru r = obj; 3366431Sigor@sysoev.ru 3367431Sigor@sysoev.ru out = r->out; 3368431Sigor@sysoev.ru 3369431Sigor@sysoev.ru if (out != NULL) { 3370431Sigor@sysoev.ru r->out = NULL; 3371431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 337288Smax.romanov@nginx.com } 337388Smax.romanov@nginx.com } 337488Smax.romanov@nginx.com 3375277Sigor@sysoev.ru 3376318Smax.romanov@nginx.com static void 3377318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3378318Smax.romanov@nginx.com void *data) 3379318Smax.romanov@nginx.com { 3380425Smax.romanov@nginx.com nxt_int_t res; 3381425Smax.romanov@nginx.com nxt_port_t *port; 3382425Smax.romanov@nginx.com nxt_bool_t cancelled; 3383425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3384318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3385318Smax.romanov@nginx.com 3386318Smax.romanov@nginx.com rc = data; 3387318Smax.romanov@nginx.com 3388425Smax.romanov@nginx.com ra = rc->ra; 3389425Smax.romanov@nginx.com 3390425Smax.romanov@nginx.com if (ra != NULL) { 3391425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 3392425Smax.romanov@nginx.com 3393425Smax.romanov@nginx.com if (cancelled) { 3394425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3395425Smax.romanov@nginx.com 3396427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 3397425Smax.romanov@nginx.com 3398425Smax.romanov@nginx.com if (res == NXT_OK) { 3399425Smax.romanov@nginx.com port = ra->app_port; 3400425Smax.romanov@nginx.com 3401551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3402551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra"); 3403551Smax.romanov@nginx.com return; 3404551Smax.romanov@nginx.com } 3405425Smax.romanov@nginx.com 3406425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 3407425Smax.romanov@nginx.com port->pid); 3408425Smax.romanov@nginx.com 3409425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3410425Smax.romanov@nginx.com } 3411425Smax.romanov@nginx.com 3412425Smax.romanov@nginx.com msg->port_msg.last = 0; 3413425Smax.romanov@nginx.com 3414425Smax.romanov@nginx.com return; 3415425Smax.romanov@nginx.com } 3416425Smax.romanov@nginx.com } 3417425Smax.romanov@nginx.com 3418616Smax.romanov@nginx.com if (rc->ap != NULL) { 3419616Smax.romanov@nginx.com nxt_http_request_error(task, rc->ap->request, 3420616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3421616Smax.romanov@nginx.com } 3422318Smax.romanov@nginx.com 3423343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3424318Smax.romanov@nginx.com } 3425318Smax.romanov@nginx.com 3426318Smax.romanov@nginx.com 3427141Smax.romanov@nginx.com static void 3428343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3429343Smax.romanov@nginx.com void *data) 3430192Smax.romanov@nginx.com { 3431753Smax.romanov@nginx.com nxt_app_t *app; 3432753Smax.romanov@nginx.com nxt_port_t *port; 3433753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3434753Smax.romanov@nginx.com 3435753Smax.romanov@nginx.com app_joint = data; 3436347Smax.romanov@nginx.com port = msg->u.new_port; 3437343Smax.romanov@nginx.com 3438753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3439343Smax.romanov@nginx.com nxt_assert(port != NULL); 3440343Smax.romanov@nginx.com 3441753Smax.romanov@nginx.com app = app_joint->app; 3442753Smax.romanov@nginx.com 3443753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3444753Smax.romanov@nginx.com 3445753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3446753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3447753Smax.romanov@nginx.com 3448753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3449753Smax.romanov@nginx.com 3450753Smax.romanov@nginx.com return; 3451753Smax.romanov@nginx.com } 3452753Smax.romanov@nginx.com 3453343Smax.romanov@nginx.com port->app = app; 3454343Smax.romanov@nginx.com 3455343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3456343Smax.romanov@nginx.com 3457507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3458507Smax.romanov@nginx.com 3459507Smax.romanov@nginx.com app->pending_processes--; 3460507Smax.romanov@nginx.com app->processes++; 3461343Smax.romanov@nginx.com 3462343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3463343Smax.romanov@nginx.com 3464507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3465507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3466343Smax.romanov@nginx.com 3467343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 3468192Smax.romanov@nginx.com } 3469192Smax.romanov@nginx.com 3470192Smax.romanov@nginx.com 3471192Smax.romanov@nginx.com static void 3472343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3473343Smax.romanov@nginx.com void *data) 3474192Smax.romanov@nginx.com { 3475318Smax.romanov@nginx.com nxt_app_t *app; 3476753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3477318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3478318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3479343Smax.romanov@nginx.com 3480753Smax.romanov@nginx.com app_joint = data; 3481753Smax.romanov@nginx.com 3482753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3483753Smax.romanov@nginx.com 3484753Smax.romanov@nginx.com app = app_joint->app; 3485753Smax.romanov@nginx.com 3486753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3487753Smax.romanov@nginx.com 3488753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3489753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 3490753Smax.romanov@nginx.com 3491753Smax.romanov@nginx.com return; 3492753Smax.romanov@nginx.com } 3493343Smax.romanov@nginx.com 3494343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 3495343Smax.romanov@nginx.com 3496343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3497343Smax.romanov@nginx.com 3498507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3499507Smax.romanov@nginx.com 3500507Smax.romanov@nginx.com app->pending_processes--; 3501318Smax.romanov@nginx.com 3502318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 3503318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 3504318Smax.romanov@nginx.com nxt_queue_remove(lnk); 3505343Smax.romanov@nginx.com lnk->next = NULL; 3506318Smax.romanov@nginx.com 3507425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3508318Smax.romanov@nginx.com 3509343Smax.romanov@nginx.com } else { 3510343Smax.romanov@nginx.com ra = NULL; 3511343Smax.romanov@nginx.com } 3512343Smax.romanov@nginx.com 3513343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3514343Smax.romanov@nginx.com 3515343Smax.romanov@nginx.com if (ra != NULL) { 3516318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 3517318Smax.romanov@nginx.com &app->name, app, ra->stream); 3518318Smax.romanov@nginx.com 3519507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 3520425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3521318Smax.romanov@nginx.com } 3522192Smax.romanov@nginx.com } 3523192Smax.romanov@nginx.com 3524753Smax.romanov@nginx.com nxt_inline nxt_port_t * 3525753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app); 3526192Smax.romanov@nginx.com 3527343Smax.romanov@nginx.com void 3528343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 3529141Smax.romanov@nginx.com { 3530343Smax.romanov@nginx.com int c; 3531343Smax.romanov@nginx.com 3532343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 3533343Smax.romanov@nginx.com 3534343Smax.romanov@nginx.com if (i < 0 && c == -i) { 3535343Smax.romanov@nginx.com 3536753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 3537753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 3538753Smax.romanov@nginx.com 3539753Smax.romanov@nginx.com } else { 3540753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 3541753Smax.romanov@nginx.com } 3542163Smax.romanov@nginx.com } 3543343Smax.romanov@nginx.com } 3544343Smax.romanov@nginx.com 3545343Smax.romanov@nginx.com 3546424Smax.romanov@nginx.com nxt_inline nxt_bool_t 3547424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 3548424Smax.romanov@nginx.com { 3549424Smax.romanov@nginx.com nxt_port_t *port; 3550424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3551424Smax.romanov@nginx.com 3552424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3553424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3554424Smax.romanov@nginx.com 3555424Smax.romanov@nginx.com return port->app_pending_responses > 0; 3556424Smax.romanov@nginx.com } 3557424Smax.romanov@nginx.com 3558424Smax.romanov@nginx.com 3559343Smax.romanov@nginx.com nxt_inline nxt_port_t * 3560427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 3561343Smax.romanov@nginx.com { 3562343Smax.romanov@nginx.com nxt_port_t *port; 3563343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3564343Smax.romanov@nginx.com 3565343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3566343Smax.romanov@nginx.com nxt_queue_remove(lnk); 3567343Smax.romanov@nginx.com 3568343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3569343Smax.romanov@nginx.com 3570424Smax.romanov@nginx.com port->app_pending_responses++; 3571424Smax.romanov@nginx.com 3572507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3573507Smax.romanov@nginx.com app->idle_processes--; 3574507Smax.romanov@nginx.com 3575507Smax.romanov@nginx.com if (port->idle_start == 0) { 3576507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 3577507Smax.romanov@nginx.com 3578507Smax.romanov@nginx.com } else { 3579507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 3580507Smax.romanov@nginx.com 3581507Smax.romanov@nginx.com port->idle_start = 0; 3582507Smax.romanov@nginx.com } 3583507Smax.romanov@nginx.com } 3584507Smax.romanov@nginx.com 3585428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 3586428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3587428Smax.romanov@nginx.com && (app->max_requests == 0 3588428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3589428Smax.romanov@nginx.com < app->max_requests)) 3590277Sigor@sysoev.ru { 3591343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 3592343Smax.romanov@nginx.com 3593425Smax.romanov@nginx.com nxt_port_inc_use(port); 3594425Smax.romanov@nginx.com 3595343Smax.romanov@nginx.com } else { 3596343Smax.romanov@nginx.com lnk->next = NULL; 3597167Smax.romanov@nginx.com } 3598167Smax.romanov@nginx.com 3599343Smax.romanov@nginx.com return port; 3600163Smax.romanov@nginx.com } 3601163Smax.romanov@nginx.com 3602163Smax.romanov@nginx.com 3603507Smax.romanov@nginx.com nxt_inline nxt_port_t * 3604507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 3605141Smax.romanov@nginx.com { 3606343Smax.romanov@nginx.com nxt_port_t *port; 3607141Smax.romanov@nginx.com 3608141Smax.romanov@nginx.com port = NULL; 3609141Smax.romanov@nginx.com 3610141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3611141Smax.romanov@nginx.com 3612343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 3613343Smax.romanov@nginx.com 3614424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3615343Smax.romanov@nginx.com port = NULL; 3616343Smax.romanov@nginx.com 3617343Smax.romanov@nginx.com continue; 3618343Smax.romanov@nginx.com } 3619343Smax.romanov@nginx.com 3620507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 3621507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3622507Smax.romanov@nginx.com 3623507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3624507Smax.romanov@nginx.com app->idle_processes--; 3625507Smax.romanov@nginx.com } 3626507Smax.romanov@nginx.com 3627507Smax.romanov@nginx.com port->app = NULL; 3628507Smax.romanov@nginx.com app->processes--; 3629343Smax.romanov@nginx.com 3630343Smax.romanov@nginx.com break; 3631343Smax.romanov@nginx.com 3632343Smax.romanov@nginx.com } nxt_queue_loop; 3633141Smax.romanov@nginx.com 3634141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3635141Smax.romanov@nginx.com 3636141Smax.romanov@nginx.com return port; 3637141Smax.romanov@nginx.com } 3638141Smax.romanov@nginx.com 3639141Smax.romanov@nginx.com 3640141Smax.romanov@nginx.com static void 3641753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 3642507Smax.romanov@nginx.com { 3643753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 3644507Smax.romanov@nginx.com 3645507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3646507Smax.romanov@nginx.com 3647753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3648507Smax.romanov@nginx.com } 3649507Smax.romanov@nginx.com 3650507Smax.romanov@nginx.com 3651507Smax.romanov@nginx.com static void 3652343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3653141Smax.romanov@nginx.com { 3654343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3655343Smax.romanov@nginx.com 3656538Svbart@nginx.com ra = data; 3657538Svbart@nginx.com 3658538Svbart@nginx.com #if (NXT_DEBUG) 3659538Svbart@nginx.com { 3660538Svbart@nginx.com nxt_app_t *app; 3661538Svbart@nginx.com 3662343Smax.romanov@nginx.com app = obj; 3663141Smax.romanov@nginx.com 3664141Smax.romanov@nginx.com nxt_assert(app != NULL); 3665343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3666343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3667343Smax.romanov@nginx.com 3668343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3669343Smax.romanov@nginx.com &app->name, app, ra->stream); 3670538Svbart@nginx.com } 3671538Svbart@nginx.com #endif 3672343Smax.romanov@nginx.com 3673425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3674343Smax.romanov@nginx.com } 3675343Smax.romanov@nginx.com 3676343Smax.romanov@nginx.com 3677343Smax.romanov@nginx.com static void 3678343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3679343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3680343Smax.romanov@nginx.com { 3681427Smax.romanov@nginx.com nxt_app_t *app; 3682507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3683507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3684427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3685427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3686427Smax.romanov@nginx.com nxt_port_select_state_t state; 3687343Smax.romanov@nginx.com 3688343Smax.romanov@nginx.com nxt_assert(port != NULL); 3689343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3690343Smax.romanov@nginx.com 3691427Smax.romanov@nginx.com ra = NULL; 3692427Smax.romanov@nginx.com 3693343Smax.romanov@nginx.com app = port->app; 3694343Smax.romanov@nginx.com 3695343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3696343Smax.romanov@nginx.com 3697424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3698343Smax.romanov@nginx.com port->app_responses += got_response; 3699343Smax.romanov@nginx.com 3700427Smax.romanov@nginx.com if (port->pair[1] != -1 3701426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3702428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3703428Smax.romanov@nginx.com && (app->max_requests == 0 3704428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3705428Smax.romanov@nginx.com < app->max_requests)) 3706343Smax.romanov@nginx.com { 3707424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3708424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3709424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3710424Smax.romanov@nginx.com 3711424Smax.romanov@nginx.com } else { 3712424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3713424Smax.romanov@nginx.com } 3714424Smax.romanov@nginx.com 3715425Smax.romanov@nginx.com nxt_port_inc_use(port); 3716424Smax.romanov@nginx.com 3717424Smax.romanov@nginx.com } else { 3718424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3719424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3720424Smax.romanov@nginx.com { 3721424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3722424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3723424Smax.romanov@nginx.com } 3724424Smax.romanov@nginx.com } 3725141Smax.romanov@nginx.com } 3726141Smax.romanov@nginx.com 3727427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3728426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3729343Smax.romanov@nginx.com { 3730141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3731141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3732343Smax.romanov@nginx.com lnk->next = NULL; 3733141Smax.romanov@nginx.com 3734425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3735425Smax.romanov@nginx.com 3736427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3737425Smax.romanov@nginx.com 3738425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3739427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3740425Smax.romanov@nginx.com } 3741425Smax.romanov@nginx.com } 3742425Smax.romanov@nginx.com 3743427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3744425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3745425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3746425Smax.romanov@nginx.com { 3747425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3748425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3749425Smax.romanov@nginx.com lnk->next = NULL; 3750425Smax.romanov@nginx.com 3751427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3752427Smax.romanov@nginx.com link_port_pending); 3753427Smax.romanov@nginx.com 3754427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3755427Smax.romanov@nginx.com 3756427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3757427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3758425Smax.romanov@nginx.com 3759425Smax.romanov@nginx.com } else { 3760427Smax.romanov@nginx.com pending_ra = NULL; 3761141Smax.romanov@nginx.com } 3762141Smax.romanov@nginx.com 3763427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3764427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3765427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3766427Smax.romanov@nginx.com 3767427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3768427Smax.romanov@nginx.com 3769427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3770427Smax.romanov@nginx.com 3771427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3772427Smax.romanov@nginx.com &app->name, re_ra->stream); 3773427Smax.romanov@nginx.com 3774427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3775427Smax.romanov@nginx.com re_ra->stream); 3776427Smax.romanov@nginx.com 3777427Smax.romanov@nginx.com if (cancelled) { 3778427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3779427Smax.romanov@nginx.com 3780427Smax.romanov@nginx.com state.ra = re_ra; 3781427Smax.romanov@nginx.com state.app = app; 3782427Smax.romanov@nginx.com 3783427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3784427Smax.romanov@nginx.com 3785427Smax.romanov@nginx.com goto re_ra_cancelled; 3786427Smax.romanov@nginx.com } 3787427Smax.romanov@nginx.com } 3788427Smax.romanov@nginx.com } 3789427Smax.romanov@nginx.com 3790427Smax.romanov@nginx.com re_ra = NULL; 3791427Smax.romanov@nginx.com 3792427Smax.romanov@nginx.com re_ra_cancelled: 3793427Smax.romanov@nginx.com 3794753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 3795753Smax.romanov@nginx.com && port->app_pending_responses == 0 3796753Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3797367Smax.romanov@nginx.com 3798507Smax.romanov@nginx.com if (send_quit) { 3799507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3800507Smax.romanov@nginx.com 3801507Smax.romanov@nginx.com port->app = NULL; 3802507Smax.romanov@nginx.com app->processes--; 3803507Smax.romanov@nginx.com 3804507Smax.romanov@nginx.com } else { 3805507Smax.romanov@nginx.com port_unchained = 0; 3806507Smax.romanov@nginx.com } 3807507Smax.romanov@nginx.com 3808507Smax.romanov@nginx.com adjust_idle_timer = 0; 3809507Smax.romanov@nginx.com 3810571Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) { 3811507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3812507Smax.romanov@nginx.com 3813507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3814507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3815507Smax.romanov@nginx.com { 3816507Smax.romanov@nginx.com adjust_idle_timer = 1; 3817507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3818507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3819507Smax.romanov@nginx.com } 3820507Smax.romanov@nginx.com 3821507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3822507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3823507Smax.romanov@nginx.com 3824507Smax.romanov@nginx.com } else { 3825507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 3826507Smax.romanov@nginx.com 3827507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 3828507Smax.romanov@nginx.com } 3829507Smax.romanov@nginx.com 3830507Smax.romanov@nginx.com app->idle_processes++; 3831507Smax.romanov@nginx.com } 3832507Smax.romanov@nginx.com 3833343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3834343Smax.romanov@nginx.com 3835507Smax.romanov@nginx.com if (adjust_idle_timer) { 3836507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3837507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 3838507Smax.romanov@nginx.com } 3839507Smax.romanov@nginx.com 3840427Smax.romanov@nginx.com if (pending_ra != NULL) { 3841427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 3842427Smax.romanov@nginx.com } 3843427Smax.romanov@nginx.com 3844427Smax.romanov@nginx.com if (re_ra != NULL) { 3845427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 3846427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3847427Smax.romanov@nginx.com nxt_router_app_process_request, 3848427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 3849427Smax.romanov@nginx.com } 3850425Smax.romanov@nginx.com } 3851425Smax.romanov@nginx.com 3852343Smax.romanov@nginx.com if (ra != NULL) { 3853425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3854425Smax.romanov@nginx.com 3855343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3856343Smax.romanov@nginx.com nxt_router_app_process_request, 3857343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 3858343Smax.romanov@nginx.com 3859343Smax.romanov@nginx.com goto adjust_use; 3860343Smax.romanov@nginx.com } 3861343Smax.romanov@nginx.com 3862343Smax.romanov@nginx.com /* ? */ 3863163Smax.romanov@nginx.com if (port->pair[1] == -1) { 3864343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 3865343Smax.romanov@nginx.com &app->name, app, port, port->pid); 3866343Smax.romanov@nginx.com 3867343Smax.romanov@nginx.com goto adjust_use; 3868163Smax.romanov@nginx.com } 3869163Smax.romanov@nginx.com 3870367Smax.romanov@nginx.com if (send_quit) { 3871507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 3872167Smax.romanov@nginx.com &app->name, app); 3873163Smax.romanov@nginx.com 3874163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 3875163Smax.romanov@nginx.com -1, 0, 0, NULL); 3876163Smax.romanov@nginx.com 3877507Smax.romanov@nginx.com if (port_unchained) { 3878507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3879507Smax.romanov@nginx.com } 3880507Smax.romanov@nginx.com 3881343Smax.romanov@nginx.com goto adjust_use; 3882163Smax.romanov@nginx.com } 3883163Smax.romanov@nginx.com 3884167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 3885167Smax.romanov@nginx.com &app->name, app); 3886141Smax.romanov@nginx.com 3887343Smax.romanov@nginx.com adjust_use: 3888343Smax.romanov@nginx.com 3889425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 3890425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3891343Smax.romanov@nginx.com } 3892141Smax.romanov@nginx.com } 3893141Smax.romanov@nginx.com 3894141Smax.romanov@nginx.com 3895343Smax.romanov@nginx.com void 3896343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 3897141Smax.romanov@nginx.com { 3898507Smax.romanov@nginx.com nxt_app_t *app; 3899507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 3900507Smax.romanov@nginx.com nxt_port_t *idle_port; 3901507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 3902141Smax.romanov@nginx.com 3903141Smax.romanov@nginx.com app = port->app; 3904343Smax.romanov@nginx.com 3905343Smax.romanov@nginx.com nxt_assert(app != NULL); 3906141Smax.romanov@nginx.com 3907141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3908141Smax.romanov@nginx.com 3909507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 3910507Smax.romanov@nginx.com 3911507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3912507Smax.romanov@nginx.com app->idle_processes--; 3913507Smax.romanov@nginx.com 3914507Smax.romanov@nginx.com if (port->idle_start == 0 3915507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 3916507Smax.romanov@nginx.com { 3917507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3918507Smax.romanov@nginx.com 3919507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 3920507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 3921507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 3922507Smax.romanov@nginx.com 3923507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 3924507Smax.romanov@nginx.com 3925507Smax.romanov@nginx.com idle_port->idle_start = 0; 3926507Smax.romanov@nginx.com } 3927343Smax.romanov@nginx.com } 3928343Smax.romanov@nginx.com 3929507Smax.romanov@nginx.com app->processes--; 3930507Smax.romanov@nginx.com 3931753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 3932507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 3933507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 3934507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 3935507Smax.romanov@nginx.com 3936507Smax.romanov@nginx.com if (start_process) { 3937507Smax.romanov@nginx.com app->pending_processes++; 3938163Smax.romanov@nginx.com } 3939141Smax.romanov@nginx.com 3940141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3941163Smax.romanov@nginx.com 3942507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 3943343Smax.romanov@nginx.com 3944343Smax.romanov@nginx.com if (unchain) { 3945343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3946163Smax.romanov@nginx.com } 3947163Smax.romanov@nginx.com 3948507Smax.romanov@nginx.com if (start_process) { 3949507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3950507Smax.romanov@nginx.com } 3951507Smax.romanov@nginx.com } 3952507Smax.romanov@nginx.com 3953507Smax.romanov@nginx.com 3954507Smax.romanov@nginx.com static void 3955507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 3956507Smax.romanov@nginx.com { 3957507Smax.romanov@nginx.com nxt_app_t *app; 3958507Smax.romanov@nginx.com nxt_bool_t queued; 3959507Smax.romanov@nginx.com nxt_port_t *port; 3960507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 3961507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3962507Smax.romanov@nginx.com nxt_event_engine_t *engine; 3963507Smax.romanov@nginx.com 3964507Smax.romanov@nginx.com app = obj; 3965507Smax.romanov@nginx.com queued = (data == app); 3966507Smax.romanov@nginx.com 3967507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 3968507Smax.romanov@nginx.com &app->name, queued); 3969507Smax.romanov@nginx.com 3970507Smax.romanov@nginx.com engine = task->thread->engine; 3971507Smax.romanov@nginx.com 3972507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 3973507Smax.romanov@nginx.com 3974753Smax.romanov@nginx.com threshold = engine->timers.now + app->joint->idle_timer.precision; 3975507Smax.romanov@nginx.com timeout = 0; 3976507Smax.romanov@nginx.com 3977507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3978507Smax.romanov@nginx.com 3979507Smax.romanov@nginx.com if (queued) { 3980507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 3981343Smax.romanov@nginx.com } 3982507Smax.romanov@nginx.com 3983507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 3984507Smax.romanov@nginx.com 3985551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3986507Smax.romanov@nginx.com 3987507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 3988507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 3989507Smax.romanov@nginx.com 3990507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 3991507Smax.romanov@nginx.com 3992507Smax.romanov@nginx.com if (timeout > threshold) { 3993507Smax.romanov@nginx.com break; 3994507Smax.romanov@nginx.com } 3995507Smax.romanov@nginx.com 3996507Smax.romanov@nginx.com nxt_queue_remove(lnk); 3997507Smax.romanov@nginx.com lnk->next = NULL; 3998507Smax.romanov@nginx.com 3999507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4000507Smax.romanov@nginx.com 4001507Smax.romanov@nginx.com app->idle_processes--; 4002507Smax.romanov@nginx.com app->processes--; 4003507Smax.romanov@nginx.com port->app = NULL; 4004507Smax.romanov@nginx.com 4005507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4006507Smax.romanov@nginx.com 4007507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4008507Smax.romanov@nginx.com &app->name, port->pid); 4009507Smax.romanov@nginx.com 4010507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4011507Smax.romanov@nginx.com 4012507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4013507Smax.romanov@nginx.com 4014507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4015507Smax.romanov@nginx.com } 4016507Smax.romanov@nginx.com 4017507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4018507Smax.romanov@nginx.com 4019507Smax.romanov@nginx.com if (timeout > threshold) { 4020753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4021507Smax.romanov@nginx.com 4022507Smax.romanov@nginx.com } else { 4023753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4024507Smax.romanov@nginx.com } 4025507Smax.romanov@nginx.com 4026507Smax.romanov@nginx.com if (queued) { 4027507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4028507Smax.romanov@nginx.com } 4029507Smax.romanov@nginx.com } 4030507Smax.romanov@nginx.com 4031507Smax.romanov@nginx.com 4032507Smax.romanov@nginx.com static void 4033507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4034507Smax.romanov@nginx.com { 4035753Smax.romanov@nginx.com nxt_timer_t *timer; 4036753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4037507Smax.romanov@nginx.com 4038507Smax.romanov@nginx.com timer = obj; 4039753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4040753Smax.romanov@nginx.com 4041753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4042753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4043753Smax.romanov@nginx.com } 4044753Smax.romanov@nginx.com } 4045753Smax.romanov@nginx.com 4046753Smax.romanov@nginx.com 4047753Smax.romanov@nginx.com static void 4048753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4049753Smax.romanov@nginx.com { 4050753Smax.romanov@nginx.com nxt_timer_t *timer; 4051753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4052753Smax.romanov@nginx.com 4053753Smax.romanov@nginx.com timer = obj; 4054753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4055753Smax.romanov@nginx.com 4056753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4057507Smax.romanov@nginx.com } 4058507Smax.romanov@nginx.com 4059507Smax.romanov@nginx.com 4060507Smax.romanov@nginx.com static void 4061753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4062507Smax.romanov@nginx.com { 4063753Smax.romanov@nginx.com nxt_app_t *app; 4064753Smax.romanov@nginx.com nxt_port_t *port; 4065753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4066753Smax.romanov@nginx.com 4067753Smax.romanov@nginx.com app_joint = obj; 4068753Smax.romanov@nginx.com app = app_joint->app; 4069753Smax.romanov@nginx.com 4070753Smax.romanov@nginx.com for ( ;; ) { 4071753Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 4072753Smax.romanov@nginx.com if (port == NULL) { 4073753Smax.romanov@nginx.com break; 4074753Smax.romanov@nginx.com } 4075753Smax.romanov@nginx.com 4076753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4077753Smax.romanov@nginx.com 4078753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4079753Smax.romanov@nginx.com 4080753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4081753Smax.romanov@nginx.com } 4082753Smax.romanov@nginx.com 4083753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 4084753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4085753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 4086753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4087753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4088753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4089753Smax.romanov@nginx.com 4090753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 4091753Smax.romanov@nginx.com nxt_free(app); 4092753Smax.romanov@nginx.com 4093753Smax.romanov@nginx.com app_joint->app = NULL; 4094753Smax.romanov@nginx.com 4095753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4096753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4097753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4098753Smax.romanov@nginx.com 4099753Smax.romanov@nginx.com } else { 4100753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4101753Smax.romanov@nginx.com } 4102141Smax.romanov@nginx.com } 4103141Smax.romanov@nginx.com 4104141Smax.romanov@nginx.com 4105427Smax.romanov@nginx.com static void 4106427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 4107141Smax.romanov@nginx.com { 4108427Smax.romanov@nginx.com nxt_app_t *app; 4109507Smax.romanov@nginx.com nxt_bool_t can_start_process; 4110427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4111427Smax.romanov@nginx.com 4112427Smax.romanov@nginx.com ra = state->ra; 4113427Smax.romanov@nginx.com app = state->app; 4114427Smax.romanov@nginx.com 4115427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 4116343Smax.romanov@nginx.com 4117425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 4118425Smax.romanov@nginx.com { 4119425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4120425Smax.romanov@nginx.com } 4121425Smax.romanov@nginx.com 4122425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 4123425Smax.romanov@nginx.com { 4124427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 4125427Smax.romanov@nginx.com 4126427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 4127427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 4128427Smax.romanov@nginx.com 4129425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4130425Smax.romanov@nginx.com } 4131425Smax.romanov@nginx.com 4132427Smax.romanov@nginx.com state->failed_port = ra->app_port; 4133427Smax.romanov@nginx.com 4134425Smax.romanov@nginx.com if (ra->app_port != NULL) { 4135427Smax.romanov@nginx.com state->failed_port_use_delta--; 4136427Smax.romanov@nginx.com 4137427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 4138427Smax.romanov@nginx.com 4139427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 4140427Smax.romanov@nginx.com state->failed_port_use_delta--; 4141427Smax.romanov@nginx.com } 4142427Smax.romanov@nginx.com 4143427Smax.romanov@nginx.com ra->app_port = NULL; 4144427Smax.romanov@nginx.com } 4145427Smax.romanov@nginx.com 4146507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 4147507Smax.romanov@nginx.com 4148427Smax.romanov@nginx.com state->port = NULL; 4149507Smax.romanov@nginx.com state->start_process = 0; 4150427Smax.romanov@nginx.com 4151427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 4152507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 4153427Smax.romanov@nginx.com { 4154427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4155427Smax.romanov@nginx.com 4156427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4157427Smax.romanov@nginx.com goto fail; 4158427Smax.romanov@nginx.com } 4159427Smax.romanov@nginx.com 4160427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 4161427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 4162427Smax.romanov@nginx.com 4163427Smax.romanov@nginx.com } else { 4164427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 4165427Smax.romanov@nginx.com } 4166427Smax.romanov@nginx.com 4167427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 4168427Smax.romanov@nginx.com 4169427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 4170427Smax.romanov@nginx.com 4171507Smax.romanov@nginx.com if (can_start_process) { 4172507Smax.romanov@nginx.com app->pending_processes++; 4173507Smax.romanov@nginx.com state->start_process = 1; 4174425Smax.romanov@nginx.com } 4175425Smax.romanov@nginx.com 4176425Smax.romanov@nginx.com } else { 4177427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 4178427Smax.romanov@nginx.com 4179427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 4180427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4181427Smax.romanov@nginx.com 4182427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4183427Smax.romanov@nginx.com goto fail; 4184351Smax.romanov@nginx.com } 4185427Smax.romanov@nginx.com 4186427Smax.romanov@nginx.com ra->app_port = state->port; 4187427Smax.romanov@nginx.com 4188427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 4189425Smax.romanov@nginx.com } 4190507Smax.romanov@nginx.com 4191507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 4192507Smax.romanov@nginx.com app->pending_processes++; 4193507Smax.romanov@nginx.com state->start_process = 1; 4194507Smax.romanov@nginx.com } 4195343Smax.romanov@nginx.com } 4196343Smax.romanov@nginx.com 4197427Smax.romanov@nginx.com fail: 4198427Smax.romanov@nginx.com 4199427Smax.romanov@nginx.com state->shared_ra = ra; 4200427Smax.romanov@nginx.com } 4201427Smax.romanov@nginx.com 4202427Smax.romanov@nginx.com 4203427Smax.romanov@nginx.com static nxt_int_t 4204427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 4205427Smax.romanov@nginx.com { 4206427Smax.romanov@nginx.com nxt_int_t res; 4207427Smax.romanov@nginx.com nxt_app_t *app; 4208427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4209427Smax.romanov@nginx.com 4210427Smax.romanov@nginx.com ra = state->shared_ra; 4211427Smax.romanov@nginx.com app = state->app; 4212427Smax.romanov@nginx.com 4213427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 4214427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 4215425Smax.romanov@nginx.com } 4216425Smax.romanov@nginx.com 4217351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4218427Smax.romanov@nginx.com if (state->port != NULL) { 4219427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 4220425Smax.romanov@nginx.com } 4221425Smax.romanov@nginx.com 4222427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 4223427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 4224427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 4225427Smax.romanov@nginx.com 4226351Smax.romanov@nginx.com return NXT_ERROR; 4227351Smax.romanov@nginx.com } 4228351Smax.romanov@nginx.com 4229427Smax.romanov@nginx.com if (state->port != NULL) { 4230343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 4231163Smax.romanov@nginx.com 4232427Smax.romanov@nginx.com ra->app_port = state->port; 4233343Smax.romanov@nginx.com 4234507Smax.romanov@nginx.com if (state->start_process) { 4235507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4236507Smax.romanov@nginx.com } 4237507Smax.romanov@nginx.com 4238141Smax.romanov@nginx.com return NXT_OK; 4239141Smax.romanov@nginx.com } 4240141Smax.romanov@nginx.com 4241507Smax.romanov@nginx.com if (!state->start_process) { 4242507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 4243343Smax.romanov@nginx.com &app->name, app); 4244343Smax.romanov@nginx.com 4245343Smax.romanov@nginx.com return NXT_AGAIN; 4246343Smax.romanov@nginx.com } 4247343Smax.romanov@nginx.com 4248507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 4249343Smax.romanov@nginx.com 4250343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4251507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 4252427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 4253343Smax.romanov@nginx.com 4254141Smax.romanov@nginx.com return NXT_ERROR; 4255141Smax.romanov@nginx.com } 4256141Smax.romanov@nginx.com 4257141Smax.romanov@nginx.com return NXT_AGAIN; 425888Smax.romanov@nginx.com } 425988Smax.romanov@nginx.com 426088Smax.romanov@nginx.com 4261427Smax.romanov@nginx.com static nxt_int_t 4262427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 4263427Smax.romanov@nginx.com { 4264427Smax.romanov@nginx.com nxt_port_select_state_t state; 4265427Smax.romanov@nginx.com 4266427Smax.romanov@nginx.com state.ra = ra; 4267427Smax.romanov@nginx.com state.app = app; 4268427Smax.romanov@nginx.com 4269427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4270427Smax.romanov@nginx.com 4271427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4272427Smax.romanov@nginx.com 4273427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4274427Smax.romanov@nginx.com 4275427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 4276427Smax.romanov@nginx.com } 4277427Smax.romanov@nginx.com 4278427Smax.romanov@nginx.com 4279431Sigor@sysoev.ru void 4280431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar) 428153Sigor@sysoev.ru { 4282431Sigor@sysoev.ru nxt_int_t res; 4283431Sigor@sysoev.ru nxt_app_t *app; 4284431Sigor@sysoev.ru nxt_port_t *port; 4285431Sigor@sysoev.ru nxt_event_engine_t *engine; 4286431Sigor@sysoev.ru nxt_http_request_t *r; 4287431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 4288431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 4289431Sigor@sysoev.ru 4290431Sigor@sysoev.ru r = ar->request; 4291683Sigor@sysoev.ru app = r->conf->socket_conf->application; 4292425Smax.romanov@nginx.com 4293425Smax.romanov@nginx.com if (app == NULL) { 4294431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4295425Smax.romanov@nginx.com return; 4296425Smax.romanov@nginx.com } 429788Smax.romanov@nginx.com 429888Smax.romanov@nginx.com engine = task->thread->engine; 429988Smax.romanov@nginx.com 4300318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 4301318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4302318Smax.romanov@nginx.com nxt_router_response_error_handler, 4303318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 4304122Smax.romanov@nginx.com 430588Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 4306431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4307141Smax.romanov@nginx.com return; 430888Smax.romanov@nginx.com } 430988Smax.romanov@nginx.com 4310318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 4311425Smax.romanov@nginx.com rc->app = app; 4312425Smax.romanov@nginx.com 4313425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4314425Smax.romanov@nginx.com 4315431Sigor@sysoev.ru rc->ap = ar; 4316346Smax.romanov@nginx.com 4317351Smax.romanov@nginx.com ra = &ra_local; 4318351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 4319167Smax.romanov@nginx.com 4320427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 4321141Smax.romanov@nginx.com 4322141Smax.romanov@nginx.com if (res != NXT_OK) { 4323141Smax.romanov@nginx.com return; 4324141Smax.romanov@nginx.com } 4325141Smax.romanov@nginx.com 4326425Smax.romanov@nginx.com ra = rc->ra; 4327167Smax.romanov@nginx.com port = ra->app_port; 4328141Smax.romanov@nginx.com 4329425Smax.romanov@nginx.com nxt_assert(port != NULL); 4330141Smax.romanov@nginx.com 4331318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 4332318Smax.romanov@nginx.com 4333425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 4334167Smax.romanov@nginx.com } 4335167Smax.romanov@nginx.com 4336167Smax.romanov@nginx.com 4337167Smax.romanov@nginx.com static void 4338423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4339423Smax.romanov@nginx.com { 4340423Smax.romanov@nginx.com } 4341423Smax.romanov@nginx.com 4342423Smax.romanov@nginx.com 4343423Smax.romanov@nginx.com static void 4344425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 4345167Smax.romanov@nginx.com { 4346343Smax.romanov@nginx.com uint32_t request_failed; 4347743Smax.romanov@nginx.com nxt_buf_t *buf; 4348167Smax.romanov@nginx.com nxt_int_t res; 4349343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 4350167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 4351167Smax.romanov@nginx.com 4352343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 4353343Smax.romanov@nginx.com 4354343Smax.romanov@nginx.com port = ra->app_port; 4355167Smax.romanov@nginx.com reply_port = ra->reply_port; 4356167Smax.romanov@nginx.com ap = ra->ap; 4357141Smax.romanov@nginx.com 4358343Smax.romanov@nginx.com request_failed = 1; 4359343Smax.romanov@nginx.com 4360141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 4361141Smax.romanov@nginx.com reply_port->id); 4362141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 4363141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 4364122Smax.romanov@nginx.com 4365122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4366423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4367345Smax.romanov@nginx.com "Failed to send reply port to application"); 4368343Smax.romanov@nginx.com goto release_port; 4369122Smax.romanov@nginx.com } 4370122Smax.romanov@nginx.com 4371141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 437288Smax.romanov@nginx.com } 437388Smax.romanov@nginx.com 4374743Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, &ap->r, port, 4375743Smax.romanov@nginx.com nxt_app_msg_prefix[port->app->type]); 4376743Smax.romanov@nginx.com 4377743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4378423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4379345Smax.romanov@nginx.com "Failed to prepare message for application"); 4380343Smax.romanov@nginx.com goto release_port; 4381122Smax.romanov@nginx.com } 438288Smax.romanov@nginx.com 4383507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4384743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4385743Smax.romanov@nginx.com port->socket.fd); 438688Smax.romanov@nginx.com 4387343Smax.romanov@nginx.com request_failed = 0; 4388343Smax.romanov@nginx.com 4389743Smax.romanov@nginx.com ra->msg_info.buf = buf; 4390743Smax.romanov@nginx.com ra->msg_info.completion_handler = buf->completion_handler; 4391743Smax.romanov@nginx.com 4392743Smax.romanov@nginx.com for (; buf; buf = buf->next) { 4393743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 4394423Smax.romanov@nginx.com } 4395423Smax.romanov@nginx.com 4396743Smax.romanov@nginx.com buf = ra->msg_info.buf; 4397743Smax.romanov@nginx.com 4398423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 4399423Smax.romanov@nginx.com ra->stream); 4400423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4401423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4402423Smax.romanov@nginx.com "Failed to get tracking area"); 4403423Smax.romanov@nginx.com goto release_port; 4404423Smax.romanov@nginx.com } 4405423Smax.romanov@nginx.com 4406743Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA, 4407743Smax.romanov@nginx.com -1, ra->stream, reply_port->id, buf, 4408423Smax.romanov@nginx.com &ra->msg_info.tracking); 4409122Smax.romanov@nginx.com 4410122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4411423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4412345Smax.romanov@nginx.com "Failed to send message to application"); 4413343Smax.romanov@nginx.com goto release_port; 4414122Smax.romanov@nginx.com } 4415343Smax.romanov@nginx.com 4416343Smax.romanov@nginx.com release_port: 4417343Smax.romanov@nginx.com 4418345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 4419345Smax.romanov@nginx.com 4420425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 442153Sigor@sysoev.ru } 442253Sigor@sysoev.ru 442353Sigor@sysoev.ru 4424743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4425743Smax.romanov@nginx.com nxt_list_part_t *part; 4426743Smax.romanov@nginx.com nxt_http_field_t *field; 4427743Smax.romanov@nginx.com }; 4428743Smax.romanov@nginx.com 4429743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4430743Smax.romanov@nginx.com 4431743Smax.romanov@nginx.com 4432743Smax.romanov@nginx.com static nxt_http_field_t * 4433743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4434216Sigor@sysoev.ru { 4435743Smax.romanov@nginx.com if (part == NULL) { 4436743Smax.romanov@nginx.com return NULL; 4437216Sigor@sysoev.ru } 4438216Sigor@sysoev.ru 4439743Smax.romanov@nginx.com while (part->nelts == 0) { 4440743Smax.romanov@nginx.com part = part->next; 4441743Smax.romanov@nginx.com if (part == NULL) { 4442743Smax.romanov@nginx.com return NULL; 4443743Smax.romanov@nginx.com } 4444216Sigor@sysoev.ru } 4445216Sigor@sysoev.ru 4446743Smax.romanov@nginx.com i->part = part; 4447743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4448743Smax.romanov@nginx.com 4449743Smax.romanov@nginx.com return i->field; 4450743Smax.romanov@nginx.com } 4451743Smax.romanov@nginx.com 4452743Smax.romanov@nginx.com 4453743Smax.romanov@nginx.com static nxt_http_field_t * 4454743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4455743Smax.romanov@nginx.com { 4456743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4457743Smax.romanov@nginx.com } 4458743Smax.romanov@nginx.com 4459743Smax.romanov@nginx.com 4460743Smax.romanov@nginx.com static nxt_http_field_t * 4461743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4462743Smax.romanov@nginx.com { 4463743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4464743Smax.romanov@nginx.com 4465743Smax.romanov@nginx.com end += i->part->nelts; 4466743Smax.romanov@nginx.com i->field++; 4467743Smax.romanov@nginx.com 4468743Smax.romanov@nginx.com if (i->field < end) { 4469743Smax.romanov@nginx.com return i->field; 4470216Sigor@sysoev.ru } 4471216Sigor@sysoev.ru 4472743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4473216Sigor@sysoev.ru } 4474216Sigor@sysoev.ru 4475216Sigor@sysoev.ru 4476743Smax.romanov@nginx.com static nxt_buf_t * 4477743Smax.romanov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4478743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix) 4479216Sigor@sysoev.ru { 4480743Smax.romanov@nginx.com void *target_pos, *query_pos; 4481743Smax.romanov@nginx.com u_char *pos, *end, *p, c; 4482743Smax.romanov@nginx.com size_t fields_count, req_size, size, free_size; 4483743Smax.romanov@nginx.com size_t copy_size; 4484743Smax.romanov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 4485743Smax.romanov@nginx.com nxt_http_field_t *field, *dup; 4486743Smax.romanov@nginx.com nxt_unit_field_t *dst_field; 4487743Smax.romanov@nginx.com nxt_fields_iter_t iter, dup_iter; 4488743Smax.romanov@nginx.com nxt_unit_request_t *req; 4489216Sigor@sysoev.ru nxt_app_request_header_t *h; 4490216Sigor@sysoev.ru 4491216Sigor@sysoev.ru h = &r->header; 4492216Sigor@sysoev.ru 4493743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 4494743Smax.romanov@nginx.com + h->method.length + 1 4495743Smax.romanov@nginx.com + h->version.length + 1 4496743Smax.romanov@nginx.com + r->remote.length + 1 4497743Smax.romanov@nginx.com + r->local.length + 1 4498743Smax.romanov@nginx.com + h->target.length + 1 4499743Smax.romanov@nginx.com + (h->path.start != h->target.start ? h->path.length + 1 : 0); 4500743Smax.romanov@nginx.com 4501743Smax.romanov@nginx.com fields_count = 0; 4502743Smax.romanov@nginx.com 4503743Smax.romanov@nginx.com nxt_list_each(field, h->fields) { 4504743Smax.romanov@nginx.com fields_count++; 4505743Smax.romanov@nginx.com 4506743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4507743Smax.romanov@nginx.com + field->value_length + 1; 4508743Smax.romanov@nginx.com } nxt_list_loop; 4509743Smax.romanov@nginx.com 4510743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4511743Smax.romanov@nginx.com 4512743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4513743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4514743Smax.romanov@nginx.com (int) req_size); 4515743Smax.romanov@nginx.com 4516743Smax.romanov@nginx.com return NULL; 4517743Smax.romanov@nginx.com } 4518743Smax.romanov@nginx.com 4519743Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, port, 4520743Smax.romanov@nginx.com nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE)); 4521743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4522743Smax.romanov@nginx.com return NULL; 4523743Smax.romanov@nginx.com } 4524743Smax.romanov@nginx.com 4525743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4526743Smax.romanov@nginx.com out->mem.free += req_size; 4527743Smax.romanov@nginx.com 4528743Smax.romanov@nginx.com req->content_length = h->parsed_content_length; 4529743Smax.romanov@nginx.com 4530743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4531743Smax.romanov@nginx.com 4532743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4533743Smax.romanov@nginx.com 4534743Smax.romanov@nginx.com req->method_length = h->method.length; 4535743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 4536743Smax.romanov@nginx.com p = nxt_cpymem(p, h->method.start, h->method.length); 4537743Smax.romanov@nginx.com *p++ = '\0'; 4538743Smax.romanov@nginx.com 4539743Smax.romanov@nginx.com req->version_length = h->version.length; 4540743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 4541743Smax.romanov@nginx.com p = nxt_cpymem(p, h->version.start, h->version.length); 4542743Smax.romanov@nginx.com *p++ = '\0'; 4543743Smax.romanov@nginx.com 4544743Smax.romanov@nginx.com req->remote_length = r->remote.length; 4545743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 4546743Smax.romanov@nginx.com p = nxt_cpymem(p, r->remote.start, r->remote.length); 4547743Smax.romanov@nginx.com *p++ = '\0'; 4548743Smax.romanov@nginx.com 4549743Smax.romanov@nginx.com req->local_length = r->local.length; 4550743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 4551743Smax.romanov@nginx.com p = nxt_cpymem(p, r->local.start, r->local.length); 4552743Smax.romanov@nginx.com *p++ = '\0'; 4553743Smax.romanov@nginx.com 4554743Smax.romanov@nginx.com target_pos = p; 4555743Smax.romanov@nginx.com req->target_length = h->target.length; 4556743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 4557743Smax.romanov@nginx.com p = nxt_cpymem(p, h->target.start, h->target.length); 4558743Smax.romanov@nginx.com *p++ = '\0'; 4559743Smax.romanov@nginx.com 4560743Smax.romanov@nginx.com req->path_length = h->path.length; 4561216Sigor@sysoev.ru if (h->path.start == h->target.start) { 4562743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 4563277Sigor@sysoev.ru 4564216Sigor@sysoev.ru } else { 4565743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 4566743Smax.romanov@nginx.com p = nxt_cpymem(p, h->path.start, h->path.length); 4567743Smax.romanov@nginx.com *p++ = '\0'; 4568305Smax.romanov@nginx.com } 4569216Sigor@sysoev.ru 4570743Smax.romanov@nginx.com req->query_length = h->query.length; 4571743Smax.romanov@nginx.com if (h->query.start != NULL) { 4572743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 4573743Smax.romanov@nginx.com h->query.start - h->target.start); 4574743Smax.romanov@nginx.com 4575743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 4576277Sigor@sysoev.ru 4577216Sigor@sysoev.ru } else { 4578743Smax.romanov@nginx.com req->query.offset = 0; 4579216Sigor@sysoev.ru } 4580216Sigor@sysoev.ru 4581743Smax.romanov@nginx.com req->host_field = NXT_UNIT_NONE_FIELD; 4582743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 4583743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 4584743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 4585743Smax.romanov@nginx.com 4586743Smax.romanov@nginx.com dst_field = req->fields; 4587743Smax.romanov@nginx.com 4588743Smax.romanov@nginx.com for (field = nxt_fields_first(h->fields, &iter); 4589743Smax.romanov@nginx.com field != NULL; 4590743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 4591743Smax.romanov@nginx.com { 4592743Smax.romanov@nginx.com if (field->skip) { 4593743Smax.romanov@nginx.com continue; 4594743Smax.romanov@nginx.com } 4595743Smax.romanov@nginx.com 4596743Smax.romanov@nginx.com dst_field->hash = field->hash; 4597743Smax.romanov@nginx.com dst_field->skip = 0; 4598743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 4599743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 4600743Smax.romanov@nginx.com 4601743Smax.romanov@nginx.com if (field->value == h->host.start) { 4602743Smax.romanov@nginx.com req->host_field = dst_field - req->fields; 4603743Smax.romanov@nginx.com 4604743Smax.romanov@nginx.com } else if (field->value == h->content_length.start) { 4605743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 4606743Smax.romanov@nginx.com 4607743Smax.romanov@nginx.com } else if (field->value == h->content_type.start) { 4608743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 4609743Smax.romanov@nginx.com 4610743Smax.romanov@nginx.com } else if (field->value == h->cookie.start) { 4611743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 4612743Smax.romanov@nginx.com } 4613743Smax.romanov@nginx.com 4614743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 4615743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 4616743Smax.romanov@nginx.com (int) field->name_length, field->name, 4617743Smax.romanov@nginx.com (int) field->value_length, field->value); 4618743Smax.romanov@nginx.com 4619743Smax.romanov@nginx.com if (prefix->length != 0) { 4620743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4621743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 4622743Smax.romanov@nginx.com 4623743Smax.romanov@nginx.com end = field->name + field->name_length; 4624743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 4625743Smax.romanov@nginx.com c = *pos; 4626743Smax.romanov@nginx.com 4627743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 4628743Smax.romanov@nginx.com *p++ = (c & ~0x20); 4629743Smax.romanov@nginx.com continue; 4630743Smax.romanov@nginx.com } 4631743Smax.romanov@nginx.com 4632743Smax.romanov@nginx.com if (c == '-') { 4633743Smax.romanov@nginx.com *p++ = '_'; 4634743Smax.romanov@nginx.com continue; 4635743Smax.romanov@nginx.com } 4636743Smax.romanov@nginx.com 4637743Smax.romanov@nginx.com *p++ = c; 4638743Smax.romanov@nginx.com } 4639743Smax.romanov@nginx.com 4640743Smax.romanov@nginx.com } else { 4641743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4642743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 4643743Smax.romanov@nginx.com } 4644743Smax.romanov@nginx.com 4645743Smax.romanov@nginx.com *p++ = '\0'; 4646743Smax.romanov@nginx.com 4647743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 4648743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 4649743Smax.romanov@nginx.com 4650743Smax.romanov@nginx.com if (prefix->length != 0) { 4651743Smax.romanov@nginx.com dup_iter = iter; 4652743Smax.romanov@nginx.com 4653743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 4654743Smax.romanov@nginx.com dup != NULL; 4655743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 4656743Smax.romanov@nginx.com { 4657743Smax.romanov@nginx.com if (dup->name_length != field->name_length 4658743Smax.romanov@nginx.com || dup->skip 4659743Smax.romanov@nginx.com || dup->hash != field->hash 4660743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 4661743Smax.romanov@nginx.com { 4662743Smax.romanov@nginx.com continue; 4663743Smax.romanov@nginx.com } 4664743Smax.romanov@nginx.com 4665743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 4666743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 4667743Smax.romanov@nginx.com 4668743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 4669743Smax.romanov@nginx.com 4670743Smax.romanov@nginx.com dup->skip = 1; 4671743Smax.romanov@nginx.com } 4672743Smax.romanov@nginx.com } 4673743Smax.romanov@nginx.com 4674743Smax.romanov@nginx.com *p++ = '\0'; 4675743Smax.romanov@nginx.com 4676743Smax.romanov@nginx.com dst_field++; 4677743Smax.romanov@nginx.com } 4678743Smax.romanov@nginx.com 4679743Smax.romanov@nginx.com req->fields_count = dst_field - req->fields; 4680743Smax.romanov@nginx.com 4681743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 4682743Smax.romanov@nginx.com 4683743Smax.romanov@nginx.com buf = out; 4684743Smax.romanov@nginx.com tail = &buf->next; 4685216Sigor@sysoev.ru 4686510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4687743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 4688743Smax.romanov@nginx.com pos = b->mem.pos; 4689743Smax.romanov@nginx.com 4690743Smax.romanov@nginx.com while (size > 0) { 4691743Smax.romanov@nginx.com if (buf == NULL) { 4692743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 4693743Smax.romanov@nginx.com 4694743Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, port, free_size); 4695743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4696743Smax.romanov@nginx.com while (out != NULL) { 4697743Smax.romanov@nginx.com buf = out->next; 4698743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 4699743Smax.romanov@nginx.com out = buf; 4700743Smax.romanov@nginx.com } 4701743Smax.romanov@nginx.com return NULL; 4702743Smax.romanov@nginx.com } 4703743Smax.romanov@nginx.com 4704743Smax.romanov@nginx.com *tail = buf; 4705743Smax.romanov@nginx.com tail = &buf->next; 4706743Smax.romanov@nginx.com 4707743Smax.romanov@nginx.com } else { 4708743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4709743Smax.romanov@nginx.com if (free_size < size 4710743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 4711743Smax.romanov@nginx.com == NXT_OK) 4712743Smax.romanov@nginx.com { 4713743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4714743Smax.romanov@nginx.com } 4715743Smax.romanov@nginx.com } 4716743Smax.romanov@nginx.com 4717743Smax.romanov@nginx.com if (free_size > 0) { 4718743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 4719743Smax.romanov@nginx.com 4720743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 4721743Smax.romanov@nginx.com 4722743Smax.romanov@nginx.com size -= copy_size; 4723743Smax.romanov@nginx.com pos += copy_size; 4724743Smax.romanov@nginx.com 4725743Smax.romanov@nginx.com if (size == 0) { 4726743Smax.romanov@nginx.com break; 4727743Smax.romanov@nginx.com } 4728743Smax.romanov@nginx.com } 4729743Smax.romanov@nginx.com 4730743Smax.romanov@nginx.com buf = NULL; 4731743Smax.romanov@nginx.com } 4732216Sigor@sysoev.ru } 4733216Sigor@sysoev.ru 4734743Smax.romanov@nginx.com return out; 4735584Salexander.borisov@nginx.com } 4736584Salexander.borisov@nginx.com 4737584Salexander.borisov@nginx.com 473853Sigor@sysoev.ru static void 4739318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4740318Smax.romanov@nginx.com { 4741615Smax.romanov@nginx.com nxt_app_t *app; 4742615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 4743615Smax.romanov@nginx.com nxt_port_t *port; 4744615Smax.romanov@nginx.com nxt_timer_t *timer; 4745615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4746615Smax.romanov@nginx.com nxt_req_app_link_t *pending_ra; 4747615Smax.romanov@nginx.com nxt_app_parse_ctx_t *ar; 4748615Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 4749615Smax.romanov@nginx.com nxt_port_select_state_t state; 4750318Smax.romanov@nginx.com 4751318Smax.romanov@nginx.com timer = obj; 4752318Smax.romanov@nginx.com 4753318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4754318Smax.romanov@nginx.com 4755431Sigor@sysoev.ru ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); 4756615Smax.romanov@nginx.com rc = ar->timer_data; 4757615Smax.romanov@nginx.com app = rc->app; 4758615Smax.romanov@nginx.com 4759615Smax.romanov@nginx.com if (app == NULL) { 4760615Smax.romanov@nginx.com goto generate_error; 4761615Smax.romanov@nginx.com } 4762615Smax.romanov@nginx.com 4763615Smax.romanov@nginx.com port = NULL; 4764615Smax.romanov@nginx.com pending_ra = NULL; 4765615Smax.romanov@nginx.com 4766615Smax.romanov@nginx.com if (rc->app_port != NULL) { 4767615Smax.romanov@nginx.com port = rc->app_port; 4768615Smax.romanov@nginx.com rc->app_port = NULL; 4769615Smax.romanov@nginx.com } 4770615Smax.romanov@nginx.com 4771615Smax.romanov@nginx.com if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) { 4772615Smax.romanov@nginx.com port = rc->ra->app_port; 4773615Smax.romanov@nginx.com rc->ra->app_port = NULL; 4774615Smax.romanov@nginx.com } 4775615Smax.romanov@nginx.com 4776615Smax.romanov@nginx.com if (port == NULL) { 4777615Smax.romanov@nginx.com goto generate_error; 4778431Sigor@sysoev.ru } 4779615Smax.romanov@nginx.com 4780615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4781615Smax.romanov@nginx.com 4782615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 4783615Smax.romanov@nginx.com 4784615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 4785615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4786615Smax.romanov@nginx.com 4787615Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 4788615Smax.romanov@nginx.com link_port_pending); 4789615Smax.romanov@nginx.com 4790615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4791615Smax.romanov@nginx.com 4792615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 4793615Smax.romanov@nginx.com &app->name, pending_ra->stream); 4794615Smax.romanov@nginx.com 4795615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 4796615Smax.romanov@nginx.com pending_ra->stream); 4797615Smax.romanov@nginx.com 4798615Smax.romanov@nginx.com if (cancelled) { 4799615Smax.romanov@nginx.com nxt_router_ra_inc_use(pending_ra); 4800615Smax.romanov@nginx.com 4801615Smax.romanov@nginx.com state.ra = pending_ra; 4802615Smax.romanov@nginx.com state.app = app; 4803615Smax.romanov@nginx.com 4804615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4805615Smax.romanov@nginx.com 4806615Smax.romanov@nginx.com } else { 4807615Smax.romanov@nginx.com pending_ra = NULL; 4808615Smax.romanov@nginx.com } 4809615Smax.romanov@nginx.com } 4810615Smax.romanov@nginx.com 4811615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4812615Smax.romanov@nginx.com 4813615Smax.romanov@nginx.com if (pending_ra != NULL 4814615Smax.romanov@nginx.com && nxt_router_port_post_select(task, &state) == NXT_OK) 4815615Smax.romanov@nginx.com { 4816615Smax.romanov@nginx.com nxt_router_app_prepare_request(task, pending_ra); 4817615Smax.romanov@nginx.com } 4818615Smax.romanov@nginx.com 4819615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 4820615Smax.romanov@nginx.com 4821615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4822615Smax.romanov@nginx.com 4823615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 4824615Smax.romanov@nginx.com 4825615Smax.romanov@nginx.com generate_error: 4826615Smax.romanov@nginx.com 4827615Smax.romanov@nginx.com nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); 4828615Smax.romanov@nginx.com 4829615Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 4830318Smax.romanov@nginx.com } 4831